Все меняется. И это грустно. Долгое время моим наиболее используемым инструментом программирования являлся Delphi. Я специально не говорю "языком", потому что Delphi - это не просто язык программирования. IDE (интегрированная среда разработки) Delphi долгое время оставалась для меня эталоном того, что можно сделать для разработчика. А чего стоила инфраструктура компонентов, Wizard-ов, плагинов?
Но, в последнее время, я все больше сижу на Java, и к Delphi-разработкам возвращаюсь все реже и реже. К тому же, мое активное программирование на этом замечательном средстве застряло на уровне версий Delphi 5, Delphi 6, Delphi 7. Нет, я пробовал что-то писать на новых версиях, например, Delphi XE 3, даже пробовал FireMonkey, но опыт этот был весьма поверхностным и непродолжительным.
Именно поэтому я решил, что буду писать про то, что делаю в Delphi. Вполне возможно, многое из того, что я опишу, покажется современным гуру этого средства детским лепетом, но это меня не останавливает.
Сегодня расскажу вот о чем. Есть у меня программка, которая что-то там делает :) Хотя нет, для полноты картины, напишу о ней несколько слов.
Программа написана с использованием Delphi XE3 (старье, да?), но используемые методы программирования и технологии более подошли бы еще более ранним версиям среды разработки. Например, используется VCL, а не FireMonkey.
Прога сидит в трее и по различным горячим комбинациям клавиш выполняет определенные действия. Большинство этих действий не нуждаются в пользовательском интерфейсе, но есть комбинация горячих клавиш, которая приводит к появлению на экране небольшой формочки.
Я думаю, многие сталкивались с такой проблемой, когда окошко показывается не поверх остальных окон, открытых в Windows, а предательски прячется под каким-нибудь из них. Особенно часто это происходит, когда открываемое окно не является главной формой приложения, а является так называемым
Наверное, я смалодушничал - взял и просто присвоил этой форме стиль
Дело в том, что в окошке этом пользователь может произвести некоторые ошибочные действия, о чем программа должна его уведомить. Как? Как обычно: выдав на экран диалоговое окно с описанием проблемы. Для выдачи таких сообщений я, обычно, использую метод
А ведь такая безобидная строчка кода:
Конечно, такой результат не мог меня удовлетворить и я отправился курить мануалы. И уже первые затяжки стали приносить результат!!! В общем, справка Delphi вывела на метод
Но, в последнее время, я все больше сижу на Java, и к Delphi-разработкам возвращаюсь все реже и реже. К тому же, мое активное программирование на этом замечательном средстве застряло на уровне версий Delphi 5, Delphi 6, Delphi 7. Нет, я пробовал что-то писать на новых версиях, например, Delphi XE 3, даже пробовал FireMonkey, но опыт этот был весьма поверхностным и непродолжительным.
Именно поэтому я решил, что буду писать про то, что делаю в Delphi. Вполне возможно, многое из того, что я опишу, покажется современным гуру этого средства детским лепетом, но это меня не останавливает.
Сегодня расскажу вот о чем. Есть у меня программка, которая что-то там делает :) Хотя нет, для полноты картины, напишу о ней несколько слов.
Программа написана с использованием Delphi XE3 (старье, да?), но используемые методы программирования и технологии более подошли бы еще более ранним версиям среды разработки. Например, используется VCL, а не FireMonkey.
Прога сидит в трее и по различным горячим комбинациям клавиш выполняет определенные действия. Большинство этих действий не нуждаются в пользовательском интерфейсе, но есть комбинация горячих клавиш, которая приводит к появлению на экране небольшой формочки.
Я думаю, многие сталкивались с такой проблемой, когда окошко показывается не поверх остальных окон, открытых в Windows, а предательски прячется под каким-нибудь из них. Особенно часто это происходит, когда открываемое окно не является главной формой приложения, а является так называемым
toolWindow
, да и само приложение представлено только иконкой в трее.Наверное, я смалодушничал - взял и просто присвоил этой форме стиль
fsStayOnTop
(ну не форме, конечно, а ее свойству FormStyle
). После этого форма стала стабильно появляться поверх всех открытых окон, что не могло не радовать. Но, как часто бывает, такое решение возымело не только положительный, но и отрицательный эффект.Дело в том, что в окошке этом пользователь может произвести некоторые ошибочные действия, о чем программа должна его уведомить. Как? Как обычно: выдав на экран диалоговое окно с описанием проблемы. Для выдачи таких сообщений я, обычно, использую метод
MessageDlg
. И этот раз не стал исключением. Вот как вы думаете, где появилось окно сообщения? Я имею в виду, относительно той самой формочки, которая отображается поверх всех окон? Правильно, окно с сообщением отобразилось под формой. Вот такая вот картинка:А ведь такая безобидная строчка кода:
MessageDlg(Format(rsCoversionError, [Id]), mtError, [mbClose], 0);
Конечно, такой результат не мог меня удовлетворить и я отправился курить мануалы. И уже первые затяжки стали приносить результат!!! В общем, справка Delphi вывела на метод
MessageBox
. На самом деле, методов два: один объявлен в Vcl.Forms.TApplication
, другой - в Winapi.Windows
. Нам нужен тот, который описан в Winapi.Windows
(то есть, второй), потому что первый (который объявлен в Vcl.Forms.TApplication
) является оберткой и как-то сам там все пытается организовать. А нам нужен полный контроль.Итак, нужный нам
MessageBox
- обычный метод Win32 API. Он примечателен тем, что первым параметром у него идет дескриптор родительского окна, и, установив его в дескриптор моей формы:MessageBox(StayOnTopForm.Handle, PWideChar(Format(rsCoversionError, [Id])), 'Error', MB_OK);
я получил желаемый результат:
Однако, этот результат меня тоже не вполне удовлетворил. Дело в том, что я не зря написал, что предпочитаю для выдачи сообщений использовать метод
MessageDlg
. Ну нравится мне больше внешний вид этого окна, чем того, которое появляется в результате вызова MessageBox
. И хотя их и можно сделать абсолютно похожими, но, в случае с MessageBox
, придется немного потанцевать с бубном. MessageDlg
все-таки более user friendly, на мой взгляд.И я снова отправился курить мануалы. Сегодня они реально доставляли!!! Довольно быстро нашелся еще один метод:
CreateMessageDialog
, который создает и возвращает форму сообщения, не показывая ее. Получив эту форму, можно попытаться поколдовать над ней для получения нужного эффекта. А нам нужно, чтобы сообщение появилось над формой, а не под ней.И тут руководство (не в смысле "начальство", а в смысле "документ") не подкачало. Вернее, на высоте оказался Delphi, ну и online справка, конечно. У формы обнаружилась пара свойств:
PopupMode
и PopupParent
. Изучение документации по обоим свойствам привело меня к следующим выводам: свойство PopupMode
можно вообще не трогать, потому что сообщение все равно показывать при помощи метода ShowModal
сконструированной формы, а этот метод принудительно выставит значение свойства в pmAuto
. А вот в PopupParent
, пожалуй, стоит записать мою формочку, чтобы сообщение появилось поверх нее. Я так и сделал: dlg := CreateMessageDialog(Format(rsCoversionError, [Id]),
mtError, [mbClose]);
dlg.PopupParent := StayOnTopForm;
dlg.ShowModal;
FreeAndNil(dlg);
И результат не заставил себя долго ждать:
Ну и напоследок немного дегтя в бочку... В какой-то момент я подумал, что существует еще один вариант решения моей задачки. Пока я лазил по документации, я набрел на такие методы класса
TApplication
, как NormalizeAllTopMosts
, NormalizeTopMosts
и RestoreTopMosts
. С их помощью можно написать примерно такой код: Application.NormalizeAllTopMosts;
MessageDlg(Format(rsCoversionError, [Id]), mtError, [mbClose], 0);
Application.RestoreTopMosts;
после чего, судя по документации, сообщение об ошибке должно появиться над формой. Но не тут-то было. Практика - упрямая вещь, о которую разбиваются многие красивые теории. Запустив приложение и создав предпосылки для появления ошибки, я увидел сообщение о ней под формой. Дальнейшее ковыряние выявило, что для формочек со стилем границ (свойство
BorderStyle
) bsToolWindow
этот метод не работает. Но, например для стиля bsSizeable
- все пучком.Какой же урок я вынес из этого случая? Delphi изменился. Даже в части так хорошо знакомого мне раньше VCL. Больше методов, больше свойств, больше возможностей. Это хорошо. Надо учить. Это тоже хорошо!