Blog. Just Blog

Быстрый поиск

Введите фрагмент названия статьи для поиска

Анимация окон с помощью функции AnimateWindow

16.09.2023 | Категория: Образ мышления: Assembler | Автор: ManHunter
Когда-то давно я показывал, как можно реализовать анимацию окна вручную. Сейчас покажу, как подобная анимация делается штатными функциями Windows, а точнее одной единственной функцией AnimateWindow. Но сперва некоторое количество констант, которые используются в программе, но про которые не знает FASM.
  1. AW_HOR_POSITIVE = 0x00000001
  2. AW_HOR_NEGATIVE = 0x00000002
  3. AW_VER_POSITIVE = 0x00000004
  4. AW_VER_NEGATIVE = 0x00000008
  5. AW_CENTER       = 0x00000010
  6. AW_HIDE         = 0x00010000
  7. AW_ACTIVATE     = 0x00020000
  8. AW_SLIDE        = 0x00040000
  9. AW_BLEND        = 0x00080000
Первым параметром функции указывается продолжительность эффекта анимации, вторым - флаг или комбинация флагов, описывающих этот эффект. Флаги AW_HOR_POSITIVE, AW_HOR_NEGATIVE, AW_VER_POSITIVE и AW_VER_NEGATIVE отвечают, соответственно, за горизонтальное и вертикальное разворачивание окна. Если скомбинировать флаг одного из горизонтальных направлений с флагом одного из вертикальных направлений, то окно будет раскрываться по диагонали. А если к одному из этих флагов добавить AW_SLIDE, то окно будет как бы выезжать из указанного направления. AW_BLEND отвечает за эффект прозрачности, что-то подобное я также реализовал вручную, только тут не надо возиться с WS_EX_LAYERED и SetLayeredWindowAttributes, всю грязную работу система берет на себя. При использовании флага AW_CENTER окно будет разворачиваться из своей центральной точки. Для того, чтобы эффект применялся не для открытия, а для сворачивания окна, к эффектам надо добавлять флаг AW_HIDE. На практике это выглядит примерно так, вот фрагмент функции обработчика диалогового окна:
  1.         cmp     [msg],WM_INITDIALOG
  2.         je      wminitdialog
  3.         cmp     [msg],WM_CLOSE
  4.         je      wmclose
  5.         ...
  6.  
  7. wminitdialog:
  8.         ; Плавно развернуть окно из центра
  9.         invoke  AnimateWindow,[hwnddlg],300,AW_CENTER+AW_ACTIVATE
  10.         ...
  11. wmclose:
  12.         ; Плавно потушить окно при закрытии
  13.         invoke  AnimateWindow,[hwnddlg],300,AW_BLEND+AW_HIDE
  14.         ...
Не обошлось и без особенностей. Обычные окна с заголовком при применении к ним функции AnimateWindow дают необычный эффект: появляется или исчезает только их внутреннее содержимое, а рамка остается неизменной. Поэтому функцию желательно применять к беззаголовочным окнам типа сплэш-окон, окнам всплывающих уведомлений, всяким патчам-кейгенам и тому подобным.

Читать статью целиком »
Просмотров: 681 | Комментариев: 0

Установка точного размера клиентской области окна

19.06.2022 | Категория: Образ мышления: Assembler | Автор: ManHunter
Очередная тривиальная задача с нетривиальным решением и очередной пламенный привет разработчикам Windows. Начнем с задачи. Надо изменить размер окна таким образом, чтобы его клиентская область, то есть внутреннее содержимое без учета заголовка, рамок и полос прокрутки, стала четко заданной ширины и высоты. Создатели Windows, безусловно, позаботились о программистах, для решения этой задачи есть как минимум две функции - SetWindowPos и MoveWindow, все хорошо и замечательно, но... Как метко подметили в одном телесериале, все, что сказано до слова "но" - чушь собачья. Эти функции действительно выполняют свое предназначение, меняют размер окна, только применяют переданные им значения к внешней границе окна. При этом не учитываются ни визуальные темы, ни стили окна, ни наличие полос прокрутки, ни толщина рамки, короче, решения поставленной задачи "в лоб" дадут гарантированно неправильный результат.


Размеры областей окна

К счастью, в Windows имеется вспомогательная функция AdjustWindowRectEx, которая используется как раз для подобных ситуаций. Он вычисляет фактические размеры окна, которые соответствуют заданным размерам его клиентской области. И вот здесь как раз учитываются стили, в том числе и расширенные, наличие у окна строки меню и установленная визуальная тема, но... Да-да, очередное "но". При расчете размеров никак не учитывается наличие в окне полос вертикальной и/или горизонтальной прокрутки. Они могут входить в размер клиентской области, а могут и не входить, в зависимости от задачи.

Читать статью целиком »
Просмотров: 885 | Комментариев: 2

Как сделать ProgressBar с надписью

21.04.2022 | Категория: Образ мышления: Assembler | Автор: ManHunter
Не перестаю удивляться, почему разработчики Microsoft с самого начала не реализовали "из коробки" очевиднейшие решения. Например, есть хороший и удобный элемент диалоговых окон - Progress Bar. Легко реализовать, удобно управлять, но по какой-то причине нет никаких инструментов, чтобы системными средствами наложить на индикатор прогресса какую-нибудь надпись типа "42% завершено". Градиентный ProgressBar мы уже делали, настала очередь реализовать ProgressBar с надписью.


ProgressBar с надписью

Использовать стандартный элемент msctls_progress32 не будем, вместо него возьмем элемент EDIT или STATIC, как и в предыдущем примере. Полоса индикатора и надпись реализуется путем рисования прямо на канве элемента диалогового окна, которое выделено под индикатор.

Основная загвоздка заключается в том, что при отрисовке текста поверх индикатора прогресса, надо учитывать разницу в цвете фона и полосы выполненной части. Посмотрите на скриншоте, чтобы стало понятно, о чем идет речь. В некоторых случаях при определенной комбинации цветов можно использовать единый цвет, но это не самое хорошее решение. Так что сделаем все правильно.

Читать статью целиком »
Просмотров: 1094 | Комментариев: 1

Обработка Drag'n'Drop в разные поля ввода

28.03.2022 | Категория: Образ мышления: Assembler | Автор: ManHunter
В статье об обработке перетаскивания файлов я упомянул про раздельную обработку перетаскивания файлов в разные поля. В частности про вариант с субклассированием. Теперь расскажу, как это делается. Предположим, что у нас на форме есть три поля для выбора файла, причем каждое должно работать независимо.
  1.         ; Разрешить каждому полю принимать файлы
  2.         invoke  GetDlgItem,[hwnddlg],ID_FILE1
  3.         mov     ebx,eax
  4.         invoke  DragAcceptFiles,ebx,TRUE
  5.         ; Установить наш собственный обработчик
  6.         invoke  SetWindowLong,ebx,GWL_WNDPROC,EditWindowProc
  7.         ; Сохранить хэндл предыдущего обработчика
  8.         invoke  SetWindowLong,ebx,GWL_USERDATA,eax
  9.  
  10.         invoke  GetDlgItem,[hwnddlg],ID_FILE2
  11.         mov     ebx,eax
  12.         invoke  DragAcceptFiles,ebx,TRUE
  13.         ; Установить наш собственный обработчик
  14.         invoke  SetWindowLong,ebx,GWL_WNDPROC,EditWindowProc
  15.         ; Сохранить хэндл предыдущего обработчика
  16.         invoke  SetWindowLong,ebx,GWL_USERDATA,eax
  17.  
  18.         invoke  GetDlgItem,[hwnddlg],ID_FILE3
  19.         mov     ebx,eax
  20.         invoke  DragAcceptFiles,ebx,TRUE
  21.         ; Установить наш собственный обработчик
  22.         invoke  SetWindowLong,ebx,GWL_WNDPROC,EditWindowProc
  23.         ; Сохранить хэндл предыдущего обработчика
  24.         invoke  SetWindowLong,ebx,GWL_USERDATA,eax
На этапе инициализации окна надо при помощи функции DragAcceptFiles разрешить каждому полю ввода принимать файлы, а затем субклассировать их, чтобы обрабатывать сам момент броска.

Читать статью целиком »
Просмотров: 648 | Комментариев: 3

MessageBox с чекбоксом "Больше не показывать"

04.10.2021 | Категория: Образ мышления: Assembler | Автор: ManHunter
Еще одна хорошая практика взаимодействия с пользователем - окно сообщения с чекбоксом "Больше не показывать это диалоговое окно". Таким образом и приложение выполняет свою работу по уведомлению пользователя о каком-то периодическом событии, и пользователь сам решает, желает ли он наблюдать это уведомление в дальнейшем. Делается это при помощи стандартной функции SHMessageBoxCheck. По параметрам эта функция очень похожа на вызов MessageBox, но поддерживает ограниченное количество стилей и не весь набор кнопок, а также обязательно требует текстовую строку с уникальным идентификатором этого сообщения. В остальном все сводится к единственному вызову, типа такого:
  1. ; Уникальный идентификатор окна сообщения
  2. szUID   db '{D9108BA3-9A61-4398-BFBC-B02102C77E8A}',0
  3.         ...
  4.         ; Значение по умолчанию
  5.         DEFAULT_RESULT = 0
  6.         ; Вывести окно сообщения с галочкой "Больше не показывать"
  7.         invoke  SHMessageBoxCheck,HWND_DESKTOP,\
  8.                 szMess,szTitle,MB_YESNO+MB_ICONEXCLAMATION,\
  9.                 DEFAULT_RESULT,szUID
  10.         ; EAX = выбранная кнопка или DEFAULT_RESULT
Получившееся окно очень похоже на обычное окно сообщения, только внизу к нему добавляется локализованная строка "Больше не показывать это диалоговое окно". Если пользователь поставит эту галочку и сделает какой-либо выбор, в реестре в ключе HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\DontShowMeThisDialogAgain добавится новый параметр с именем уникального идентификатора, который был использован при создании окна сообщения, и строковым значением "NO". При очередном вызове функции SHMessageBoxCheck с таким же уникальным идентификатором, система проверяет наличие и значение этого параметра. Если параметр в реестре найден, то окно сообщения появляться не будет, а приложению сразу же вернется используемое при вызове дефолтное значение. Кстати, хотя такое окно визуально напоминает окно, создаваемое функцией MessageBox и ее аналогами, по своей структуре оно гораздо сложнее. И если у вас вдруг возникнет желание как-нибудь его кастомизировать, то сделать это будет не так просто. По крайней мере на установку хука WH_CBT оно точно не реагирует.

Читать статью целиком »
Просмотров: 1047 | Комментариев: 6

prev 01 02 03 04 05 06 07 08 09 ... 14
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.09 сек. / MySQL: 3 (0.0052 сек.) / Память: 4.5 Mb
Наверх