Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.10.23;
Скачать: [xml.tar.bz2];

Вниз

Вопрос про csOpaque   Найти похожие ветки 

 
Суслик ©   (2005-09-27 20:02) [0]

Добрый день.

Никак не могу понять, как работает csOpaque.
1. Создаю кнопку
2. Создаю TWinControl, у которого ControlStyle := ControlStyle - [csOpaque]. При этом этот TWinControl "лежит" НАД кнопкой.

Почему не видна кнопка? Вроде должна...


 
Суслик ©   (2005-09-27 20:08) [1]

Example

var
  kf: tform;
  kb: tbutton;
  kc: twincontrol;
begin
  kf := tform.createnew(application);

  kb := tbutton.create(kf);
  kb.parent := kf;
  kb.left := 10;
  kb.top := 10;

  kc := twincontrol.create(kf);
  kc.parent := kf;
  kc.controlstyle := kc.controlstyle - [csopaque];
  kc.left := 5;
  kc.top := 5;
  kc.width := 100;
  kc.height := 100;

  kf.show();
end;


 
umbra ©   (2005-09-27 20:12) [2]

так контрол заслоняет

csOpaque контрол полностью заполняет своой клиентский прямоугольник.


Если csOpaque убрать, то будет заполнять не полностью, но как-то ж будет. И


Не стоит изменять ControlStyle во время віполнения, разве что в конструкторе. Текущие характеристики содержатся в свойстве ControlState.


 
Суслик ©   (2005-09-27 20:18) [3]


> Не стоит изменять ControlStyle во время віполнения, разве
> что в конструкторе. Текущие характеристики содержатся в
> свойстве ControlState.

в данном примере это не важно

все равно тоже самое...

type
  twincontrol2 = class(twincontrol)
     constructor create(o: tcomponent); override;
  end;

constructor twincontrol2.create;
begin
  inherited;
  controlstyle := controlstyle - [csopaque];
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  kf: tform;
  kb: tbutton;
  kc: twincontrol2;
begin
  kf := tform.createnew(application);

  kb := tbutton.create(kf);
  kb.parent := kf;
  kb.left := 10;
  kb.top := 10;

  kc := twincontrol2.create(kf);
  kc.parent := kf;
  kc.left := 5;
  kc.top := 5;
  kc.width := 100;
  kc.height := 100;

  kf.show();
end;


 
Суслик ©   (2005-09-27 20:20) [4]

У меня есть подозрение, что я вообще неверно понимаю csOpaque...


 
umbra ©   (2005-09-27 20:25) [5]

с прозрачносью это не имеет ничего общего. Это преведенная строка из хелпа


csOpaque - контрол полностью заполняет свой клиентский прямоугольник.


 
umbra ©   (2005-09-27 20:26) [6]

для прозрачности достаточто Visible := false


 
Суслик ©   (2005-09-27 20:29) [7]

Знаю я эту строку из хелпа.
Но я же отключаю csOpaque. По идее, согласно же хелпу, контрол НЕ полностью заполняет свой прямоугольник.

Вот как раз этого эффекта, т.е. неполного заполнения прямоугольника, в моем примере и не видно.

В этом собственно и вопрос - почему?


 
umbra ©   (2005-09-27 20:36) [8]

по-моему, отличие в степени запонения на глаз не отличишь. вот если убрать csOpaque у кнопки, она на вид изменится хоть чуть-чуть?


 
Суслик ©   (2005-09-27 20:38) [9]

Причем здесь кнопка?

Ее же вообще не видно...

Да... надо будет поизучать controls.pas.


 
Игорь Шевченко ©   (2005-09-27 21:52) [10]

csOpaque определяет, будет ли ему посылаться сообщение WM_ERASEBKGND.

Opaque - непрозрачный. Значит, обязан нарисовать всю свою клиентскую область, а не заставлять родителя рисовать ее.


 
Суслик ©   (2005-09-28 09:35) [11]


> Значит, обязан нарисовать всю свою клиентскую


Вот я примерно так и думал. Только найти в коде controls.pas не могу.

Насколько я понимаю указанный тобой факт (т.е. что не посылвается wv_erasebkgnd) реализуется в TControl.InvalidateControl и далее в InvalidateRect (в 3ем параметре).

Собственно вопрос родиля потому, что:
1. Я задавал вопрос http://delphimaster.net/view/1-1127738263/
2. В ответе [3] Леонид Трояновский сказал, что нужен csOpaque.
3. Я пытаюсь понять на что он влияет, т.к. что без csOpaque, что c csOpaque я не вижу разницы.

Т.е. как бы увидеть разницу в поведении потомков TWinControl c csOpaque и без него?


 
Суслик ©   (2005-09-28 09:51) [12]

В своем предположении, что:
1 Посылает wm_erasebkgnd BeginPaint
2 Управляет необходимость посылки этого сообщения InvalidateRect
я был вроде прав.

Тогда вопрос.
1. Есть потомок TWinControl
2. В стилях контрола НЕТ csOpaque
3. На контроле ничего не лежит.
Почему под контролом ничего не видно (т.е. не видны другие контролы, например TButton, лежищие под моим контролом)?


 
Игорь Шевченко ©   (2005-09-28 10:07) [13]


> 1. Есть потомок TWinControl
> 2. В стилях контрола НЕТ csOpaque
> 3. На контроле ничего не лежит.
> Почему под контролом ничего не видно (т.е. не видны другие
> контролы, например TButton, лежищие под моим контролом)?
>


Перекрой WMEraseBkgnd и не делай там ничего


 
Суслик ©   (2005-09-28 12:59) [14]

Вот интересно

type
  twincontrol2 = class(twincontrol)
     constructor create(o: tcomponent); override;
     procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  end;

constructor twincontrol2.create;
begin
  inherited;
  controlstyle := controlstyle + [csopaque];
end;

procedure TWinControl2.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  inherited; // до сюда управление доходит. Почему? Установлен же csOpaque.
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  kf: tform;
  kb: tbutton;
  kc: twincontrol2;
begin
  kf := tform.createnew(application);

  kb := tbutton.create(kf);
  kb.parent := kf;
  kb.left := 10;
  kb.top := 10;
  kb.width := 150;

  kc := twincontrol2.create(kf);
  kc.parent := kf;
  kc.left := 5;
  kc.top := 5;
  kc.width := 100;
  kc.height := 100;

  kf.show();
end;


 
Суслик ©   (2005-09-28 13:09) [15]

ах да, комментарий, что интересно забыл вставить - см. комментарий в теле листинга в методе WVEraseBkgnd.


 
Игорь Шевченко ©   (2005-09-28 13:47) [16]

Суслик ©   (28.09.05 13:09) [15]


> см. комментарий в теле листинга в методе WVEraseBkgnd.


см. пост 13

> и не делай там ничего


 
Суслик ©   (2005-09-28 13:59) [17]


>  [16] Игорь Шевченко ©   (28.09.05 13:47)

да я понял. Если ничего не делать, то будет "грязь" - остаток какого нить старого рисунка.

Вопрос то состоит в том, почему это сообщение вообще приходит. Вроде не должно - я же поставил csOpaque.

Вопрос не праздный, а скорее более теоретический - о влиянии csOpaque.


 
Игорь Шевченко ©   (2005-09-28 14:28) [18]

Суслик ©   (28.09.05 13:59) [17]


> Вроде не должно - я же поставил csOpaque.


Должно. Контрол же себя должен перерисовать, правильно ? Я могу еще раз сказать, что csOpaque отвечает за ответственность прорисовки. В случае csOpaque контрол сам обязан перерисовать всю свою клиентскую область, в случае отсутствия этого флага, часть клиентской области прорисовывает его родитель.


 
Суслик ©   (2005-09-28 14:35) [19]

Все вроде понятно, но все же.

Вот смотри:

1. Как я сказал, в случае если у контрола УСТАНОВЛЕН флаг csOpaque ему все равно приходит wm_erasebkgnd
2. Т.е. вызывается обработчик сообщения TWinControl.WMEraseBkgnd. В нем мы видим, что в любом случае (мой контрол НЕ DoubleBuffered) происходит прорисовка прямоугольника.

procedure TWinControl.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
 { Only erase background if we"re not doublebuffering or painting to memory. }
 if not FDoubleBuffered or
    (TMessage(Message).wParam = TMessage(Message).lParam) then
   FillRect(Message.DC, ClientRect, FBrush.Handle);
 Message.Result := 1;
end;


Т.е. несмотря на наличие csOpaque происходит рисование прямоугольника.

Что я в этом понимаю не так?


 
Игорь Шевченко ©   (2005-09-28 15:13) [20]

Суслик ©   (28.09.05 14:35) [19]


> 1. Как я сказал, в случае если у контрола УСТАНОВЛЕН флаг
> csOpaque ему все равно приходит wm_erasebkgnd


TControl.Invalidate и TControl.Repaint глянь

кроме того, у меня есть сильное подозрение, что csOpaque имеет больше смысла для TControl, нежели для TWinControl


 
Суслик ©   (2005-09-28 15:16) [21]


> кроме того, у меня есть сильное подозрение, что csOpaque
> имеет больше смысла для TControl, нежели для TWinControl

скорее для TGraphicControl.

Указанные методы вроде смотрел. Не особо что видно.
У меня есть подозрение, что понять как это все работает можно только тотальным изучением controls.pas.


 
umbra ©   (2005-09-28 15:20) [22]

Может, дело прояснит TWinControl.Invalidate и связанная с ней TWinControl.CMInvalidate. Там видно, что если есть стиль csOpaque, то прямоугольник контрола не должен перерисовываться


 
Суслик ©   (2005-09-28 15:23) [23]


>  [22] umbra ©   (28.09.05 15:20)

Ты понимаешь в чем дело, рассуждения, начиная с поста [14] говорят об обратном - все равно перерисовывается. Возьми код из [14].
Поставь breakpoint в wmerasebkgnd и увидишь.


 
Игорь Шевченко ©   (2005-09-28 15:52) [24]

Суслик ©   (28.09.05 15:16) [21]


> скорее для TGraphicControl.


Без разницы.


> У меня есть подозрение, что понять как это все работает
> можно только тотальным изучением controls.pas.


Достаточно одной строчки:

     InvalidateRect(FHandle, nil, not (csOpaque in ControlStyle));

и справки по InvalidateRect


 
umbra ©   (2005-09-28 15:53) [25]

дело в том, что wm_erasebkgnd - сообщение виндоуз, а csOpaque - стиль контрола в Делфи. И, похоже, реализован он не на уровне сообщений винды, а позже - В TControl.Invalidate, TWinControl.Invalidate и т.д. В этих методах речь идет не о wm_erasebkgnd, а о СM_INVALIDATE - сообщении, определенном в Делфи, и действия различаются для контрола с csOpaque и для контрола без него!


 
Суслик ©   (2005-09-28 15:55) [26]


> Достаточно одной строчки:
>
>      InvalidateRect(FHandle, nil, not (csOpaque in ControlStyle));
>
> и справки по InvalidateRect

кто же спорит.
Но опыт показывает, что наличие csOpaque не гарантирует, что wm_erasebkgnd не прийдет.

См. [14].


 
Игорь Шевченко ©   (2005-09-28 16:10) [27]

Суслик ©   (28.09.05 15:55) [26]


> Но опыт показывает, что наличие csOpaque не гарантирует,
>  что wm_erasebkgnd не прийдет.


Ты читаешь внимательно ? Или через слово ? В каком посте сказано, что наличие этого флага гарантирует/не гарантирует посылку WM_EraseBkgnd ?

Запусти поиск по каталогу с исходными текстами VCL слова csOpaque в файлах *.pas - посмотри, как и в каких случаях используется.


 
Суслик ©   (2005-09-28 16:22) [28]

Так. Будем корректнее про мою внимательность.

Берем InvalidateRect. Читаем про третий параметр
bErase
[in] Specifies whether the background within the update region is to be erased when the update region is processed. If this parameter is TRUE, the background is erased when the BeginPaint function is called. If this parameter is FALSE, the background remains unchanged.


Читаем про BeginPaint
Remarks
The update region is set by the InvalidateRect or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or any other operation that affects the client area. If the update region is marked for erasing, BeginPaint sends a WM_ERASEBKGND message to the window.


Судя по всему кто-то еще, а не указанный тобой InvalidateRect маркирует регион for erasing.


 
Суслик ©   (2005-09-28 16:23) [29]

Виноват. Дурацкий шрифт получился.
Лучше так:

bErase
[in] Specifies whether the background within the update
region is to be erased when the update region is processed.
If this parameter is TRUE, the background is erased when
the BeginPaint function is called. If this parameter is
FALSE, the background remains unchanged.


 
umbra ©   (2005-09-28 16:37) [30]

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


 
Суслик ©   (2005-09-28 16:42) [31]

Вот и вопрос - кто его посылает. Я не доказываю, что я прочел все и сделал вывод, что посылать сообщение некому. Я лишь говорю о том, что в приведенных кусках кода про InvalidateRect + дока на BeginPain можно сделать вывод, что его посылает еще кто-то. Вот и интересно кто?


 
Игорь Шевченко ©   (2005-09-28 16:43) [32]


> Судя по всему кто-то еще, а не указанный тобой InvalidateRect
> маркирует регион for erasing


Регион задается вторым параметром этой функции. Третий параметр определяет, будет ли посылаться WM_Erasebkgnd при отрисовке этого региона.

При вызове Invalidate такому контролу ничего не придет. Но это не значит, что сообщение WM_EraseBkgnd контролу не придет вообще.
Опять же, если у контрола нет этого стиля, то InvalidateRect вызывается для родительского окна с указанием стереть клиентскую область, занимаемую контролом. То есть, контрол сам не рисует ВСЮ свою область и делегирует часть рисования родительскому компоненту.


 
Суслик ©   (2005-09-28 16:44) [33]

Спасибо, Игорь.
Буду смотреть, интересно.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.10.23;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.038 c
8-1117544871
LameFox
2005-05-31 17:07
2005.10.23
Работа с большими картинками


3-1126123296
Alpine
2005-09-08 00:01
2005.10.23
Нужно чделать отбор выделенных записей !


2-1127846953
vvh
2005-09-27 22:49
2005.10.23
Базы данных и Интернет


14-1128055512
CHES
2005-09-30 08:45
2005.10.23
Примеры "нестандартных" решений.


14-1128078838
Delphin
2005-09-30 15:13
2005.10.23
Как позвонить?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский