Проблемы с NSScrollView

У меня есть несколько проблем с NSScrollView, который я пытаюсь использовать, и мне нужна помощь. Я прочитал NSView, NSScrollView и несколько других руководств и справочников, а также вопросы здесь и cocoadev, но до сих пор не могу их понять.

(Код для моего подкласса представления можно найти ниже.)

Моя главная цель - создать интерфейс, подобный интерфейсу KGChart, разработчика диаграмм с иглами, предназначенного исключительно для ПК. (веб-сайт KGChart)

  1. Как я могу сохранить то, что я рисую, в режиме прокрутки? Мой метод -drawStitch выполняется во время событий мыши, где он рисует прямоугольник с символом на нем (в настоящее время только черный с «+») в представление документа в scrollview. Когда я прокручиваю его из виду и обратно, он исчезает, и мне нужно как-то его сохранить. Моя идея состоит в том, чтобы попробовать 2D-массив для отслеживания стежков, но я думаю, что производительность будет ухудшаться с большими холстами (я бы хотел сделать 2,000x2,000, но я бы остановился на 500x500).

  2. Если вы посмотрите на изображение работы моей программы, вы увидите разницу в цвете сетки. Код для рисования сетки находится в -drawRect, а цвет установлен как grayColor. Когда программа запускается, видимая сетка имеет более светлый цвет, но темнее на тех частях холста, которые открываются при прокрутке. Я думаю, что это связано с вызовом -drawRect, заставляющим его перерисовывать сетку, но я не знаю, почему он затемняет штрихи, поскольку их непрозрачность уже должна быть 1.0. Кроме того, если я полностью прокручу исходный кадр и вернусь назад, сетка там также станет темнее.

  3. Есть ли способ нарисовать сетку в начале программы, которой нет в drawRect, чтобы она не перерисовывалась? Я пробовал использовать -awakeFromNib и -initWithFrame даже с -lockFocus, но это не сработало. Я понимаю, что первое, вероятно, не сработало, потому что не было рамки для рисования.

  4. В конце концов, мне нужно будет разобраться в таких вещах, как инструмент заливки и тому подобное, так что было бы лучше использовать для этого что-то вроде Core Graphics, или обычный API в порядке? Я бы предпочел использовать более позднее, поскольку я знаю о нем больше, чем компьютерную графику, но я тоже немного читал об этом.

Заключительные примечания: я использую сборку мусора, и я перевернул представление и окно, в котором оно находится, если это вообще имеет значение.

Изображение запущенной программы:

Изображение запущенной программы

    - (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    [self setFrameSize:NSMakeSize(3000, 3000)];
    return self;
}

- (void)drawRect:(NSRect)rect {

    width = [self frame].size.width;
    height = [self frame].size.height;

    [[NSColor grayColor] setStroke];

    NSBezierPath* drawingPath = [NSBezierPath bezierPath];
    [NSBezierPath setDefaultLineWidth:2.0];
    [self addDashStyleToPath:drawingPath];

    int i;

    for( i = 0 ; i <= width ; i=i+30) {
        [drawingPath moveToPoint:NSMakePoint(i, 0)]; 
        [drawingPath lineToPoint:NSMakePoint(i, height)]; 
    } 

    for( i = 0 ; i <= height ; i=i+30) { 
        [drawingPath moveToPoint:NSMakePoint(0,i)]; 
        [drawingPath lineToPoint:NSMakePoint(width, i)]; 
    }

    [drawingPath stroke];

}
-(void)drawStitch{

    NSPoint thisPoint;
    NSPoint fillPoint;
    NSRect fillRect;


    float thisPointX = [self calculatedItemBounds].origin.x + 5.0;
    float thisPointY = [self calculatedItemBounds].origin.y - 8.0;

    float fillPointX = [self calculatedItemBounds].origin.x + 1.0;
    float fillPointY = [self calculatedItemBounds].origin.y + 1.0;

    thisPoint.x = thisPointX;
    thisPoint.y = thisPointY;

    fillPoint.x = fillPointX;
    fillPoint.y = fillPointY;

    fillRect.origin.x = fillPoint.x;
    fillRect.origin.y = fillPoint.y;

    fillRect.size.width = 28;
    fillRect.size.height = 28;

    NSMutableDictionary *theAttributes;

    theAttributes = [[NSMutableDictionary alloc] init];
    [theAttributes setObject: [NSColor whiteColor] forKey:NSForegroundColorAttributeName];
    [theAttributes setObject: [NSFont fontWithName:@"Helvetica" size: 32] forKey: NSFontAttributeName];

    NSString *theString = @"+";
    [self lockFocus];
    [[NSColor blackColor] setFill];
    [NSBezierPath setDefaultLineWidth:2.0];
    [self addDashStyleToPath:[NSBezierPath bezierPathWithRect:[self calculatedItemBounds]]];
    [NSBezierPath fillRect:fillRect];

    NSNumber* myInteger = [NSNumber numberWithInt:310];

    [myArray setObject:myInteger :location.x/30 :location.y/30];
    NSLog(@"%@", [myArray objectInSection:location.x/30 :location.y/30]);
    NSLog(@"%f, %f", location.x/30,location.y/30);

    [theString drawAtPoint:thisPoint withAttributes:theAttributes];
    [self displayIfNeededInRectIgnoringOpacity:[self calculatedItemBounds]];

    [self unlockFocus];
    [theAttributes release];
}

Я, очевидно, довольно нубичен в этом, так что спасибо за вашу помощь!


person nintandrew    schedule 06.07.2011    source источник
comment
Хорошо, я решил проблемы 2 и 3 с помощью оператора if, который рисует сетку только при первом вызове -drawRect. Знание того, будет ли Core Graphics работать лучше, все равно поможет. Но номер один по-прежнему остается моей главной проблемой. Если я сделаю стежок на экране и прокручиваю его так, чтобы он упирался в край прокрутки, когда я прокручиваю сделанный мной стежок обратно к центру, он копирует этот стежок, как хвост от края. Кроме того, я пытался использовать 2D-массив для хранения нарисованных стежков, но он заметно тормозит. Ссылка в правильном направлении была бы очень полезна.   -  person nintandrew    schedule 09.07.2011


Ответы (2)


По умолчанию представление содержимого (экземпляр NSClipView) NSScrollView выполняет некоторую оптимизацию производительности путем копирования существующего визуализированного изображения при прокрутке. В большинстве случаев это работает нормально, но когда вы рисуете сложный пользовательский вид, это часто нежелательное поведение, поэтому вам следует отключить его.

Если вы используете перо для определения своего пользовательского интерфейса, просто выберите режим прокрутки в IB и снимите флажок «Копии при прокрутке».

Вы можете установить это программно, используя ‑setCopiesOnScroll: метод NSClipView:

[[scrollView contentView] setCopiesOnScroll:NO];
person Rob Keniger    schedule 06.07.2011
comment
Хорошо, я снял этот флажок для прокрутки в IB, но теперь вся сетка меняет цвет на темный, когда я начинаю прокручивать. Кроме того, все, что я рисую, остается на том же месте при прокрутке, как будто полосы прокрутки просто перемещаются, ничего не делая. Однако он меняет вид, поскольку я NSLog, где пользователь щелкает, но нарисованный контент не перемещается. Боковое примечание: похоже, это не из копий при прокрутке, но без моего метода -adjustScroll линии сетки, похоже, соединяются вместе и перепутываются. Я думаю, это тоже, вероятно, из-за того, что сетка была нарисована в -drawRect. - person nintandrew; 06.07.2011
comment
Что делает ваш adjustScroll метод? Вам не нужно ничего делать для поддержки прокрутки, если ваше представление больше, чем видимая область представления прокрутки, прокрутка будет работать. Я тестировал урезанную версию вашего кода рисования, и он отлично работает. - person Rob Keniger; 07.07.2011
comment
Он просто выполняет прокрутку с шагом 30 пикселей. Опять же, я думаю, это потому, что код рисования сетки находится в -drawRect, поэтому, даже когда представление прокручивается почти не прокручивается, он перерисовывает сетку в обнаруженных частях представления, портя ее, если прокрутка не отрегулирована. Кроме того, я, вероятно, должен был сказать это раньше, но это все в подклассе NSView (представление документа в scrollview), должен ли я создать подкласс NSScrolView и попробовать это в нем? - person nintandrew; 07.07.2011

Я действительно считаю, что исправил это. Чтобы он заработал, мне пришлось изменить код, чтобы рисовать в drawRect, а не использовать lockFocus в моем методе drawStitch (мне нужно прочитать о проектировании MVC). Кроме того, scrollview, кажется, перерисовывает только последний путь Безье, поэтому, чтобы сделать несколько «стежков», мне нужно продолжать добавлять путь с помощью прямоугольников.

person nintandrew    schedule 13.07.2011