пятница, 28 февраля 2014 г.

VCL: Show vs Visible

У котнролов в VCL есть свойство Visible, которое как называется, за то и отвечает. Если Visible = False, то контрол скрыт и пользователь его не увидит. Если Visible = True, то есть вероятность, что пользователь его увидит.

А есть ещё два метода – Hide и Show, которые взаимодействуют со свойством Visible.

А теперь вопрос: как же правильно скрывать/отображать контрол?

На самом деле вопрос с небольшим подвохом, на него ответить однозначно нельзя, но… давайте по порядку

В большинстве случаев ответ напрашивается сам собой: используем Visible, т.к. это способствует единообразию. Например, потому что есть свойство Enabled, для которого нету методов типа Enable/Disable. У экшенов (TAction) есть Visible, но нет Show/Hide. И ещё такой момент, сравните:

LabelSomeInfo.Visible := SomeCondition;

и

if SomeCondition then
  LabelSomeInfo.Show
else
  LabelSomeInfo.Hide;

Первый вариант и пишется быстрее, и проще сопровождается. (Правда всегда найдутся люди, которые скажут, что второй вариант выразительнее первого...)

Ещё можно порассуждать так (на интуитивном уровне, ещё не заглядывая в исходники или справку). Visible – это свойство, которое задаёт (и показывает) состояние контрола на текущий момент времени. Show/Hide – это методы, они призваны изменить состояние контрола, но не факт, что это произойдёт одномоментно, и не факт, что это действие не приведёт к какому-то побочному эффекту. Поэтому (как бы) безопаснее использовать Visible.

 

Теперь самое время заглянуть в исходники VCL. Hide просто скрывает контрол (устанавливая Visible в False). А вот Show не только меняет Visible, но делает кое-что ещё. А именно – вызывает виртуальный метод ShowControl у родительского контрола (если такой определён). А это и есть тот самый побочный эффект, о котором можно догадаться на интуитивном уровне. На практике, в самой VCL, я нашёл только одно место, где это можно использовать – компонент TPageControl. Когда мы вызываем Show для контрола, расположенного на одной из вкладок PageControl’а, происходит активация той вкладки (TabSheet), на которой этот контрол расположен. Более того, если вложить несколько PageControl’ов друг-в-вдруга, то активация вкладок произойдёт по цепочке от контрола вверх до самой формы.

Т.е. вывод делаем такой: если просто нужно задать состояние для контрола (в большинстве случаев именно это и нужно), то используем Visible. Если нужно акцентировать внимание пользователя на контрол, то используем Show (и ещё, после этого, можно вызвать SetFocus для полей ввода). Зачем нужен Hide – не знаю, видимо он заводился на “автомате”, в противовес Show. Ещё странно, что эти методы не виртуальные…

В общем, это надо знать и уметь применять.

 

А за примерами, где это может быть применимо, далеко ходить не надо. В самой IDE Delphi: нажимаем F6, набираем “editor font”, жамкаем Enter – открывается окно с настройками IDE, осуществляется переход к вкладке Editor Options \ Display и устанавливается фокус ввода на комбобокс для выбора шрифта. (Уверен, что это сделано парой вызов Show + SetFocus для самого комбобокса.)

Ещё пример (уже из моей практики). На форме есть обязательное для ввода поле. Пользователь его не заполнил и переключился на другую вкладку, затем нажимает OK. Я вижу, что поле не заполнено, и просто вызываю пару методов Show + SetFocus (не задумываясь, надо ли активировать вкладку, на какой вкладке это поле и т.п.). После этого можно показать сообщение пользователю (мол заполни поле) или даже не показывать, а сделать Beep – фокус уже будет где надо, и пользователь поймёт, что от него требуется.

 

Полезный метод Show. Но его нельзя применять, когда надо просто отобразить какой-то контрол по условию (например при отображении формы), т.к. это может привести к переключению вкладок у PageControl’а.

5 коммент.:

Unknown комментирует...

А я то дурак свою функцию писал, чтобы все паренты отобразить.
Вообще, имхо, по SetFocus можно было бы такое поведение сделать.

Unknown комментирует...

Я где-то уже видел подобное в блоге, возможно здесь

Пишу еще раз. Надо удалятья и добвлять в жопу скрытие

Николай Зверев комментирует...

Лешик Иванов, я пока ещё не прочувствовал фишку с удалением. Дополнительная преграда для злых рук - да, но не везде она нужна. Экономия ресурсов - да, но очень не значительная. И ещё такой вопрос - почему именно удалять? Может лучше тогда вообще не создавать?

Анонимный комментирует...

НЕ совсем понял как ето у вас функция SetFocus() сама ищет не заполненые поля?

Николай Зверев комментирует...

Интересно, какая фраза навела Вас на вывод, что "SetFocus() сама ищет не заполненые поля"?

Отправить комментарий

.

.