Содержание сайта
Главная Новичку Цитаты Реализации Статьи Документация
Компании Программы Ссылки Обсуждение Обсуждение 2 Гостевая

Без мерцания

Алексей Баран
email: 'bmfycApqujnb/dpn/vb' collect: [:e | Character value: e asInteger - 1]

Андрей Собчук
email: 'boesfjAnbsu/dl/vb' collect: [:e | Character value: e asInteger - 1]

English version

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

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

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

Вы можете воспользоваться исправлениями к текущей реализации двойной буферизации.
Загрузите парсел или установите пакет DoubleBufferingFix из Cincom public repository.
И включите двойную буферизацию Settings->System->Repair policy. Только новые окна будут использовать двойную буферизацию. Окна, открытые ранее, будут содержать эффект мерцания.

Так что же не работает в текущей реализации двойной буферизации?
Когда графический элемент хочет себя перерисовать он посылает сообщение из семейства invalidate. В сообщении указывается должна ли перерисовка быть выполнена сразу (repairNowNoFill: true) либо можно подождать пока окно само не начнет перерисовку (repairNowNoFill: false). Текущая реализация двойной буферизации работает только в случае отложеных перерисовок (repairNowNoFill: false). В случае же немедленной перерисовки будут видны мерцания. Эти мерцания вызваны рисованием на экране, в то время как надо бы рисовать на невидимом холсте.

Для наглядного примера возьмем Aragon DataSet. Когда DataSet решает выполнить перерисовку строки он требует это выполнить безотлагательно (repairNowNoFill: false). Поэтому, даже если у вас включена двойная буферизация вы все равно увидите мерцания. DoubleBufferingFix помогает этого избежать.


Для тех, кто любит рыться в коде и хочет знать где ошибка зарыта:

ApplicationWindow >> invalidateRectangle: aRectangle 
	repairNow: aBooleanOrSymbol 
	forComponent: aVisualComponent

	"Damage is coming up from below.  Resolve with 
	outstanding damage and redisplay if aBoolean is true,
	otherwise just accumulate.  In adition to true
	and false for aBooleanOrSymbol the reciever 
	handles #repairNowNoFill which can keep flashing 
	out of the picture when the visual component 
	needing repair is opaque."

	| box  gc|
	self isOpen ifFalse: [^self].
	"Check for invalidation suppression.
	See comment in extentEvent: for details."
	self sensor invalidationSuppressed ifTrue: [^self].
	self sensor pseudoEvent.
	box := self bounds.
	(aRectangle intersects: box ) ifTrue: 
		[ | dbox |
		dbox := aRectangle intersect: box.
		(damageRepairIsLazy and: [aBooleanOrSymbol == false])
			ifTrue: [^self sensor addDamage: dbox].
		self sensor hasDamage ifTrue: [self displayPendingInvalidation].
	
	>>> Код ниже должен
	>>> не напрямую рисовать на graphicsContext
	>>> a передать эту обязанность damageRepairPolicy
	>>> в нашем случае DoubleBufferingWindowDisplayPolicy
	
		gc := self graphicsContext.
		gc clippingRectangle: dbox.
		aBooleanOrSymbol == #repairNowNoFill ifFalse: 
			[gc paint: self backgroundColor.
			gc displayRectangle: dbox].
		gc paint: self foregroundColor.
		self component displayOn: gc.
		^self flush]

В исправленном варианте рисование выполняется с помощью damageRepairPolicy

	self damageRepairPolicy
		displayArea: dbox
		in: self
		repairNowNoFill: aBooleanOrSymbol 



Есть комментарии? Пишите.