Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > Форма "моргает". Как сделать перерисовку быстрой?


Автор: Гость_Александр 27.6.2004, 11:42
Добрый день!

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

И когда форма по какой-то причине (изменение размера, открытие-закрытие панели и т.п.) отрисовывает себя по новой, это выглядит, как нервный тик - всё начинает "моргать" и дёргаться.

Прошёл по списку компонентов, выставил всем DoubleBuffer. "Моргать" перестало, но время отрисовки формы выросло настолько, что можно чуть ли не кофе попить, пока она приводит себя в порядок.

Думаю, я не первый сталкиваюсь с такими вещами. Кто уже решал подобные проблемы - поделитесь опытом, плиз! Спасибо заранее.

Автор: Borland_Delphi_6 27.6.2004, 12:39
У меня похожая проблема: Timage должен двигаться, из-за этого его сильно глючит sad.gif Кто-нибудь знает решение подобных проблем?

Автор: ZLDO 27.6.2004, 12:50
Зачем двигать TImage? Нужно двигать изображение на TImage, а чтобы не моргало нужно всё прорисовывать в памяти (например временных TBitmap), а потом за один раз выдавать на экран - ...Canvas.Draw или BitBlt

Автор: <Spawn> 27.6.2004, 18:21
Гость_Александр у тебя какая машина, что так тормозит от DoubleBuffered? И зачем для каждого контрола ее выставлять? Достаточно для формы поставить. У тебя точно на таймерах\потоках ни чего не сидит?

Автор: Гость_Александр 28.6.2004, 13:02
Машина - второй пень. Тормозит она не так страшно, но задержка в несколько секунд с прорисовкой - это хреново. Просто на форме много всякого понавешано.

Насчёт DoubleBuffered для формы - ты знаешь, если выставить для формы или если выставить для каждого компонента, программа ведёт себя по-разному.

Автор: dm9 29.6.2004, 04:02
Borland_Delphi_6, насчёт TImage.
Передо мной стояла задача периодической перерисовки изображения - всё работало очень плавно. Двигать Image - изврат. Я бы просто перерисовывал изображение на канве парента с новыми координатами. Делается так.

Сам обработчик onPaint:
Код
var
  Bitmap     : HBITMAP;
  BitmapInfo : TBitMapInfo;


Код
procedure TESSGMainForm.pbPaint(Sender: TObject);
var
  MemDC : HDC;
  bm    : TBitmap;
begin
  MemDC := CreateCompatibleDC(pb.Canvas.Handle);
  SelectObject (MemDC, Bitmap);
  GetObject (Bitmap, SizeOf (TBITMAP), @bm);
  BitBlt (pb.Canvas.Handle, 0, 0, pb.Width, pb.Height, MemDC, 0, 0, SRCCOPY);
  DeleteDC (MemDC);
end;


(Подумав) О, Господи. А теперь надо рассказать, как по-простому загрузить картинку в HBitmap, как использовать CreateDIBSection...

А сейчас 5 утра.
В общем, извините. Если ЭТО кому-то надо - будет. Если нет - то нет.
Просто сейчас писать про всё это очень не хочется... smile.gif
Добавлено @ 04:03
Если интересно - напишите, и завтра я опишу всё подробно.

Автор: Borland_Delphi_6 29.6.2004, 15:31
dm9
Нужно, нужно smile.gif В общем, у меня есть jpeg, его нужно туда-сюда по форме таскать

Автор: dm9 2.7.2004, 21:38
Borland_Delphi_6, что-то я тогда загнался smile.gif
DIB - это хорошо, но в данном случае совершенно ни к чему.
Просто создаёшь динамически j : TJPEGImage, грузишь туда картинку и затем отрисовываешь картинку на форме:
Form1.Canvas.Draw (X, Y, j);

Единственное, можно допустить такую ошибку. На таймере или как там поставить изменение координат X и Y, и затем написать Form1.Repaint или Form1.Refresh. Тогда будет моргать. А надо писать просто Form1.Canvas.Draw (X, Y, j). Всё плавно - я проверил. На на onPaint форсы тоже на забыть отрисовку.

А то тут хотел уж рассказывать, как работать с DIB и DDB smile.gif Отдохнуть просто надо - я слишком долго занимался этими DIB - зациклился уже.

Автор: Borland_Delphi_6 3.7.2004, 16:34
Цитата
На на onPaint форсы тоже на забыть отрисовку.

Смысл этого предложения мне не понятен... withstupid.gif
И еще. Вот у меня был такой код:
Код
if Image1.Left>=(Form1.ClientWidth-5)-Image1.Width
then gx:=-gx;
if Image1.Top>=(Form1.ClientHeight-5)-Image1.Height
then gy:=-gy;
if Image1.Top<=0
then gy:=-gy;
if Image1.Left<=0
then gx:=-gx;
Image1.Left:=Image1.Left+gx;
Image1.Top:=Image1.Top+gy;

(это что-то вроде скринсевера)

Как мне теперь узнать аналог Image1.Left и Image1.Top?

Автор: dm9 4.7.2004, 01:39
Borland_Delphi_6, в простейшем случае я имел в виду это (см. файл).
Если более сложно - там надо писать ещё обработчик onPaint для формы и делать не столь халявную перерисовку.
Добавлено @ 01:39
PS Там что-то типа 5 килобайт...

Автор: Borland_Delphi_6 4.7.2004, 13:14
dm9
Спасибо, примерчик очень хороший! Тока я взялся попробовать написать эту прогу на API, а то уж слишком большая она получается. smile.gif

Автор: dm9 4.7.2004, 14:44
Borland_Delphi_6, О! А вот здесь тогда как раз понадобится работа с DIB smile.gif
И отрисовку делать надо будет, как я написал.

Будет время - скину примерчик.

Автор: Borland_Delphi_6 4.7.2004, 15:12
dm9
Спасибо, как раз хотел тебе попрасить об этом rolleyes.gif Точнее, вывести пикчуру я уже научился, вот так вот:
Код
bmp:=LoadImage(0,'img.bmp',IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
WindowDc:=GetDC(MainWnd);
memorydc:=CreateCompatibleDC(windowdc);
SelectObject(memorydc,bmp);
BitBlt(windowdc,x,y,200,150,memorydc,0,0,SRCCOPY);
DeleteDC(memorydc);
ReleaseDC(MainWnd,windowdc);

Автор: dm9 5.7.2004, 17:03
Вот тебе примерчик отрисовки, всё на чистом WinAPI. (Не мой).
Что там тебе ещё надо. Таймер? smile.gif

Да, и не забывай всякие DeleteDC, DeleteObject, etc.

Кстати, мои эксперименты показывают, что при такой отрисовке BeginPaint и EndPaint не спасают от мерцания почему-то... Это если движение картинки делать.
Добавлено @ 17:04
PS Компиляция - запуск батника. Там < 30 кБайт.

Автор: Albinos_x 5.7.2004, 17:27
имеются две фазы обновления окна.
1. привыводе окна винда посылает сообщение WM_ERASEBKGND, оповещяющее онеобходимости стирания фона перед процедурой рисования. Затем посылается сообщение WM_PAINT, служащее сигналом для закрашивания.
Первое сообщение можно пропустить
а) форсируя обновление самому с помощью вызова функции InvalidateRect(Handle, Nil, False) ;
б) Можно указать VCL не стирать фон
ControlStyle := ControlStyle + [csOpaque];

В этом случае от моргания можно избавиться.

PS: Второй выриант в ХР не срабатывает почему-то (имею ввиду, что всё равно моргает), первый не проверял, но работать должен.

Автор: Borland_Delphi_6 5.7.2004, 17:29
Цитата
Кстати, мои эксперименты показывают, что при такой отрисовке BeginPaint и EndPaint не спасают от мерцания почему-то... Это если движение картинки делать.

Тогда не катит sad.gif но у меня вроде есть код пдходящий, проблема не в этом...

Автор: Albinos_x 5.7.2004, 17:36
Borland_Delphi_6

мой вариан не пробовал?

Автор: dm9 5.7.2004, 19:23
Borland_Delphi_6, на этих BeginPaint-ах свет клином не сошёлся. Их можно вообще не использовать.

Albinos_x, я немного не то имею в виду. Если делать отрисовку тем способом, который я предложил, через BitBlt, то эта самая отрисовка происходит сразу же, мгновенно. Если поставить отрисовку между BeginPaint и EndPaint, ничего не меняется. Поэтому если мы делаем движение картинки таким образом: стираем фон, а затем рисуем картинку на новом месте, то получается мерцание. Я знаю только один способ, как сделать, чтобы процесс перерисовки не появлялся на экране - рисовать на дополнительном DC, созданном при помощи CreateCompatibleDC, а затем его отрисовывать на основной DC. Проблема в том, что при больших изображениях получается медленно.

Можно, прада, применить хитрость. Если фон монотонный, то просто сделать окантовку картинке с таким же цветом и при плавном перемещении картинка сама будет закрашивать себя. Так я сделал в первом VCL-ном примере.

PS Может быть, глюк с BeginPaint и EndPaint связан с тем, что у меня Win2003...

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)