Без мерцания
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