Blog. Just Blog

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

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

Окна нестандартной формы на Ассемблере. Часть 2

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

Итак, берем нужную картинку и накладываем ее на какой-нибудь однородный цветной фон, причем цвет фона не должен присутствовать на основной картинке. Можно добавить надпись, но главное чтобы границы всех элементов композиции были четкими и не сливались с фоном. Получится примерно следующее:


Картинка для окна

Картинку надо сохранить в формате BMP, с глубиной цвета 8 бит. Это очень важно, так как в этом случае количество цветов в палитре не превышает 256, а каждая точка описывается ровно одним байтом. Поскольку картинка будет накладываться на диалоговое окно, то и хранить ее надо будет в ресурсах. Тут есть важная особенность: в ресурсах картинка хранится без 14-байтного заголовка BITMAPFILEHEADER и все смещения считаются сразу же от начала блока BITMAPINFOHEADER.

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

Окна нестандартной формы на Ассемблере. Часть 1

22.06.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Фигурная резьба по деревянным окнам - старинное народное творчество. А в нашем 21-м веке народным творчеством будет резьба по окнам Windows. При умелом использовании это станет стильным украшением для ваших приложений, добавив им привлекательности.

Форма окна определяется особыми структурами, называемыми регионами. Они могут быть прямоугольной формы, закругленной, эллиптической и многоугольной. Весь принцип работы с регионами сводится к следующему. Сперва создается главный регион, равный по размерам основному диалоговому окну, затем создаются дополнительные регионы нужного размера и накладываются на него с нужной битовой маской. Режимы наложения определяют будет ли новый регион удален из основного, или же наоборот добавлен. Размер главного региона лучше всего рассчитывать из результатов функции GetClientRect, вызванной с хэндлом нужного диалогового окна. Наложение регионов выполняется функцией CombineRgn, возможные режимы наложения смотрите в официальной документации. Все действия выполняются на этапе инициализации окна по событию WM_INITDIALOG.
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. hRMain  dd ?   ; Хэндл главного региона окна
  5. coord   RECT   ; Координаты окна для вычисления размера региона
  6.         ...
В сегменте данных инициализируется хэндл главного региона окна и структура RECT с координатами диалогового окна, по которым будет рассчитываться размер главного региона.

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

Всплывающее окно на Ассемблере

26.05.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Всплывающее окно - удобный способ информировать о том, что ваша программа выполнила какое-то действие, не требующее немедленного вмешательства пользователя, но достаточно важное, чтобы он об этом узнал. Это может быть сообщение о завершении закачки файла, получении нового письма, завершении длительных вычислений и т.п. Красивый эффект получается, когда информационное окно плавно выезжает из-под таскбара. Простого перемещения окна тут будет недостаточно, так как придется учитывать положение таскбара и всяких других панелей, которые резервируют под себя часть рабочего стола. Поэтому надо сперва получить размер видимой области экрана с учетом различных панелей инструментов и размеры самого всплывающего окна. Затем окно перемещается по одному пикселу в нужном направлении с учетом положения панелей, а размер его видимой части увеличивается на один пиксел в противоположную сторону. Это делается при помощи функции MoveWindow. Лучше всего сам эффект всплытия реализовать на стадии инициализации окна по сообщению WM_INITDIALOG, но в этом случае придется принудительно показывать окно функцией ShowWindow и обновлять его содержимое функцией UpdateWindow после каждого сдвига. Рекомендуются стили окна без заголовка и поверх всех окон, как сделано в прилагаемом примере. Атрибут прозрачности для всплывающих окон лучше не использовать, так как при анимации появляются заметные искажения.
  1. ; Сегмент данных
  2. section '.data' data readable writeable
  3.  
  4. coord   RECT    ; Размеры окна
  5. screen  RECT    ; Размеры экрана
  6.  
  7. ; Сегмент кода
  8. section '.code' code readable executable
  9.         ...
  10.         ; Обработчик сообщения WM_INITDIALOG
  11. wminitdialog:
  12.         ; Получить размер рабочей области экрана
  13.         invoke  SystemParametersInfo,SPI_GETWORKAREA,NULL,screen,FALSE
  14.  
  15.         ; Получить размер окна
  16.         invoke  GetClientRect,[hwnddlg],coord
  17.  
  18.         ; Вычислить отступ от правой границы экрана
  19.         mov     eax,[screen.right]
  20.         sub     eax,[coord.right]
  21.         dec     eax
  22.         mov     [screen.right],eax
  23.  
  24.         ; Высота окна
  25.         mov     ecx,[coord.bottom]
  26.         ; Цикл всплытия окна
  27. @@:
  28.         ; Сохранить значение счетчика
  29.         push    ecx
  30.  
  31.         ; Заполняем стек для MoveWindow
  32.         push    TRUE
  33.         mov     eax,[coord.bottom]
  34.         sub     eax,ecx
  35.         push    eax
  36.         push    [coord.right]
  37.         mov     ecx,[screen.bottom]
  38.         sub     ecx,eax
  39.         push    ecx
  40.         invoke  MoveWindow,[hwnddlg],[screen.right]
  41.  
  42.         ; Так как сейчас только инициализация, то придется принудительно
  43.         ; показать окно и обновить его содержимое
  44.         invoke  ShowWindow,[hwnddlg], SW_SHOW
  45.         invoke  UpdateWindow,[hwnddlg]
  46.  
  47.         ; Небольшая пауза
  48.         invoke  Sleep,2
  49.  
  50.         ; Восстановить счетчик
  51.         pop     ecx
  52.         loop    @b
  53.         ...
После полного появления окна нужно решить, каким образом будет выполняться его дальнейшая обработка. Окно можно убрать по таймеру через несколько секунд, скрыть по клику мышкой на нем или подождать другого события, например, нажатия на какую-нибудь кнопку. В любом случае окно можно или просто закрыть, или убрать его с таким же эффектом, только направление движения будет противоположным. Код плавного скрытия всплывающего окна приведен ниже. Подразумевается, что все используемые структуры с размерами после его открытия остались неизменными.

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

Магнитное (липкое) окно на Ассемблере

12.05.2009 | Категория: Образ мышления: Assembler | Автор: ManHunter
Еще один интересный трюк при работе с окнами - так называемые "липкие" или "магнитные" окна, которые прилипают к границам экрана при перемещении. Это реализуется достаточно просто, но выглядит очень эффектно. Для перехвата перемещения окна надо обрабатывать сообщение WM_MOVING. В параметре lParam передается адрес структуры RECT, которая содержит значения конечных координат окна после отпускания курсора мыши. Чтобы при изменении координат окна не возникало неприятного эффекта моргания, их надо менять сразу же в передаваемой структуре. Обработчик WM_MOVING выглядит следующим образом:
  1. ; Обработчик сообщения WM_MOVING
  2.  
  3. MAX_GRID = 20   ; Размер магнитной сетки
  4.  
  5.         ; Получить размер рабочей области экрана
  6.         invoke  SystemParametersInfo,SPI_GETWORKAREA,NULL,coord,FALSE
  7.  
  8.         ; В регистре EDI указатель на структуру координат окна
  9.         mov     edi,[lparam]
  10.  
  11.         ; Проверить положение левой границы окна
  12.         mov     edx,[edi+RECT.left]
  13.         sub     edx,[coord.left]
  14.         mov     eax,edx
  15.         jns     @f
  16.         neg     edx
  17. @@:
  18.         cmp     edx,MAX_GRID
  19.         ja      @f
  20.         sub     [edi+RECT.right],eax
  21.         sub     [edi+RECT.left],eax
  22. @@:
  23.         ; Проверить положение правой границы окна
  24.         mov     edx,[edi+RECT.right]
  25.         sub     edx,[coord.right]
  26.         mov     eax,edx
  27.         jns     @f
  28.         neg     edx
  29. @@:
  30.         cmp     edx,MAX_GRID
  31.         ja      @f
  32.         sub     [edi+RECT.right],eax
  33.         sub     [edi+RECT.left],eax
  34. @@:
  35.         ; Проверить положение верхней границы окна
  36.         mov     edx,[edi+RECT.top]
  37.         sub     edx,[coord.top]
  38.         mov     eax,edx
  39.         jns     @f
  40.         neg     edx
  41. @@:
  42.         cmp     edx,MAX_GRID
  43.         ja      @f
  44.         sub     [edi+RECT.top],eax
  45.         sub     [edi+RECT.bottom],eax
  46. @@:
  47.         ; Проверить положение нижней границы окна
  48.         mov     edx,[edi+RECT.bottom]
  49.         sub     edx,[coord.bottom]
  50.         mov     eax,edx
  51.         jns     @f
  52.         neg     edx
  53. @@:
  54.         cmp     edx,MAX_GRID
  55.         ja      @f
  56.         sub     [edi+RECT.top],eax
  57.         sub     [edi+RECT.bottom],eax
  58. @@:
  59.         mov     eax,TRUE
  60.         jmp     finish
Размеры области экрана для вычисления новых координат окна с учетом таскбара и других видимых панелей можно получить вызовом функции SystemParametersInfo с параметром SPI_GETWORKAREA. В приведенном примере размер магнитной сетки (минимальное расстояние до границы экрана, с которого начинает действовать сила притяжения), меняется в константе MAX_GRID. По умолчанию значение равно 20 пикселов.

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

Обработка перетаскивания файлов (Drag'n'Drop)

10.12.2008 | Категория: Образ мышления: Assembler | Автор: ManHunter
Если в вашем приложении используется обработка файлов, то кроме открытия через стандартные диалоги выбора файла и каталога, можно получать их из Проводника Windows перетаскиванием. Обработка перетаскивания файлов выполняется в два этапа. При инициализации диалогового окна приложения должна вызываться функция DragAcceptFiles. Параметр функции TRUE разрешает принятие файлов окном, а FALSE его запрещает, так что прием файлов можно регулировать динамически. Непосредственно прием файлов окном выполняется функцией DragQueryFile.
  1. ; Сегмент кода
  2. section '.code' code readable executable
  3.         ... 
  4. ; Процедура обработчика окна
  5. proc DialogProc hwnddlg,msg,wparam,lparam 
  6.         ...
  7.         ; Инициализация окна
  8.         cmp     [msg],WM_INITDIALOG
  9.         je      wminitdialog
  10.         ; Обработка перетаскивания файлов
  11.         cmp     [msg],WM_DROPFILES
  12.         je      wmdropfiles
  13.         ...
  14. wminitdialog:
  15.         ; Разрешить окну принимать файлы
  16.         invoke  DragAcceptFiles,[hwnddlg],TRUE
  17.         jmp     processed
  18.  
  19. wmdropfiles:
  20.         ; Обработка полученных файлов. Функция DragQueryFile возвращает имя
  21.         ; файла с указанным индексом (нумерация индексов начинается с нуля).
  22.         ; Для получения общего количества переданных файлов ее надо вызвать с
  23.         ; индексом равным 0FFFFFFFFh
  24.         invoke  DragQueryFile,[wparam],0FFFFFFFFh,NULL,NULL
  25.         ; В регистре EAX количество переданных файлов
  26.  
  27.         ; Перебрать по очереди все переданные окну файлы
  28.         xor     ecx,ecx
  29. process_file:
  30.         push    ecx eax
  31.         ; Получить имя файла или каталога в буфер fname
  32.         invoke  DragQueryFile,[wparam],ecx,fname,100h
  33.         ...
  34.         ; Тут будет обработчик переданных файлов и каталогов
  35.         ...
  36.         pop     eax ecx
  37.         inc     ecx
  38.         cmp     ecx,eax
  39.         jne     process_file
  40.  
  41.         ; Освободить дескриптор операции
  42.         invoke  DragFinish,[wparam]
  43.         ...
Если требуется получить только один файл, то запрашивать общее количество файлов не обязательно, достаточно вызвать DragQueryFile с нулевым индексом файла. Если в интерфейсе предусмотрено несколько полей для приема файлов, то может возникнуть необходимость определять, в какое именно поле выполнятся сброс файла. Делать это можно, например, через субклассирование, но есть способ проще. При помощи функции DragQueryPoint можно определять координаты точки внутри окна, на которых был выполнен бросок файла. Сравнив их с координатами полей ввода, легко определить, какому из них предназначался файл.

После выполнения всех необходимых действий с файлом, надо освободить память, выделенную под файлы, при помощи функции DragFinish.

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

Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2024
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.06 сек. / MySQL: 3 (0.0038 сек.) / Память: 4.5 Mb
Наверх