Создание сетки в NSView

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

Цель сетки состоит в том, чтобы действовать как инструкция для пользователя при выстраивании в линию объектов. Все работает просто великолепно за одним исключением. Когда я изменяю размер NSWindow путем перетаскивания изменить размер дескриптора, если мой интервал сетки является особенно маленьким (говорят что 10 пикселей). перетаскивание изменяет размер, становится летаргическим по своей природе.

Мой drawRect код для сетки следующие:

-(void)drawRect:(NSRect)dirtyRect {

    NSRect thisViewSize = [self bounds];

    // Set the line color

    [[NSColor colorWithDeviceRed:0 
                           green:(255/255.0) 
                            blue:(255/255.0) 
                           alpha:1] set];

    // Draw the vertical lines first

    NSBezierPath * verticalLinePath = [NSBezierPath bezierPath];

    int gridWidth = thisViewSize.size.width;
    int gridHeight = thisViewSize.size.height;

    int i;

    while (i < gridWidth)
    {
        i = i + [self currentSpacing];

        NSPoint startPoint = {i,0};
        NSPoint endPoint = {i, gridHeight};

        [verticalLinePath setLineWidth:1];
        [verticalLinePath moveToPoint:startPoint];
        [verticalLinePath lineToPoint:endPoint];
        [verticalLinePath stroke];
    }

    // Draw the horizontal lines

    NSBezierPath * horizontalLinePath = [NSBezierPath bezierPath];

    i = 0;

    while (i < gridHeight)
    {
        i = i + [self currentSpacing];

        NSPoint startPoint = {0,i};
        NSPoint endPoint = {gridWidth, i};

        [horizontalLinePath setLineWidth:1];
        [horizontalLinePath moveToPoint:startPoint];
        [horizontalLinePath lineToPoint:endPoint];

        [horizontalLinePath stroke];
    }
}

Я подозреваю, что это полностью относится к способу, которым я тяну сетку и открыт для предложений о том, как я мог бы лучше пойти об этом.

Я вижу, где неэффективность входит, перетаскивание измененный размер NSWindow постоянно звонит drawRect в этом представлении, как это изменяет размер, и чем ближе сетка, тем больше вычислений на пиксель перетаскивает родительского окна.

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

У кого-либо есть какие-либо идеи о лучшем или более эффективном способе к рисованию сетки?

Вся справка, как всегда, очень ценивший.

6
задан Hooligancat 26 April 2010 в 22:27
поделиться

2 ответа

Вы непреднамеренно ввели Шлемиля в свой алгоритм. Каждый раз, когда вы вызываете moveToPoint и lineToPoint в своих циклах, вы фактически добавляете больше линий к одному и тому же пути, все из которых будут рисоваться каждый раз, когда вы вызываете stroke на этом пути.

Это означает, что вы рисуете одну линию в первый раз, две линии во второй раз, три линии в третий раз и т.д...

Быстрым решением может быть использование нового пути каждый раз через цикл, просто выполняя stroke после цикла (спасибо Джейсону Коко за идею):

path = [NSBezierPath path];
while (...)
{
    ...

    [path setLineWidth:1];
    [path moveToPoint:startPoint];  
    [path lineToPoint:endPoint];
}
[path stroke];

Обновление: Другой подход заключается в том, чтобы не создавать этот NSBezierPath вообще, а просто использовать метод класса strokeLineFromPoint:toPoint::

[NSBezierPath setDefaultLineWidth:1];
while (...)
{
    ...
    [NSBezierPath strokeLineFromPoint:startPoint toPoint:endPoint];
}

Обновление #2: Я сделал несколько базовых сравнительных тестов для подходов, использованных до сих пор. Я использую окно размером 800x600 пикселей, шаг сетки десять пикселей, и мне приходится перерисовывать окно тысячу раз, масштабируя его с 800x600 до 900x700 и обратно. Работая на моем MacBook Core Duo Intel 2 ГГц, я вижу следующее время:

Original method posted in question:  206.53 seconds  
Calling stroke after the loops:       16.68 seconds  
New path each time through the loop:  16.68 seconds  
Using strokeLineFromPoint:toPoint:    16.68 seconds  

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

Уроки:

  1. Скрытые Шлемиели могут действительно замедлить работу.
  2. Всегда профилируйте свой код перед ненужной оптимизацией
13
ответ дан 8 December 2019 в 18:34
поделиться

Вам следует запустить Instruments Cpu Sampler, чтобы определить, на что тратится большая часть времени, а затем выполнить оптимизацию на основе этой информации. Если это обводка, выведите ее за пределы петли. Если он рисует путь, попробуйте выгрузить рендеринг на графический процессор. Посмотрите, может ли CALayer помочь.

0
ответ дан 8 December 2019 в 18:34
поделиться