![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
про Align, когда выключена видимость родителей [Delphi, Windows]
Galkov © (2006-12-15 23:48:00)Вот пример:
Program test;
uses windows,kol;
type TMainForm=object
Control,Check,Panel_1,Panel_2,Button_1,Button_2:PControl;
procedure _OnClick(Obj:PObj);
end;
function TMainForm._OnClick;
begin
Panel_1.Visible := Check.Checked;
end;
var MainForm:TMainForm;
begin
Applet := NewApplet('TestApp');
with MainForm do begin
Control := NewForm(Applet,'Test').SetSize(400,300);
//CheckBox
Check := NewCheckBox(Control,'Show').SetPosition(10,240);
Check.OnClick := MainForm._OnClick;
//Panel_1
Panel_1 := NewPanel(Control,esLowered).SetPosition(10,10).SetSize(370,180);
Panel_1.Visible := false;
//Panel_2
Panel_2 := NewPanel(Panel_1,esRaised).SetSize(364,100);
Panel_2.Align := caTop;
NewSplitterEx(Panel_1,0,0,esRaised);
//Button_1
Button_1 := NewButton(Panel_2,'Button_1').SetSize(100,100);
Button_1.Align := caLeft;
NewSplitterEx(Panel_2,0,0,esRaised);
//Button_2
Button_2 := NewButton(Panel_2,'Button_1').SetSize(100,100);
Button_2.Align := caClient;
end;
Run(Applet);
end.
Размышляя над ним возникают вопросы:
1) Какие у нас гарантии, что здесь
procedure AlignChildrenProc( Sender: PObj );
type
TAligns = set of TControlAlign;
var P: PControl;
CR: TRect;
procedure DoAlign( Allowed: TAligns );
...........
if ChgPos or ChgSiz then
begin
C.BoundsRect := R;
if ChgSiz then
AlignChildrenProc( C );
end;
...........
НЕТ необходимости вызывать AlignChildrenProc, если не менялся размер контролла. Вроде бы совершенно не факт, что Ailgn там УЖЕ произведен. Видимость родителей, в момент предыдущих вызовов AlignChildrenProc, вполне могла быть выключена. Как в вышестоящем примере.
2) И чего делать, если возникает необходимость поменять некоторые размеры, в момент невидимости кого-то из родителей ???
Vladimir Kladov (2006-12-16 10:15:00) [41]А надо - Global_Align( Panel_2 ). Я же говорю, это только в этом конкретном случае, как раз потому что размер менялся в глубоко внутреннем, реально невидимом контроле. Объодить все контролы может быть накладно, если их много - на каждый чих. Например, при движении сплиттера. Все будет тормозить, и кому это понравится.
Нормальный случай: код НЕ меняет размер контролов, когда они реально не видны. Т.е. нормальный случай - это когда размеры контролирует пользователь, меняя позицию сплиттера или размер формы. Ваш случай выпал из нормального. Соответственно, приходится добавлять немного своего кода. Понимаю, что это чуть сложнее, чем просто ничего не делать. Но полный обход - это точно не выход.
Galkov (2006-12-16 09:10:00) [42]В момент включения видимости Global_Align(Panel_1) и так вызывается.
И целью примера было показать что это не всегда приводит к цели.
Но мне кажется, что всегда приведет, если рекурсивный вызов AlignChildrenProc из DoAlign вытащить из под условий проверки (обоих).
И мне тоже кажется, что это гораздо проще, чем проверять адекватность этой проверки.
Определять в Run Time "проблемность" парента - тоже ведь точно такой же не подарок. Ну откуда в момент включения видимости Panel_1 можно узнать, что на самом деле следует делать Global_Align(Panel_2) ???
Пример ведь, не конкретная проблема (измени 364 на 363 - и всего делов) - а демонстрация ее существования.
И хочется иметь решение для общего случая...
Vladimir Kladov (2006-12-16 09:00:00) [43]Выравнивание работает прекрасно, пока объекты, подлежащие выравниванию, видны на экране. Для того, чтобы выравнивание не выполнялось для невидимых управляющих элементов, и для того, чтобы невидимые управляющие элементы не участвовали в выравнивании (что важнее), в процедуре выравнивания проверяется значение свойства ToBeVisible. Почему именно, оно, а не Visible? Дело в том, что видимость контрола трактуется в терминах оконной системы несколько иначе, чем это подразумевает этимология слова Visible. Для нас «видимый» означает, что мы объект видим на экране. Когда форма передвинута так, что выходит за край экрана, то элементы, имеющие значение Visible = true, оказываются на самом деле невидимыми. Если форма заслонена другими окнами, то мы видим не все части этой формы. Но, даже не принимая в расчет эти случаи, можно обнаружить еще несколько ситуаций, в которых Visible = true не соответствует реальному положению дел.
Во-первых, это видимость родительского визуального объекта (т.е. визуального элемента, на котором размещается исследуемый контрол со значением свойства Visible = true). ToBeVisible возвратит true, только если контрол является видимым вместе со всеми своими родительскими окнами.
Во-вторых, есть такой особый визуальный элемент – tab control. В каждый отдельный момент времени фактически видимой является только одна из множества его закладок, хотя все его закладки могут иметь свойство Visible = true. Выполнять выравнивание для фактически невидимых закладок несколько накладно. Достаточно представить себе ситуацию, когда закладок много (например, 50), и на каждой имеется приличное количество объектов, подлежащих выравниванию (например, 20). Выполнять выравнивание для 1000 контролов, когда изменяется размер только одного из них, наверное, будет несколько накладно.
По этой причине, объекты, не являющиеся в данный момент фактически видимыми (ToBeVisible = false), исключаются из процедуры выравнивания – вместе со всеми своими дочерними визуальными объектами. Это может привести к тому, что окна окажутся не выровненными, если вы включите свойство Visible в значение true, предварительно изменив размеры каких-то подчиненных элементов в своей программе. Исправляется это довольно просто: достаточно вызвать функцию Global_Align( p ) для родителя проблемных (не выровненных) элементов, вместе с включением свойства Visible в true.
Данное решение – не идеально, я это признаю. Но оно простое, не требует много кода, не увеличивает ту часть кода, которая встраивается во все приложения, использующие выравнивание. И не надо мне говорить, что в VCL таких проблем нет. Там другие проблемы есть. Например, неожиданное изменение визуального порядка выровненных визуальных элементов после включения Visible в свойство true. Особенно неприятное, когда свое положение на неправильное меняет, например, сплиттер. Там для борьбы с подобным глюком приходится своим кодом менять значения свойств Left/Top проблемных контролов, и это решение ничуть не менее обходное, чем использование Global_Align в KOL.
Vladimir Kladov (2006-12-16 08:15:00) [44]всегда можно вызвать Global_Align( parent ) для проблемного parent'а, когда что-то не так. Например после включения видимости. Этот вызов стоить будет дешевле, чем городить сложные проверки в самом алгоритме выравнивания.