2010-11-11 4 views
1

У меня есть панель, в которой я делаю какой-то пользовательский чертеж. Чтобы пропорционально масштабировать графику при изменении размера панели, я использую свойство Transform моего Graphics.Жесткое масштабирование графики при изменении размера панели

private void panelGraph_Paint(object sender, PaintEventArgs e) 
{ 
    var gfx = e.Graphics; 
    gfx.Transform = BuildTransform(e.ClipRectangle); 
    var width = 1.0f/gfx.Transform.Elements[0]; 
    var white = new Pen(Color.White, width); 
    gfx.DrawLine(white, new PointF(-1.0f, -1.0f), new PointF(1.0f, -1.0f)); 
    gfx.DrawLine(white, new PointF(-1.0f, -1.0f), new PointF(-1.0f, 1.0f)); 
} 

Матрица из BuildTransform отображает область с шириной и высотой [-2, 2] в области e.ClipRectangle.

Код работает, как. Проблема в том, что когда я изменяю размер панели, масштабирование моей графики не является гладким, но происходит с дискретными шагами. Если добавить следующую строку в моей лакокрасочное функции:

Console.WriteLine("Paint {0} {1}", e.ClipRectangle.Width, e.ClipRectangle.Height); 

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

Paint 1 815 
Paint 1 815 
Paint 1 815 
Paint 751 815 
Paint 1 815 
Paint 753 815 
Paint 1 813 
Paint 754 811 

Что вызывает это и как я могу это исправить?

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

ответ

2

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

+0

Ага, я думаю, я понимаю свой результат сейчас.Прямоугольник клипа - это область, которая нуждается в перекраске, поэтому, когда я просто отрегулирую вертикальный размер окна, произнеся один пиксель, я получаю размер клипа примерно как '654, 1'. Как только я изменю его по горизонтали, а также весь регион нужно будет перерисовать. –

+0

Да! WinForms пытаются оптимизировать перерисовку для вас. Окна обычно собирают области и используют самый маленький прямоугольник, содержащий их все для процесса невязки. Довольно часто вам необходимо переопределить это поведение, если вы хотите иметь гладкую графику, то есть во взаимодействии с пользователем. Вы также можете взглянуть на эту ссылку: http://stackoverflow.com/questions/957573/winforms-how-to-speed-up-invalidate – Pedery

3

AFAIK, ClipRectangle не то, что вам нужно, вместо этого используйте Bounds.

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

+0

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

+0

Используйте контрольные BOUNDS, как сказано, попробуйте с ним. Размер, предоставленный в событии перерисовки, - это то, что вы не хотите использовать здесь. Если это сработает, я попытаюсь объяснить, почему. –

+0

Я добавил объяснение, которое должно как-то вас успокоить :) –

1

Настроить свойство Form.DoubleBuffer на true.

+0

Это только удаляет мерцание (что приятно конечно), проблема с масштабированием остается. –

1

Вот композит правильных ответов других людей:

  • Вы должны переопределить/обработать событие изменения размера и аннулирует все окно
  • Вы должны использовать ClientRectangle и не e.ClipRectangle при расчете масштабирования для окно.
Смежные вопросы