Пятница, 18.07.2025, 16:26 Приветствую Вас Гость

On-line: Книги, учебники, статьи

Главная | Регистрация | Вход | RSS

Глава 4. Примеры программ использующих ресурсы(3)

Комментарий к программе на Рис. 2.4.2.

1. Самое главное: разберитесь с тем, как мы определяем, когда первое окно редактирования теряет, когда приобретает фокус. В начале определяется, что сообщение пришло от окна редактирования с идентификатором 1, а затем - какое сообщение пришло: EN_SETFOCUS или EN_KILLFOCUS. В первом случае мы устанавливаем горячие клавиши, а во втором снимаем горячие клавиши.

2. В области данных задаем таблицу горячих клавиш. Функция RegisterHotKey имеет следующие параметры:

  • 1-й параметр - идентификатор окна.
  • 2-й параметр - идентификатор горячей клавиши.
  • 3-й параметр - флаг нажатия управляющих клавиш.
  • 4-й параметр - виртуальный код клавиши.

В нашем случае виртуальный код клавиши и идентификатор горячей клавиши совпадают. Конечно, здесь есть поле для дальнейшего усовершенствования. Скажем, исключить из обработки клавиши управления курсором. Я думаю, читатель справится с этим самостоятельно.

III

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

Средства управления списком можно разделить на сообщения и свойства32. Свойства задаются в файле ресурсов. Например, свойство LBS_SORT приводит к тому, что содержимое списка будет автоматически сортироваться при добавлении туда элемента. Очень важным является свойство LBS_WANTKEYBOARDINPUT. При наличии такого свойства приложение получает сообщение WM_VKEYTOITEM, которое посылается приложению, когда нажимается какая-либо клавиша при наличии фокуса на данном списке. Вы можете выбрать самостоятельную обработку - клавиша PgUp, или оставить стандартную обработку. В том случае, если стандартная обработка не нужна, следует возвратить из функции диалогового окна отрицательное значение.


32 Впрочем, это можно сказать о любых элементах на диалоговом окне. Не правда ли, это весьма похоже на методы и свойства в объектном программировании. Но мы то с Вами знаем, что если углубиться еще дальше, то мы обнаружим, что значительная часть свойств опять сведется к обработке сообщений (см. комментарий к программе на Рис. 2.4.3).


// файл diallst.rc

// определение констант
#define WS_SYSMENU 0x00080000L
#define WS_MINIMIZEBOX 0x00020000L
#define WS_MAXIMIZEBOX 0x00010000L
#define WS_VISIBLE 0x10000000L
#define WS_TABSTOP 0x00010000L
#define WS_VSCROLL 0x00200000L
#define WS_THICKFRAME 0x00040000L
#define LBS_NOTIFY 0x0001L
#define LBS_SORT 0x0002L
#define LBS_WANTKEYBOARDINPUT 0x0400L

// идентификаторы
#define LIST1 101
#define LIST2 102
#define IDI_ICON1 3

// определили иконку
IDI_ICON1 ICON "ico1.ico"

// определение диалогового окна
DIAL1 DIALOG 0, 0, 210, 110
STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
CAPTION "Пример диалогового окна"
FONT 8, "Arial"
{
 CONTROL "ListBox1",LIST1, "listbox", WS_VISIBLE |
 WS_TABSTOP | WS_VSCROLL | WS_THICKFRAME | LBS_NOTIFY | 
 LBS_WANTKEYBOARDINPUT,
 16, 16, 70, 75
 CONTROL "ListBox2", LIST2, "listbox", WS_VISIBLE |
 WS_TABSTOP | WS_VSCROLL | WS_THICKFRAME | LBS_NOTIFY | LBS_SORT,
 116, 16, 70, 75
}

; файл diallst.inc
; константы
; сообщение приходит при закрытии окна
WM_CLOSE equ 10h
WM_INITDIALOG equ 110h
WM_SETICON equ 80h
WM_COMMAND equ 111h
WM_VKEYTOITEM equ 2Eh
LB_ADDSTRING equ 180h
LBN_DBLCLK equ 2
LB_GETCURSEL equ 188h
LB_GETTEXT equ 189h
LB_FINDSTRING equ 18Fh
VK_INSERT equ 2Dh

; прототипы внешних процедур
EXTERN ExitProcess@4:NEAR
EXTERN GetModuleHandleA@4:NEAR
EXTERN DialogBoxParamA@20:NEAR
EXTERN EndDialog@8:NEAR
EXTERN LoadIconA@8:NEAR
EXTERN SendMessageA@16:NEAR
EXTERN SendDlgItemMessageA@20:NEAR
EXTERN MessageBoxA@16:NEAR

; структуры
; структура сообщения
MSGSTRUCT STRUC
 MSHWND DD ?
 MSMESSAGE DD ?
 MSWPARAM DD ?
 MSLPARAM DD ?
 MSTIME DD ?
 MSPT DD ?
MSGSTRUCT ENDS

; файл diallst.asm
.386P
; плоская модель
.MODEL FLAT, stdcall
include dial.inc
; директивы компоновщику для подключения библиотек
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
;-------------------------------------------------
; сегмент данных
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
 MSG MSGSTRUCT <?>
 HINST DD 0 ; дескриптор приложения
 PA DB "DIAL1",0
 BUFER DB 100 DUP (0)
 STR1 DB "Первый",0
 STR2 DB "Второй",0
 STR3 DB "Третий",0
 STR4 DB "Четвертый",0
 STR5 DB "Пятый ",0
 STR6 DB "Шестой",0
 STR7 DB "Седьмой",0
 STR8 DB "Восьмой",0
 STR9 DB "Девятый",0
 STR10 DB "Десятый",0
 STR11 DB "Одиннадцатый",0
 STR12 DB "Двенадцатый",0
 STR13 DB "Тринадцатый",0
 STR14 DB "Четырнадцатый",0
 STR15 DB "Пятнадцатый",0
 INDEX DD OFFSET STR1
 DD OFFSET STR2
 DD OFFSET STR3
 DD OFFSET STR4
 DD OFFSET STR5
 DD OFFSET STR6
 DD OFFSET STR7
 DD OFFSET STR8
 DD OFFSET STR9
 DD OFFSET STR10
 DD OFFSET STR11
 DD OFFSET STR12
 DD OFFSET STR13
 DD OFFSET STR14
 DD OFFSET STR15
_DATA ENDS

; сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:
; получить дескриптор приложения
 PUSH 0
 CALL GetModuleHandleA@4
 MOV [HINST], EAX
;----------------------------------------
 PUSH 0
 PUSH OFFSET WNDPROC
 PUSH 0
 PUSH OFFSET PA
 PUSH [HINST]
 CALL DialogBoxParamA@20
 CMP EAX,-1
 JNE KOL
; сообщение об ошибке
KOL:
;----------------------------------------
 PUSH 0
 CALL ExitProcess@4
;----------------------------------------
; процедура окна
; расположение параметров в стеке
; [EBP+014Н] ; LPARAM
; [EBP+10H] ; WAPARAM
; [EBP+0CH] ; MES
; [EBP+8] ; HWND
WNDPROC PROC
 PUSH EBP
 MOV EBP, ESP
 PUSH EBX
 PUSH ESI
 PUSH EDI
;----------------------------------------
 CMP DWORD PTR [EBP+0CH],WM_CLOSE
 JNE L1
 PUSH 0
 PUSH DWORD PTR [EBP+08H]
 CALL EndDialog@8
 JMP FINISH
L1:
 CMP DWORD PTR [EBP+0CH], WM_INITDIALOG
 JNE L2
; загрузить иконку
 PUSH 3 ; идентификатор иконки
 PUSH [HINST] ; идентификатор процесса
 CALL LoadIconA@8
; установить иконку
 PUSH EAX
 PUSH 0 ; тип иконки (маленькая)
 PUSH WM_SETICON
 PUSH DWORD PTR [EBP+08H]
 CALL SendMessageA@16
; заполнить левый список
 MOV ECX, 15
 MOV ESI, 0
L01:
 PUSH ECX ; сохранить параметр цикла
 PUSH INDEX[ESI]
 PUSH 0
 PUSH LB_ADDSTRING
 PUSH 101
 PUSH DWORD PTR [EBP+08H]
 CALL SendDlgItemMessageA@20
 ADD ESI, 4
 POP ECX
 LOOP L01
 JMP FINISH
L2:
 CMP DWORD PTR [EBP+0CH],WM_COMMAND
 JNE L3
; не сообщение ли от левого списка?
 CMP WORD PTR [EBP+10Н],101
 JNE FINISH
; не было ли двойного щелчка?
 CMP WORD PTR [EBP+12H], LBN_DBLCLK
 JNE FINISH
; был двойной щелчок, теперь определим элемент
; получить индекс выбранного элемента
L4:
 PUSH 0
 PUSH 0
 PUSH LB_GETCURSEL
 PUSH 101
 PUSH DWORD PTR [EBP+08H]
 CALL SendDlgItemMessageA@20
; скопировать элемент списка в буфер
 PUSH OFFSET BUFER
 PUSH EAX ; индекс записи
 PUSH LB_GETTEXT
 PUSH 101
 PUSH DWORD PTR [EBP+08H]
 CALL SendDlgItemMessageA@20
; определить, нет ли элемента в правом списке
 PUSH OFFSET BUFER
 PUSH -1 ; искать во всем списке
 PUSH LB_FINDSTRING
 PUSH 102
 PUSH DWORD PTR [EBP+08H]
 CALL SendDlgItemMessageA@20
 CMP EAX,-1
 JNE FINISH ; элемент нашли
; не нашли, можно добавлять
 PUSH OFFSET BUFER
 PUSH 0
 PUSH LB_ADDSTRING
 PUSH 102
 PUSH DWORD PTR [EBP+08H]
 CALL SendDlgItemMessageA@20
 MOV EAX,-1
 JMP FIN
L3:
; здесь проверка, не нажата ли клавиша
 CMP DWORD PTR [EBP+0CH],WM_VKEYTOITEM
 JNE FINISH
 CMP WORD PTR [EBP+10H],VK_INSERT
 JE L4
 MOV EAX,-1
 JMP FIN
FINISH:
 MOV EAX, 0
FIN:
 POP EDI
 POP ESI
 POP EBX
 POP EBP
 RET 16
WNDPROC ENDP
_TEXT ENDS
END START

Puc. 2.4.3. Пример программы с двумя списками. Перебросить запись из левого списка в правый можно двойным щелчком мыши или клавишей INSERT.

Комментарий к программе на Рис. 2.4.3.

  1. В первую очередь обратите внимание на функцию SendDIgItemMessage. Для посылки сообщения элементам диалогового окна эта функция более удобна, чем SendMessage, так как элемент в ней идентифицируется не дескриптором (который еще надо узнать), а номером, определенным в файле ресурсов.
  2. Взглянув на файл ресурсов. Вы увидите, что второму (правому) списку присвоено свойство LBS_SORT. Если такое свойство присвоено списку, то при добавлении в него элемента (сообщение LB_ADDSTRING) этот элемент помещается в список так, что список остается упорядоченным. Свойство LBS_SORT стоит системе Windows довольно большой работы. Посредством сообщения WM_COMPAREITEM она определяет нужное положение нового элемента в списке, а затем вставляет его при помощи сообщения LB_INSERTSTRING.
  3. Хотелось бы также обратить внимание на цикл заполнения левого списка. Нам приходится хранить регистр ECX в стеке. Вы скажете - дело обыкновенное при организации цикла при помощи команды LOOP. А я Вам скажу, что это совсем не очевидно. К сожалению, в документации по функциям API и сообщениям не указывается, какие регистры микропроцессора сохраняются, а какие нет. Все это придется устанавливать экспериментально. Что и было сделано мною в данном примере.
  4. Сообщение WM_VKEYTOITEM приходит при нажатии какой-либо клавиши, при наличии фокуса на списке. При этом список должен иметь свойство LBS_WANTKEYBOARDINPUT. Именно потому, что данное свойство установлено только у левого списка, у нас нет необходимости проверять, от какого списка пришло сообщение.


Вход на сайт
Поиск
Календарь
«  Июль 2025  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей
Наш опрос
Как Вам удобнее??
Всего ответов: 341
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0