- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
О чём не пишут в книгах по Delphi - А. Григорьев
Шрифт:
Интервал:
Закладка:
GoToForeground;
// Пока есть команды, читаем их и выполняем
Letter := ReadStringFromMailslot;
while Letter <> '' do
begin
// Анализируем и выполняем команду.
// Команда "s" не требует никаких действий, кроме перевода
// приложения на передний план, поэтому здесь мы ее не учитываем
case Letter[1] of
'e': OpenFile(Copy(Letter, 2, MaxInt), False);
'v': OpenFile(Copy(Letter, 2, MaxInt), True);
end;
Letter := ReadStringFronMailslot;
end;
end;
// Чтение очередного сообщения из почтового ящика
function TDksViewMainForm.ReadStringFromMailslot: string;
var
MessageSize: DWORD;
begin
// Получаем размер следующего сообщения в почтовом ящике
GetMailslotInfo(ServerMailslotHandle, nil, MessageSize, nil, nil);
// Если сообщения нет, возвращаем пустую строку
if MessageSize = MAILSLOT_NO_MESSAGE then
begin
Result := '';
Exit;
end;
// Выделяем для сообщения буфер и читаем его в этот буфер
SetLength(Result, MessageSize);
ReadFile(ServerMailslotHandle, Result[1], MessageSize, MessageSize, nil);
end;
ПримечаниеТак как события являются именованными объектами, второй экземпляр приложения мог бы обнаруживать наличие первого не по почтовому ящику, а по событию. Более того, если бы нам требовалось не передавать данные первому экземпляру, а только активизировать его, можно было бы вообще обойтись одним только событием.
1.3.2.4. Перевод приложения на передний план
Первая копия приложения, получив команду от другой копии, должна вывести себя на передний план. Казалось бы, все просто: с помощью функции SetForegroundWindow мы можем вывести туда любое окно. Однако так было только до Windows 95 и NT 4. В более поздних версиях введены ограничения, и теперь программа не может вывести себя на передний план по собственному усмотрению. Функция SetForegroundWindow просто заставит мигать соответствующую кнопку на панели задач.
Тем не менее, если программа свернута, команда Application.Restore не только восстанавливает окно, но и выводит его на передний план, что нам и требуется. Ну а если программа не свернута, то "выливаем из чайника воду и тем самым сводим задачу к предыдущей": сначала сворачиваем приложение с помощью Application.Minimize, а потом разворачиваем его. Цели мы добились — главное окно на переднем плане.
Дело портит только то, что изменение состояния окна сопровождается анимацией: видно, как главное окно сначала сворачивается, а потом разворачивается. Чтобы убрать этот неприятный эффект, можно на время сворачивания/разворачивания окна запретить анимацию, а потом восстановить ее. С учетом этого метод GoToForeground выглядит так, как показано в листинге 1.50.
Листинг 1.50. Перевод приложения на передний план// Перевод приложения на передний план
procedure TDKSViewMainForm.GoToForeground;
var
Info: TAnimationInfo;
Animation: Boolean;
begin
// Проверяем, включена ли анимация для окон
Info.cbSize := SizeOf(TAnimationInfo);
Animation := SystemParametersInfo(SPI_GETANIMATION,
SizeOf(Info), @Info, 0 and (Info.iMinAnimate <> 0);
// если включена, отключаем, чтобы не было ненужного мерцания
if Animation then
begin
Info.iMinAnimate := 0;
SysteParametersInfo(SPI_SETANIMATION, SizeOf(Info), @Info, 0);
end;
// Если приложение не минимизировано, минимизируем
if not IsIconic(Application.Handle) then Application.Minimize;
// Восстанавливаем приложение. При этом оно автоматически выводится
// на передний план
Application.Restorе;
// Если анимация окон была включена, снова включаем ее
if Animation than
begin
Info.iMinAnimate := 1;
SystemParametersInfo(SPI_SETANIMATION, SizeOf(Info), @Info, 0);
end;
end;
Теперь у нас сделано все, что нужно: приложение умеет ассоциировать расширение с двумя командами; проверять, не ассоциировано ли расширение с другим приложением, и если да, предлагать пользователю установить эту ассоциацию; запрещать запуск второй копии приложения, переводя вместо этого на передний план первую копию; передавать параметры второй копии первой, чтобы она могла выполнить требуемые действия.
1.3.3. Обобщающий пример 3 — "Дырявое" окно
В этом примере мы создадим "дырявое" окно. Те, кто уже знаком с функцией SetWindowRgn, знает, что сделать "дырку" в окне или придать ему какую-либо другую необычную форму не так уж и сложно. Но мы здесь пойдем дальше: у дырки в нашем окне будет рамка, и пользователь сможет изменять размеры и положение дырки так же, как он может изменять положение и размеры окна. Как это выглядит, показано на рис. 1.14.
Рассмотрим те средства, которые нам понадобятся для реализации этого.
1.3.3.1. Сообщение WM_NCHCHITTEST
Каждое окно в Windows делится на две области: клиентскую и не клиентскую. Клиентской называется та область, в которой отображается содержимое окна. Неклиентская область — это различные служебные области окна: рамка, заголовок, полосы прокрутки, главное меню и т.п. Положение клиентской части окна относительно неклиентской определяет само окно при обработке сообщения WM_NCCALCRECT. Многие окна (особенно различные элементы управления) вообще не имеют неклиентской части.
Некоторые сообщения для клиентской части окна имеют аналоги для неклиентской. Например, перерисовка клиентской области осуществляется с помощью сообщения WM_PAINT, а неклиентской — WM_NCPAINT. Нажатие левой кнопки мыши над клиентской частью окна генерирует сообщение WM_LBUTTONDOWN, а над неклиентской — WM_NCLBUTTONDOWN и т.п. Неклиентская область неоднородна: в нее входит заголовок, кнопки сокрытия, разворачивания и закрытия окна, иконка системного меню, главное меню, вертикальная и горизонтальная полосы прокрутки и рамка. Рамка тоже неоднородна — она имеет левую, правую, верхнюю и нижнюю границы и четыре угла. Сообщение WM_NCCALCSIZE позволяет выяснить, какая область окна является неклиентской, но не позволяет узнать, где какая часть неклиентской области находится. Эта задача решается с помощью другого сообщения — WM_NCHITTEST. В качестве входных параметров WM_NCHITTEST получает координаты точки, а результат кодирует, к какой части окна относится эта точка (например, HTCLIENT означает, что точка принадлежит к клиентской части окна, HTCAPTION — к заголовку, HTLEFT — к левой границе рамки, меняющей размер, и т.п.).
Рис. 1.14. "Дырявое" окно
При любых событиях от мыши система начинает с того, что посылает окну сообщение WM_NCHITTEST с координатами положения мыши. Получив результат, система решает, что делать дальше. В частности, при нажатии левой кнопки мыши окну посылается WM_NCHITTEST. Затем, если результатом был HTCLIENT, посылается сообщение WM_LBUTTONDOWN, в противном случае — WM_NCLBUTTONDOWN. При каждом перемещении мыши окно также получает WM_NCHITTEST — это позволяет системе постоянно отслеживать, над какой частью окна находится курсор, при необходимости меняя его вид (как, например, при прохождении курсора над рамкой).
Что будет, если подменить обработчик WM_NCHITTEST? Например, так, чтобы при попадании точки в клиентскую часть окна он возвращал не HTCLIENT, а HTCAPTION? Это приведет к тому, что любые события от мыши над клиентской областью будут восприниматься так же, как над заголовком. Например, можно будет взять окно за клиентскую часть и переместить его, а двойной щелчок на ней приведет к разворачиванию окна. Однако это полностью блокирует нормальную реакцию на мышь, потому что вместо клиентских "мышиных" сообщений окно будет получать неклиентские.
С практической точки зрения окно, которое можно таскать за любую точку, обычно не очень интересно (особенно это касается приложений, разработанных с помощью VCL: на мышь перестанет правильно реагировать не только само окно, но и расположенные на нем неоконные элементы управления). Однако обработчик WM_NCHITTEST можно сделать более интеллектуальным и получить довольно интересные эффекты. Например, положив на форму панель и переопределив у панели обработчик WM_NCHITTEST таким образом, чтобы при нахождении мыши около границ панели возвращался результат, соответствующий различным частям рамки с изменяемым размером, можно получить панель, размеры которой пользователь программы сможет изменять: система будет реагировать на эту область панели как на обычную рамку, которую можно взять и потянуть. (Пример такой панели можно увидеть в статье "Компонент, который меняет свои размеры в режиме run-time аналогично тому, как это происходит в design-time" http://www.delphikingdom.com/asp/viewitem.asp?catalogid=22.) Фантазия может подсказать и многие другие способы получения интересных эффектов с помощью WM_NCHITTEST.

