платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 10 - Диалоговое окно как основное
Страница 1 из 1
платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 10 - Диалоговое окно как основное
Win32 API. Урок 10. Диалоговое окно как основное
Теперь время для действительно интересной темы, относящейся к GUI, о диалоговом окне. В этом туториале (и в следующем) мы научимся как использовать диалоговое окно в качестве основного.
Теория:
Если вы изучили примеры в предыдущем туториалe достаточно подробно, вы заметили, что вы не могли перемещать фокус ввода от одного дочернего окна на другое, используя кнопку Tab. Вы могли сделать это только кликнув на нужном контроле, чтобы перевести на него фокус. Это довольно неудобно. Также вы могли заметить, что изменился цвет родительского окна на серый. Это было сделано для того, чтобы цвет дочерних окон не контрастировал с клиентской областью родительского окна. Есть путь, чтобы обойти эту проблему, но он не очень прост. Вы должны сабклассить все дочерние элементы управления в вашем родительском окне.
Причина того, почему возникают подобные неудобства состоят в том, что дочерние окна изначально проектировались для работы с диалоговым окном, а не с обычным.
Цвет дочернего окна по умолчанию серый, так как это обычный цвет диалогового окна.
Прежде чем мы углубимся в детали, мы должны сначала узнать, что такое диалоговое окно. Диалоговое окно - это не что иное, как обычное окно, которое спроектировано для работы с дочерними элементами управления. Windows также предоставляет внутренний "менеджер диалоговых окон", который воплощает большую часть диалоговой логики, такую как перемещение фокуса ввода, когда юзер нажимает Tab, нажатие кнопки по умолчанию, если нажата кнопка 'Enter, и так далее, так чтобы программисты могли заниматься более высокоуровневыми задачами. Поскольку диалоговое окно можно считать "черным ящиком" (это означает то, что вы не обязаны знать, как
работает диалоговое окно, для того, чтобы использовать его), вы должны только знать, как с ним взаимодействовать. Это принцип объектно-ориентированного
программирования, называемого скрытием информации. Если черный ящик спроектирован совершенно, пользователь может использовать его не зная, как он работает.
Правда, загвоздка в том, что черный ящик должен быть совершенным, это труднодостижимо в реальном мире. Win32 API также спроектирован как черный ящик.
Ладно, похоже, что мы немного отклонились. Давайте вернемся к нашему сюжету. Диалоговые окна спроектированы так, чтобы снизить нагрузку на программиста.
Обычно, если вы помещаете дочерний контрол на обычное окно, вы должны сабклассить их и самостоятельно обрабатывать нажатия на клавиши. Но если вы помещаете их на диалоговое окно, оно обработает их за вас. Вы только должны как получать информацию, вводимую пользователем, или как посылать команды окну. Диалоговое окно определяется как ресурс (похожим образом, как и меню). Вы пишете шаблон диалогового окна, описывая характеристики диалогового окна и его контролов, а затем компилируете его с помощью редактора ресурсов.
Обратите внимание, что все ресурсы располагаются в одном скрипте ресурсов. Вы можете использовать любой текстовый редактор, чтобы написать шаблон диалогового окна, но я бы не рекомендовал это. Вы должны использовать редактор ресурсов, чтобы сделать визуально расположить дочерние окна. Существует несколько прекрасных редакторов ресурсов. К большинству из основных компиляторов прилагаются подобные редакторы. Вы можете использовать их, чтобы создать скрипт ресурса. После этого стоит вырезать лишние линии, например, те, которые относятся к MFC.
Есть два основных вида диалоговых окон: модальные и независимые. Независимые диалоговые окна дают вам возможность перемещать фокус ввода на другие окна.
Пример - диалоговое окно 'Find' в MS Word. Есть два подтипа модальных диалоговых окон: модальные к приложению и модальные к системе. Первые не дают вам переключаться на другое окно того же приложения, но вы можете переключиться на другое приложение. Вторые не дают вам возможности переключиться на любое другое окно.
Независимое диалоговое окно создается с помощью вызова функции CreateDialogParam. Модальное диалоговое окно создается вызовом DialogBoxParam. Единственное Различие между диалоговым окном, модальным отношению к приложению, и диалоговым окном, модальным по отношению к системе, - это стиль DS_SYSMODAL. Если вы включите стиль DS_SYSMODAL в шаблон диалогового окна, это диалоговое окно будет модальным к системе.
Вы можете взаимодействовать с любым дочерним элементом управления на диалоговом окне с помощью функции SendDlgItemMessage. Ее синтакс следующий:
function SendDlgItemMessage _
(byval hwndDlg as HWND, _
byval idControl as integer, _
byval uMsg as UINT, _
byval wParam as WPARAM, _
byval lParam as LPARAM) as LRESULT
Эта API-функция неоценимо полезна при взаимодействии с дочерним окном. Например, если вы хотите получить текст с контрола edit, вы можете сделать следующее:
SendDlgItemMessage(hDlg, ID_EDITBOX, WM_GETTEXT, 256, @text_buffer)
Чтобы знать, какое сообщение когда посылать, вы должны проконсультироваться с вашим Win32 API-справочником.
Windows также предоставляет несколько специальных API-функций, заточенных под дочерние окна, для быстрого получения и установки нужных данных, например, GetDlgItemText, CheckDlgButton и т.д. Эти специальные функции созданы, чтобы программисту не приходилось выяснять каждый раз значения wparam и lparam.
Как правило, вы должны использовать данные функции, если хотите, чтобы управление кодом было легче. Используйте SendDlgItemMessage только, если нет соответствующей API-функции. Менеджер диалоговых окон посылает некоторые сообщения специальной callback-функции, называемой процедурой диалогового окна, которая имеет следующий формат:
function DlgProc _
(byval hDlg as HWND
uMsg as UINT, _
byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
Процедура диалогового окна очень похожа на процедуру окна, если не считать тип возращаемого значения - TRUE/FALSE, вместо обычных LRESULT. Внутренний менеджер диалоговых окон внутри Windows - истинная процедура для диалоговых окон. Она вызывает нашу процедуру диалоговых окон, передавая некоторые из полученных сообщений. Поэтому главное правило следующее: если наша процедура диалогового окна обрабатывает сообщение, она должна вернуть TRUE и если она не обрабатывает сообщение, тогда она должна вернуть FALSE. Заметьте, что процедура диалогового окна не передает сообщения функции DefWindowProc, так как это не настоящая процедура окна.
Диалоговое окно можно использовать в двух целях. Вы можете использовать ее как основное окно или как вспомогательное для получения информации, вводимой пользователем. В этом туториале мы изучим первый вариант.
"Использование диалогового окна как основное окно" можно понимать двояко.
• Вы можете использовать шаблон диалогового окна как шаблон класса, который вы регистрируете с помощью функции RegisterClassEx. В этом случае, диалоговое окно ведет себя как "нормальное": оно получает сообщения через процедуру окна, на которую ссылается lрfnWndProc, а не через процедуру диалогового окна.
Выгода данного подхода состоит в том, что вы не должны самостоятельно создавать дочерние элементы управления, Windows создает их во время создания диалогового окна. Также Windows берет на себя логику нажатий на клавиши (Tab и т.д.). Плюс вы можете указать курсор и иконку вашего окна в структуре класса окна.
• Ваша программа создает диалоговое окно без создания родительского окна. Этот подход делает цикл сообщений ненужным, так как сообщения шлются напрямую процедуре диалогового окна. Вам даже не нужно регистрировать класс окна!
Похоже, что этот туториал будет довольно долгим.
Пример:
файл dialog.bas
Dialog.rc
Теперь время для действительно интересной темы, относящейся к GUI, о диалоговом окне. В этом туториале (и в следующем) мы научимся как использовать диалоговое окно в качестве основного.
Теория:
Если вы изучили примеры в предыдущем туториалe достаточно подробно, вы заметили, что вы не могли перемещать фокус ввода от одного дочернего окна на другое, используя кнопку Tab. Вы могли сделать это только кликнув на нужном контроле, чтобы перевести на него фокус. Это довольно неудобно. Также вы могли заметить, что изменился цвет родительского окна на серый. Это было сделано для того, чтобы цвет дочерних окон не контрастировал с клиентской областью родительского окна. Есть путь, чтобы обойти эту проблему, но он не очень прост. Вы должны сабклассить все дочерние элементы управления в вашем родительском окне.
Причина того, почему возникают подобные неудобства состоят в том, что дочерние окна изначально проектировались для работы с диалоговым окном, а не с обычным.
Цвет дочернего окна по умолчанию серый, так как это обычный цвет диалогового окна.
Прежде чем мы углубимся в детали, мы должны сначала узнать, что такое диалоговое окно. Диалоговое окно - это не что иное, как обычное окно, которое спроектировано для работы с дочерними элементами управления. Windows также предоставляет внутренний "менеджер диалоговых окон", который воплощает большую часть диалоговой логики, такую как перемещение фокуса ввода, когда юзер нажимает Tab, нажатие кнопки по умолчанию, если нажата кнопка 'Enter, и так далее, так чтобы программисты могли заниматься более высокоуровневыми задачами. Поскольку диалоговое окно можно считать "черным ящиком" (это означает то, что вы не обязаны знать, как
работает диалоговое окно, для того, чтобы использовать его), вы должны только знать, как с ним взаимодействовать. Это принцип объектно-ориентированного
программирования, называемого скрытием информации. Если черный ящик спроектирован совершенно, пользователь может использовать его не зная, как он работает.
Правда, загвоздка в том, что черный ящик должен быть совершенным, это труднодостижимо в реальном мире. Win32 API также спроектирован как черный ящик.
Ладно, похоже, что мы немного отклонились. Давайте вернемся к нашему сюжету. Диалоговые окна спроектированы так, чтобы снизить нагрузку на программиста.
Обычно, если вы помещаете дочерний контрол на обычное окно, вы должны сабклассить их и самостоятельно обрабатывать нажатия на клавиши. Но если вы помещаете их на диалоговое окно, оно обработает их за вас. Вы только должны как получать информацию, вводимую пользователем, или как посылать команды окну. Диалоговое окно определяется как ресурс (похожим образом, как и меню). Вы пишете шаблон диалогового окна, описывая характеристики диалогового окна и его контролов, а затем компилируете его с помощью редактора ресурсов.
Обратите внимание, что все ресурсы располагаются в одном скрипте ресурсов. Вы можете использовать любой текстовый редактор, чтобы написать шаблон диалогового окна, но я бы не рекомендовал это. Вы должны использовать редактор ресурсов, чтобы сделать визуально расположить дочерние окна. Существует несколько прекрасных редакторов ресурсов. К большинству из основных компиляторов прилагаются подобные редакторы. Вы можете использовать их, чтобы создать скрипт ресурса. После этого стоит вырезать лишние линии, например, те, которые относятся к MFC.
Есть два основных вида диалоговых окон: модальные и независимые. Независимые диалоговые окна дают вам возможность перемещать фокус ввода на другие окна.
Пример - диалоговое окно 'Find' в MS Word. Есть два подтипа модальных диалоговых окон: модальные к приложению и модальные к системе. Первые не дают вам переключаться на другое окно того же приложения, но вы можете переключиться на другое приложение. Вторые не дают вам возможности переключиться на любое другое окно.
Независимое диалоговое окно создается с помощью вызова функции CreateDialogParam. Модальное диалоговое окно создается вызовом DialogBoxParam. Единственное Различие между диалоговым окном, модальным отношению к приложению, и диалоговым окном, модальным по отношению к системе, - это стиль DS_SYSMODAL. Если вы включите стиль DS_SYSMODAL в шаблон диалогового окна, это диалоговое окно будет модальным к системе.
Вы можете взаимодействовать с любым дочерним элементом управления на диалоговом окне с помощью функции SendDlgItemMessage. Ее синтакс следующий:
function SendDlgItemMessage _
(byval hwndDlg as HWND, _
byval idControl as integer, _
byval uMsg as UINT, _
byval wParam as WPARAM, _
byval lParam as LPARAM) as LRESULT
Эта API-функция неоценимо полезна при взаимодействии с дочерним окном. Например, если вы хотите получить текст с контрола edit, вы можете сделать следующее:
SendDlgItemMessage(hDlg, ID_EDITBOX, WM_GETTEXT, 256, @text_buffer)
Чтобы знать, какое сообщение когда посылать, вы должны проконсультироваться с вашим Win32 API-справочником.
Windows также предоставляет несколько специальных API-функций, заточенных под дочерние окна, для быстрого получения и установки нужных данных, например, GetDlgItemText, CheckDlgButton и т.д. Эти специальные функции созданы, чтобы программисту не приходилось выяснять каждый раз значения wparam и lparam.
Как правило, вы должны использовать данные функции, если хотите, чтобы управление кодом было легче. Используйте SendDlgItemMessage только, если нет соответствующей API-функции. Менеджер диалоговых окон посылает некоторые сообщения специальной callback-функции, называемой процедурой диалогового окна, которая имеет следующий формат:
function DlgProc _
(byval hDlg as HWND
uMsg as UINT, _
byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
Процедура диалогового окна очень похожа на процедуру окна, если не считать тип возращаемого значения - TRUE/FALSE, вместо обычных LRESULT. Внутренний менеджер диалоговых окон внутри Windows - истинная процедура для диалоговых окон. Она вызывает нашу процедуру диалоговых окон, передавая некоторые из полученных сообщений. Поэтому главное правило следующее: если наша процедура диалогового окна обрабатывает сообщение, она должна вернуть TRUE и если она не обрабатывает сообщение, тогда она должна вернуть FALSE. Заметьте, что процедура диалогового окна не передает сообщения функции DefWindowProc, так как это не настоящая процедура окна.
Диалоговое окно можно использовать в двух целях. Вы можете использовать ее как основное окно или как вспомогательное для получения информации, вводимой пользователем. В этом туториале мы изучим первый вариант.
"Использование диалогового окна как основное окно" можно понимать двояко.
• Вы можете использовать шаблон диалогового окна как шаблон класса, который вы регистрируете с помощью функции RegisterClassEx. В этом случае, диалоговое окно ведет себя как "нормальное": оно получает сообщения через процедуру окна, на которую ссылается lрfnWndProc, а не через процедуру диалогового окна.
Выгода данного подхода состоит в том, что вы не должны самостоятельно создавать дочерние элементы управления, Windows создает их во время создания диалогового окна. Также Windows берет на себя логику нажатий на клавиши (Tab и т.д.). Плюс вы можете указать курсор и иконку вашего окна в структуре класса окна.
• Ваша программа создает диалоговое окно без создания родительского окна. Этот подход делает цикл сообщений ненужным, так как сообщения шлются напрямую процедуре диалогового окна. Вам даже не нужно регистрировать класс окна!
Похоже, что этот туториал будет довольно долгим.
Пример:
файл dialog.bas
- Код:
' диалоговое окно как основное
#include "windows.bi"
#include "l10_dialog.bi"
declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
byval szCmdLine as LPSTR, _
byval iCmdShow as integer ) as integer
' начало программы
dim shared as zString * 512 buffer 'буффер для editboxа
end WinMain(GetModuleHandle( NULL ),NULL,GetCommandLine() , SW_SHOWNORMAL ) ' вызвать основную функцию
' здесь заканчивается программа
' процедура окна
function WndProc _
(byval hwnd as HWND, _ ' хэндл окна
byval uMsg as UINT, _ ' сообщение
byval wParam as WPARAM, _ ' дополнительный параметр сообщений
byval lParam as LPARAM) as LRESULT ' дополнительный параметр сообщений
function = 0
select case uMsg 'начинаем обработку сообщений
case WM_DESTROY ' если пользователь закрывает окно
PostQuitMessage(0) ' выходим из программы
exit function
case WM_COMMAND ' если получили сообщение WM_COMMAND
if lParam = 0 then ' если lParam = 0, значит идет сообщение от меню
select case loword(wParam) ' начинаем обрабатывать элементы меню
case IDM_GETTEXT
' прочитаем текст из editboxа в буфер
GetDlgItemText _
(hwnd, _ ' хэндл диалога
IDC_EDIT, _ ' идентификатор editboxа
@buffer, _ ' указатель на буфер
512) ' число прочитанных байт
' выведем в Message Box
MessageBox(NULL,@buffer,"Our First Dialog Box",MB_OK)
case IDM_CLEAR
' очистим editbox
SetDlgItemText _
(hwnd, _ ' хэндл диалога
IDC_EDIT, _ ' хэндл editboxа
NULL) ' пустая строка
case IDM_EXIT
DestroyWindow(hwnd) ' разрушим окно и выдем из программы
end select
end if
if hiword(wparam) = BN_CLICKED then ' если кликают кнопки
select case loword(wParam) ' продолжаем проверять идентификаторы
case IDC_BUTTON ' если сообщение нашей кнопки
'запишем в editbox тестовую строку
SetDlgItemText _
(hwnd, _ ' хэндл диалога
IDC_EDIT, _ ' идентификатор editboxа
"Wow! I'm in an edit box now") ' тестовая строка
case IDC_EXIT
' пошлем сообщение, как будто мы выбрали в менюшке exit
SendMessage _
(hwnd, _ ' хэндл окна
WM_COMMAND, _ ' тип сообщения
IDM_EXIT, _ ' ид меню
0)
end select
end if
end select
function = DefWindowProc(hwnd,uMsg,wParam,lParam) ' Дефаултная функция обработки окна
end function
'функция WinMain
function WinMain _
(byval hInst as HINSTANCE, _ ' хэндл программы
byval hPrevInst as HINSTANCE, _ 'в win32 всегда 0
byval szCmdLine as LPSTR, _ 'указатель на командную строку
byval iCmdShow as integer ) as integer ' состояние окна при первом появлении
dim wc as WNDCLASSEX ' структура параметров окна
dim wMsg as MSG ' структура сообщений
dim hDlg as HWND ' хэндл диалога
'структура класса окна wc
with wc ' заполняем структуру wc
.cbSize = SIZEOF( WNDCLASSEX ) ' размер структуры WNDCLASSEX
.style = CS_HREDRAW or CS_VREDRAW ' Стиль окна
.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
.cbClsExtra = NULL ' резервирование дополнительных байт за концом структуры
.cbWndExtra = DLGWINDOWEXTRA
.hInstance = hInst ' хэндл модуля
.hbrBackground = cast(HGDIOBJ, COLOR_BTNFACE+1) ' Цвет фона
.lpszMenuName = @"MyMenu" ' хэндл меню
.lpszClassName = @"DLGCLASS" ' имя класса окна
.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
.hIconSm = .hIcon 'Хэндл маленькой иконки
.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора
end with
' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if
' Создадим диалог
hDlg = CreateDialogParam _
(hInst, _ ' хэндл модуля
"MyDialog", _ ' id dialoga
NULL,NULL,NULL)
if hDlg = 0 then
messagebox(0,"Не могу создать диалог","ошибка",0)
end 2
end if
ShowWindow(hDlg,iCmdShow) ' отобразить наше окно на десктопе
UpdateWindow( hDlg) ' обновить клиентскую область
' получим дескриптор editboxа и установим фокус в editbox
SetFocus(GetDlgItem _
(hDlg,_ ' хэндл диалога
IDC_EDIT)) ' id editboxа
while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE ) 'цикл сообщений
if IsDialogMessage(hDlg, @wMsg) = FALSE then
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
end if
wend
function = wMsg.wParam
end function
Dialog.rc
- Код:
#include "resource.h"
MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our First Dialog Box"
CLASS "DLGCLASS"
{
EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13
PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13, WS_GROUP
}
MyMenu MENU
{
POPUP "Test Controls"
{
MENUITEM "Get Text", IDM_GETTEXT
MENUITEM "Clear Text", IDM_CLEAR
MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "E&xit", IDM_EXIT
}
}
Последний раз редактировалось: electrik (Вт Май 23, 2017 5:50 pm), всего редактировалось 1 раз(а)
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 10 - Диалоговое окно как основное
Win32 API. Урок 10. Диалоговое окно как основное - продолжение
Анализ:
Давайте проанализируем первый пример.
Этот пример показывает, как зарегистрировать диалоговый шаблон как класс окна и создает "окно" из этого класса. Это упрощает вашу программу, так как вам не нужно создавать дочерние контролы самостоятельно.
Давайте проанализируем шаблон диалогового окна.
MyDialog DIALOG 10, 10, 205, 60
Объявление имя диалога, в данном случае - "MyDialog", за которым следует ключевое слово "DIALOG". Следующие четыре номера - это x, y, ширина и высота диалогового окна в специальных единицах (не в пикселях).
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
Объявление стилей диалогового окна.
CAPTION "Our First Dialog Box"
Это текст, который появится в title bar'е.
CLASS "DLGCLASS"
Это ключевая строка. Ключевое слово 'CLASS' позволяет нам использовать шаблон диалогового окна в качестве класса окна. Следующее слово - это имя "класса окна".
{
EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13
PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13
}
Данный блок определяет дочерние элементы управления в диалоговом окне. Они определены между фигурными скобками { }. Общий синтаксис таков:
control-type "text" ,controlID, x, y, width, height [,styles]
control-type'ы - это константы компилятора ресурсов, вам нужно свериться с руководством.
Теперь мы углубляемся непосредственно в код. Интересующая нас часть находится в структуре класса окна.
.cbWndExtra = DLGWINDOWEXTRA
.lpszClassName = @"DLGCLASS"
Обычно этот параметр оставляется равным нулю, но если мы хотим зарегистрировать шаблон диалогового окна как класс окна, мы должны установить этот параметр равным DLGWINDOWEXTRA. Заметьте, что имя класса должно совпадать с именем, что определено в шаблоне диалогового окна. Остающиеся параметры инициализируются как обычно. После того, как вы заполните структуру класса окна, зарегистрируйте ее с помощью RegisterClassEx. Звучит знакомо. Точно также вы регистрируете
обычный класс окна.
' Создадим диалог
hDlg = CreateDialogParam _
(hInst, _
"MyDialog", _
NULL,NULL,NULL)
После регистрации "класса окна", мы создаем наше диалоговое окно. В этом примере я создал его как независимое диалоговое окно функцией CreateDialogParam.
Эта функция получает 5 параметров, но вам нужно заполнить только первые два: хэндл процесса и указатель на имя шаблона диалогового окна. Заметьте, что второй параметр - это не указатель на имя класса.
В этот момент, диалоговое окно и его дочерние элементы управления создаются Windows. Ваша процедура окна получит сообщение WM_CREATE как обычно.
SetFocus(GetDlgItem _
(hDlg,_
IDC_EDIT))
После того, как диалоговое окно создано, я хочу установить фокус ввода на edit control. Если я помещу соответствующий код в секцию WM_CREATE, вызов GetDlgItem провалится, так как дочерние окна еще не созданы. Единственный путь сделать это - вызвать эту функцию после того, как диалоговое окно и все его дочерние окна будут созданы. Поэтому я помещаю данные две линии после вызова UpdateWindow. Функция GetDlgItem получает ID контрола и возвращает соответствующий хэндл окна. Так вы можете получить хэндл окна, если вы знаете его control ID.
if IsDialogMessage(hDlg, @wMsg) = FALSE then
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
end if
Программа входит в цикл сообщений и перед тем, как мы транслируем и передаем сообщения, мы вызываем функцию IsDialogMessage, чтобы позволить менеджеру диалоговых сообщений обрабатывать логику сообщений за нас. Если эта функция возвращает TRUE, это значит, что сообщение сделано для диалогового окна и обрабатывается менеджером диалоговых сообщений. Отметьте другое отличие от предыдущего туториала. Когда процедура окна хочет получить текст с edit контрола, она вызывает функцию GetDlgItemText, вместо функции GetWindowText. GetDlgItemText принимает ID контрола вместо хэндла окна. Это делает вызов проще в том случае, если вы используете диалоговое окно.
Теперь давайте перейдем ко второму подходу использования диалогового окна как основного окна. В следующем примере, я создам програмно-модальное диалоговое окно. Вы не увидите цикл сообщений или процедуру окна, потому что они не нужны!
файл dialog_p2.bi
файл dialog_p2.rc
Function DlgProc (byval hwnd as HWND, byval uMsg as UINT, _
byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
Мы объявляем прототип функции для DlgProc, так что мы можем ссылаться на нее оператором @:
end DialogBoxParam _
(hModule, _ '
"MyDialog", _
NULL, _
@DlgProc, _
NULL)
В вышеприведенной строке вызывается функция DialogBoxParam, которая получает 5 параметров: хэндл процесса, имя шаблона диалогового окна, хэндл родительского окна, адрес процедуры диалогового окна и специальные данные для диалогового окна. DialogBoxParam создает модальное диалоговое окно. Она не возвращается, пока диалоговое окно не будет уничтожено.
case WM_INITDIALOG
SetFocus(GetDlgItem _
(hWnd, _
IDC_EDIT))
case WM_CLOSE
SendMessage _
(hWnd, _
WM_COMMAND, _
IDM_EXIT, _
0)
Процедура диалогового окна выглядит как процедура окна, не считая того, что она не получает сообщение WM_CREATE. Первое сообщение, которое она получает- это WM_INITDIALOG. Обычно вы помещаете здесь инициализационный код. Заметьте, что вы должны вернуть значение TRUE, если вы обрабатываете это сообщение.
Внутренний менеджер диалогового окна не посылает нашей процедуре сообщение WM_DESTROY, а вот WM_CLOSE шлет. Поэтому если мы хотим отреагировать на то, что юзер нажимает кнопку закрытия на нашем диалоговом окне, мы должны обработать сообщение WM_CLOSE. В нашем примере мы посылаем сообщение WM_CLOSE со значением IDM_EXIT в wParam. Это произведет тот же эффект, что и выбор пункта 'Exit' в меню. EndDialog вызывается в ответ на IDM_EXIT.
Обработка сообщений WM_COMMAND остается такой же.
Когда вы хотите уничтожить диалоговое окно, единственный путь - это вызов функции EndDialog. Не пробуйте DestroyWindow! EndDialog не уничтожает диалоговое окно немедленно. Она только устанавливает флаг для внутреннего менеджера диалогового окна и продолжает выполнять следующие инструкции.
Теперь давайте изучим файл ресурсов. Заметное изменение - это то, что вместо использования текстовой строки в качестве имени меню, мы используем значение IDR_MENU1. Это необходимо, если вы хотите прикрепить меню к диалоговому окну, созданному DialogBoxParam'ом. Заметьте, что в шаблоне диалогового окна вы должны добавить ключевое слово 'MENU', за которым будет следовать ID ресурса меню.
различие между двумя примерами в этом туториале, которое вы можете легко заметить - это отсутствие иконки в последнем примере. Тем не менее, вы можете установить иконку, послав сообщение WM_SETICON диалоговому окну во время обработки WM_INITDIALOG.
[C] Iczelion, пер. Aquila.
Анализ:
Давайте проанализируем первый пример.
Этот пример показывает, как зарегистрировать диалоговый шаблон как класс окна и создает "окно" из этого класса. Это упрощает вашу программу, так как вам не нужно создавать дочерние контролы самостоятельно.
Давайте проанализируем шаблон диалогового окна.
MyDialog DIALOG 10, 10, 205, 60
Объявление имя диалога, в данном случае - "MyDialog", за которым следует ключевое слово "DIALOG". Следующие четыре номера - это x, y, ширина и высота диалогового окна в специальных единицах (не в пикселях).
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
Объявление стилей диалогового окна.
CAPTION "Our First Dialog Box"
Это текст, который появится в title bar'е.
CLASS "DLGCLASS"
Это ключевая строка. Ключевое слово 'CLASS' позволяет нам использовать шаблон диалогового окна в качестве класса окна. Следующее слово - это имя "класса окна".
{
EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13
PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13
}
Данный блок определяет дочерние элементы управления в диалоговом окне. Они определены между фигурными скобками { }. Общий синтаксис таков:
control-type "text" ,controlID, x, y, width, height [,styles]
control-type'ы - это константы компилятора ресурсов, вам нужно свериться с руководством.
Теперь мы углубляемся непосредственно в код. Интересующая нас часть находится в структуре класса окна.
.cbWndExtra = DLGWINDOWEXTRA
.lpszClassName = @"DLGCLASS"
Обычно этот параметр оставляется равным нулю, но если мы хотим зарегистрировать шаблон диалогового окна как класс окна, мы должны установить этот параметр равным DLGWINDOWEXTRA. Заметьте, что имя класса должно совпадать с именем, что определено в шаблоне диалогового окна. Остающиеся параметры инициализируются как обычно. После того, как вы заполните структуру класса окна, зарегистрируйте ее с помощью RegisterClassEx. Звучит знакомо. Точно также вы регистрируете
обычный класс окна.
' Создадим диалог
hDlg = CreateDialogParam _
(hInst, _
"MyDialog", _
NULL,NULL,NULL)
После регистрации "класса окна", мы создаем наше диалоговое окно. В этом примере я создал его как независимое диалоговое окно функцией CreateDialogParam.
Эта функция получает 5 параметров, но вам нужно заполнить только первые два: хэндл процесса и указатель на имя шаблона диалогового окна. Заметьте, что второй параметр - это не указатель на имя класса.
В этот момент, диалоговое окно и его дочерние элементы управления создаются Windows. Ваша процедура окна получит сообщение WM_CREATE как обычно.
SetFocus(GetDlgItem _
(hDlg,_
IDC_EDIT))
После того, как диалоговое окно создано, я хочу установить фокус ввода на edit control. Если я помещу соответствующий код в секцию WM_CREATE, вызов GetDlgItem провалится, так как дочерние окна еще не созданы. Единственный путь сделать это - вызвать эту функцию после того, как диалоговое окно и все его дочерние окна будут созданы. Поэтому я помещаю данные две линии после вызова UpdateWindow. Функция GetDlgItem получает ID контрола и возвращает соответствующий хэндл окна. Так вы можете получить хэндл окна, если вы знаете его control ID.
if IsDialogMessage(hDlg, @wMsg) = FALSE then
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
end if
Программа входит в цикл сообщений и перед тем, как мы транслируем и передаем сообщения, мы вызываем функцию IsDialogMessage, чтобы позволить менеджеру диалоговых сообщений обрабатывать логику сообщений за нас. Если эта функция возвращает TRUE, это значит, что сообщение сделано для диалогового окна и обрабатывается менеджером диалоговых сообщений. Отметьте другое отличие от предыдущего туториала. Когда процедура окна хочет получить текст с edit контрола, она вызывает функцию GetDlgItemText, вместо функции GetWindowText. GetDlgItemText принимает ID контрола вместо хэндла окна. Это делает вызов проще в том случае, если вы используете диалоговое окно.
Теперь давайте перейдем ко второму подходу использования диалогового окна как основного окна. В следующем примере, я создам програмно-модальное диалоговое окно. Вы не увидите цикл сообщений или процедуру окна, потому что они не нужны!
- Код:
'програмно-модальное диалоговое окно
#include "windows.bi"
#include "dialog_p2.bi"
declare Function DlgProc (byval hwnd as HWND, byval uMsg as UINT, _
byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
dim shared hModule as HINSTANCE ' хэндл модуля(программы)
dim shared as zstring * 512 buffer ' буфер для editboxа
hModule = GetModuleHandle(NULL) ' получим хэндл программы
'создадим диалог
end DialogBoxParam _
(hModule, _ ' хэндл программы
"MyDialog", _ ' идентификатор диалога
NULL, _
@DlgProc, _ ' указатель на DlgProc
NULL)
Function DlgProc (byval hwnd as HWND, byval uMsg as UINT, _
byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
select case uMsg
case WM_INITDIALOG ' если диалог инициализируется
' получим дискриптор editboxа и установим фокус в editbox
SetFocus(GetDlgItem _
(hWnd, _ ' хэндл диалога
IDC_EDIT)) ' идентификатор editboxа
case WM_CLOSE ' если сообщение о закрытии окна
' пошлем сообщение, как будто мы выбрали в меню exit
SendMessage _
(hWnd, _ ' хэндл диалога
WM_COMMAND, _ ' тип сообщения
IDM_EXIT, _ ' идентификатор меню
0)
case WM_COMMAND
if lParam = 0 then ' если равно 0, значит идут сообщения от меню
select case loword(wParam) ' начинаем обрабатывать сообщения от меню
case IDM_GETTEXT
' прочитаем текст из editboxа в буфер
GetDlgItemText _
(hWnd, _ ' хэндл диалога
IDC_EDIT, _ ' идентификатор editboxа
@buffer, _ ' указатель на буфер
512) ' число прочитанных байт
' выведем буфер в MessageBox
MessageBox(NULL,@buffer,"Our Second Dialog Box",MB_OK)
case IDM_CLEAR
' очистим editbox
SetDlgItemText _
(hWnd, _ ' хэндл диалога
IDC_EDIT, _ ' идентификатор editboxа
NULL) ' пустая строка
case IDM_EXIT
' закроем диалог функцией EndDialog
EndDialog _
(hWnd, _ ' хэндл диалога
NULL)
end select
end if
if hiword(wParam) = BN_CLICKED then ' если кликают кнопки
select case loword(wParam) ' продолжаем проверять идентификаторы
case IDC_BUTTON
' запишем в editbox тестовую строку
SetDlgItemText _
(hWnd, _ ' хэндл диалога
IDC_EDIT, _ ' идентификатор editboxа
"Wow! I'm in an edit box now") ' строка записываемая в editbox
case IDC_EXIT
' пошлем сообщение, как будто мы выбрали в меню exit
SendMessage(hWnd, _ ' хэндл диалога
WM_COMMAND, _ ' тип сообщения
IDM_EXIT, _ ' идентификатор меню
0)
end select
end if
case else
function = FALSE
exit function
end select
function = TRUE
end function
файл dialog_p2.bi
- Код:
#define IDC_EDIT 3000
#define IDC_BUTTON 3001
#define IDC_EXIT 3002
#define IDR_MENU1 3003
#define IDM_GETTEXT 32000
#define IDM_CLEAR 32001
#define IDM_EXIT 32003
файл dialog_p2.rc
- Код:
#include "dialog_p2.bi"
MyDialog DIALOG 10, 10, 205, 60
STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK
CAPTION "Our Second Dialog Box"
MENU IDR_MENU1
BEGIN
EDITTEXT IDC_EDIT, 15,17,111,13, ES_AUTOHSCROLL | ES_LEFT
DEFPUSHBUTTON "Say Hello", IDC_BUTTON, 141,10,52,13
PUSHBUTTON "E&xit", IDC_EXIT, 141,26,52,13
END
IDR_MENU1 MENU
BEGIN
POPUP "Test Controls"
BEGIN
MENUITEM "Get Text", IDM_GETTEXT
MENUITEM "Clear Text", IDM_CLEAR
MENUITEM "", , 0x0800 /*MFT_SEPARATOR*/
MENUITEM "E&xit", IDM_EXIT
END
END
Function DlgProc (byval hwnd as HWND, byval uMsg as UINT, _
byval wparam as WPARAM, byval lparam as LPARAM) as BOOL
Мы объявляем прототип функции для DlgProc, так что мы можем ссылаться на нее оператором @:
end DialogBoxParam _
(hModule, _ '
"MyDialog", _
NULL, _
@DlgProc, _
NULL)
В вышеприведенной строке вызывается функция DialogBoxParam, которая получает 5 параметров: хэндл процесса, имя шаблона диалогового окна, хэндл родительского окна, адрес процедуры диалогового окна и специальные данные для диалогового окна. DialogBoxParam создает модальное диалоговое окно. Она не возвращается, пока диалоговое окно не будет уничтожено.
case WM_INITDIALOG
SetFocus(GetDlgItem _
(hWnd, _
IDC_EDIT))
case WM_CLOSE
SendMessage _
(hWnd, _
WM_COMMAND, _
IDM_EXIT, _
0)
Процедура диалогового окна выглядит как процедура окна, не считая того, что она не получает сообщение WM_CREATE. Первое сообщение, которое она получает- это WM_INITDIALOG. Обычно вы помещаете здесь инициализационный код. Заметьте, что вы должны вернуть значение TRUE, если вы обрабатываете это сообщение.
Внутренний менеджер диалогового окна не посылает нашей процедуре сообщение WM_DESTROY, а вот WM_CLOSE шлет. Поэтому если мы хотим отреагировать на то, что юзер нажимает кнопку закрытия на нашем диалоговом окне, мы должны обработать сообщение WM_CLOSE. В нашем примере мы посылаем сообщение WM_CLOSE со значением IDM_EXIT в wParam. Это произведет тот же эффект, что и выбор пункта 'Exit' в меню. EndDialog вызывается в ответ на IDM_EXIT.
Обработка сообщений WM_COMMAND остается такой же.
Когда вы хотите уничтожить диалоговое окно, единственный путь - это вызов функции EndDialog. Не пробуйте DestroyWindow! EndDialog не уничтожает диалоговое окно немедленно. Она только устанавливает флаг для внутреннего менеджера диалогового окна и продолжает выполнять следующие инструкции.
Теперь давайте изучим файл ресурсов. Заметное изменение - это то, что вместо использования текстовой строки в качестве имени меню, мы используем значение IDR_MENU1. Это необходимо, если вы хотите прикрепить меню к диалоговому окну, созданному DialogBoxParam'ом. Заметьте, что в шаблоне диалогового окна вы должны добавить ключевое слово 'MENU', за которым будет следовать ID ресурса меню.
различие между двумя примерами в этом туториале, которое вы можете легко заметить - это отсутствие иконки в последнем примере. Тем не менее, вы можете установить иконку, послав сообщение WM_SETICON диалоговому окну во время обработки WM_INITDIALOG.
[C] Iczelion, пер. Aquila.
electrik- Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 43
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург
Страница 1 из 1
Права доступа к этому форуму:
Вы не можете отвечать на сообщения