платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 18 - Common Control'ы

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 18 - Common Control'ы

Сообщение  electrik в Пн Июн 29, 2009 8:05 pm

Win32 API. Урок 18. Common Control'ы

Мы узнаем, что такое common control'ы и как их использовать. Этот туториал является не более, чем поверхностным введением в данную тему.

Теория:

Windows 95 принесла несколько новых элементов пользовательского интерфейса, сделавших GUI более разнообразным. Некоторые из них широко использовались и в Windows 3.1, но программисты должны были программировать их самостоятельно. Теперь Микрософт включил их в Windows 9x и NT. Мы изучим их в этом туториале.

Вот список новых контролов:

• Toolbar
• Tooltip
• Status bar
• property sheet
• property page
• Tree view
• List view
• Animation
• Drag list
• Header
• Hot-key
• Image list
• progress bar
• Right edit
• Tab
• Trackbar
• Up-down

Так как новых контролов довольно много, их загрузка в память и регистрация была бы бессмысленной тратой ресурсов. Все эти элементы управления, за исключением rich edit'а, находятся в comctl32.dll, чтобы приложения могли загружать их, когда они им нужны. Rich edit находится в своей собственной dll, richedXX.dll, так как он слишком сложен и поэтому больше, чем остальные.

Вы можете вызвать comctl32.dll, поместив вызов функции InitCommonControls в вашу программу. InitCommonControls - это функция в comctl32.dll, поэтому ее вызов в любом месте вашего кода заставит PE-загрузчик загрузить comctl32.dll, когда ваша программа запустится. Вам не нужно выполнять эту функцию, просто поместите ее где-нибудь. Эта функция ничего не делает! Ее единственной инструкцией является "ret". Ее главная цель - это создание ссылки на comctl32.dll в секции импорта, чтобы PE-загрузчик загружал ее всегда, когда будет загружаться программа. Главным следствием будет являться то, что стартовая функция DLL зарегистрирует все классы common control'ов при загрузке dll. Common control'ы создаются на основе этих классов, как и другие дочерние элементы окон, например, edit control, listbox и так далее.

С rich edit'ом дел обстоит совершенно по другому. Если вы хотите использовать его, вы должны вызвать LoadLibrary, чтобы загрузить его и FreeLibrary, чтобы выгрузить. Теперь давайте научимся создавать common control'ы. Вы можете использовать редактор ресурсов, чтобы внедрить их в диалоговое окно, или создать их самостоятельно. Почти все common control'ы создаются с помощью вызова CreateWindowEx или CreateWindow, путем передачи имени класса контрола. У некоторых common control'ов есть специальные функции для создания, хотя, на самом деле, они являются функциями-обвертками вокруг CreateWindowEx, чтобы сделать создание элемента управления легче. Такие функции перечислены ниже:

• CreateToolbarEx
• CreateStatusWindow
• CreatepropertySheetpage
• propertySheet
• ImageList_Create

Чтобы создавать common control'ы, вы должны знать их имена. Они перечисленны ниже:

                     Class Name           Common Control

Имя класса           Common Control'ы

ToolbarWindow32              Toolbar

tooltips_class32             Tooltip

msctls_statusbar32          Status bar

SysTreeView32               Tree view

SysListView32               List view

SysAnimate32                Animation

SysHeader32                   Header

msctls_hotkey32              Hot-key

msctls_progress32          progress bar

RICHEDIT                    Rich edit

msctls_updown32              Up-down

SysTabControl32                Tab


property sheet'ы и property page'ы и контрол image list имеют собственные функции создания. Drag list control - это усовершенствованный listbox, поэтому у него нет своего собственного класса. Вышеприведенные имена проверены путем проверки скриптов ресурсов, генерируемых редактором ресурсов, входящего в Visual C++. Они отличаются от имен, приведенных в  справочнике по Win32 API от Borland'а и тех, что указаны в книге Charles рetzold's "programming Windows 95". Вышеприведенный список является точной версией.

Эти common control'ы могут использовать общие стили окна, такие как WS_CHILD и т.п. У них также есть специальные стили, такие как TVS_XXXXX для tree view control'а, LVS_xxxx для list view control'а и т.д. Справочник по Win32 API ваше лучшее руководство в данном случае.

Теперь, когда мы знаем, как создать common control'ы, мы можем перейти к тому, как взаимодействуют common control'ы и их родители. В отличие от дочерних элементов управления, common control'ы не взаимодействуют с родительским окном через WM_COMMAND. Вместо этого они используют сообщение WM_NOTIFY, посылаемое родительскому окну, когда происходит какое-то интересное событие. "родитель" может контролировать "детей", посылая им определенные сообщения, которых введено достаточно много. Вам следует обратиться к справочнику по Win32 API за конкретными деталями.

Давайте посмотрим, как создать рrogress bar и status bar.

Пример:

Код:

' Common Control'ы
#include "windows.bi"
#include "win/commctrl.bi"

declare function WinMain ( byval hInst as HINSTANCE, _
byval hPrevInst as HINSTANCE, _
  byval szCmdLine as LPSTR, _
  byval iCmdShow as integer ) as integer

' начало программы
#define IDC_PROGRESS 1 ' идентификатор Progress Bar'а
#define IDC_STATUS 2 ' идентификатор Status Bar'а
#define IDC_TIMER 3 ' идентификатор таймера

#define ClassName "CommonControlWinClass" ' Имя нашего класса окна
#define AppName "Common Control Demo" ' Имя нашего окна
#define progressClass  "msctls_progress32" ' название класса Progress Bar'а
#define Message "Finished!"
dim shared hModule as HINSTANCE ' Хэндл нашей программы
dim shared hwndProgress as HANDLE ' хэндл Progress Bar'а
dim shared hwndStatus as HANDLE ' хэндл status Bar'а
dim shared CurrentStep as uInteger ' шаг Progress Bar'а
dim shared TimerID as uInteger ' идентификатор таймера
hModule = GetModuleHandle( NULL ) ' Взять хэндл программы
end WinMain( hModule,NULL,GetCommandLine(), SW_SHOWNORMAL ) ' вызвать основную функцию
InitCommonControls() ' инициализируем Common Control'ы
' здесь заканчивается программа

' процедура окна
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) ' выходим из программы
if TimerID <> 0 then
KillTimer _ ' удалим таймер
(hWnd, _ ' хэндл окна
TimerID) ' идентификатор таймера
end if
exit function
case WM_CREATE ' если сообщение WM_CREATE
hwndProgress  = CreateWindowEx _ ' создадим Progress Bar
(NULL, _ ' дополнительные стили
progressClass, _ ' класс Progress Bar'а
NULL, _ ' название окна
WS_CHILD+WS_VISIBLE, _ ' стиль окна
100, _ ' x
200, _ ' y
300, _ ' ширина
20, _ ' высота
hWnd, _ ' хэндл родительского окна
cptr(HMENU,IDC_PROGRESS), _ ' идентификатор Progress Bar'а
hModule, _ ' хэндл программы
NULL) ' указатель на структуру данных
CurrentStep = 1000 ' текущий шаг
SendMessage _ ' пошлем сообщение
(hwndProgress, _ ' хэндл Progress Bar'а
PBM_SETRANGE, _ ' установить диапазон
0, _
CurrentStep shl 16) ' максимальное значение диапазона
SendMessage _ ' пошлем сообщение
(hwndProgress, _ ' хэндл Progress Bar'а
pBM_SETSTEP, _ ' установить шаг в
10, _ ' шагов
0)
hwndStatus = CreateStatusWindow _ ' создадим status Bar
(WS_CHILD+WS_VISIBLE, _ ' стиль окна
NULL, _ ' указатель на строку
hWnd, _ ' хэндл родительского окна
IDC_STATUS) ' идентификатор status Bar'а
TimerID = SetTimer _ ' установим таймер
(hWnd, _ ' хэндл окна
IDC_TIMER, _ ' идентификатор таймера
100, _ ' число миллисекунд
NULL) ' будем использовать сообщения
case WM_TIMER ' если пришло сообщение от таймера
SendMessage _ ' пошлем сообщение
(hwndProgress, _ ' хэндл progress Bar'а
PBM_STEPIT, _ ' сделать шаг вверх
0,0)
CurrentStep -= 10
if CurrentStep = 0 then
    KillTimer _ ' удалим таймер
   (hWnd, _ ' хэндл окна
   TimerID) ' идентификатор таймера
TimerID = 0 ' запишем 0
SendMessage _ ' пошлем сообщение
(hwndStatus, _ ' хэндл Status Bar'а
SB_SETTEXT, _ ' _ ' установить текст
0, _
cPtr(LPARAM,Message)) ' строка с текстом
MessageBox(hWnd,Message,AppName,MB_OK+MB_ICONINFORMATION)
SendMessage _ ' пошлем сообщение
(hwndStatus, _ ' хэндл Status Bar'a
SB_SETTEXT, _
0, _
0) ' пустая строка
SendMessage _ ' пошлем сообщение
(hwndProgress, _ ' хэндл Progress Bar'а
PBM_SETPOS, _ ' установить позицию
0, _
0)
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 hWnd as HWND ' хэндл окна

 'структура класса окна wc
 ' заполняем структуру wc
wc.cbSize = SIZEOF( WNDCLASSEX )  ' размер структуры WNDCLASSEX
wc.style = CS_HREDRAW or CS_VREDRAW  ' Стиль окна
wc.lpfnWndProc = @WndProc ' Адрес процедуры окна WndProc
wc.cbClsExtra = NULL  ' резервирование  дополнительных байт за концом структуры
wc.cbWndExtra = NULL
wc.hInstance = hInst  ' хэндл модуля
wc.hbrBackground = cast(HGDIOBJ, COLOR_ApPWORKSPACE) ' Цвет фона
wc.lpszMenuName = NULL ' Хэндл меню
wc.lpszClassName = @ClassName ' класс окна
wc.hIcon = LoadIcon( NULL,IDI_APPLICATION ) ' Хэндл иконки
wc.hIconSm = wc.hIcon 'Хэндл маленькой иконки
wc.hCursor = LoadCursor( NULL,IDC_ARROW) ' Хэндл курсора


' регистрация нашего класса окна
if(RegisterClassEx(@wc) = FALSE) then
MessageBox(0,"Не могу зарегистрировать класс окна","Ошибка",0)
end 1
end if

' Создадим окно
hwnd = CreateWindowEx _
(WS_EX_CLIENTEDGE, _ ' дополнительные стили
@ClassName, _ ' указатель на строку с именем класса окна
@AppName, _ ' указатель на строку с именем окна
WS_OVERLAPPED+WS_CAPTION+WS_SYSMENU+WS_MINIMIZEBOX+WS_MAXIMIZEBOX+WS_VISIBLE, _ ' стиль окна
CW_USEDEFAULT, _ ' X
CW_USEDEFAULT, _ ' Y
CW_USEDEFAULT, _ ' ширина окна
CW_USEDEFAULT, _ ' высота окна
NULL, _ ' хэндл родительского окна
NULL, _ ' хэндл меню
hInst, _ ' хэндл модуля
NULL) ' указатель на структуру данных

while( GetMessage( @wMsg, NULL, 0, 0 ) <> FALSE )  'цикл сообщений
TranslateMessage( @wMsg )
DispatchMessage( @wMsg )
wend
function = wMsg.wParam
end function

Анализ:

end WinMain( hModule,NULL,GetCommandLine(), SW_SHOWNORMAL ) ' вызвать основную функцию
InitCommonControls()

Я специально поместил InitCommonControls после Exitprocess, чтобы продемонстрировать то, что эта функция необходима только для создания ссылки на comctl32.dll в секции импорта. Как вы можете видеть, common control'ы работают, даже если функция InitCommonControls не запускалась.

case WM_CREATE
hwndProgress  = CreateWindowEx _
(NULL, _
progressClass, _
NULL, _
WS_CHILD+WS_VISIBLE, _
100, _
200, _
300, _
20, _
hWnd, _
cptr(HMENU,IDC_PROGRESS), _
hModule, _
NULL)

Здесь мы создаем common control. Заметьте, что вызов CreateWindowEx содержит hWnd в качестве хэндла родительского окна. Он также задает ID контрола, для идентификации последнего. Тем не менее, так как у нас есть хэндл окна контрола, этот ID не используется. Все дочерние окна должны иметь стиль WS_CHILD.

CurrentStep = 1000
SendMessage _
(hwndProgress, _
PBM_SETRANGE, _
0, _
CurrentStep shl 16)
SendMessage _
(hwndProgress, _
pBM_SETSTEP, _
10, _
0)

После того, как создан progress bar, мы можем установить его диапазон. Диапазон по умолчанию равен от 0 до 100. Если это вас не устраивает, вы можете указать ваш собственный диапазон с помощью сообщения PBM_SETRANGE. lparam этого сообщения содержит диапазон, максимальное значение в верхнем слове и минимальное в нижнем. Вы также можете указать шаг, используя сообщение PBM_SETSTEP. Этот пример устанавливает его в 10, что означает то, что когда вы посылаете сообщение PBM_STEPIT прогресс бару, индикатор прогресса будет повышаться на 10. Вы также можете установить положение индикатора, послав сообщение PBM_SETPOS. Это сообщение дает вам полный контроль над Progress bar'ом.

hwndStatus = CreateStatusWindow _
(WS_CHILD+WS_VISIBLE, _
NULL, _
hWnd, _
IDC_STATUS)
TimerID = SetTimer _
(hWnd, _
IDC_TIMER, _
100, _
NULL)

Затем мы создаем status bar, вызывая CreateStatusWindow. Этот вызов легко понять, поэтому я не буду комментировать его. После того, как status window создан, мы создаем таймер. В этом примере мы будем обновлять progress bar каждые 100 ms, поэтому нам нужно создать таймер.
function SetTimer _
(byval hWnd  as HWND, _
byval TimerID  as UINT, _
byval TimerInterval  as UINT, _
byval lpTimeрProc  as TIMERPROC) as UINT

hWnd : хэндл родительского окна

TimerID : не равный нулю идентификатор таймера. Вы можете создать свой собственный идентификатор.

TimerInterval : временной интервал в миллисекундах, который должен пройти, прежде чем таймер вызовет процедуру таймер или пошлет сообщение WM_TIMER.

lpTimeрProc : адрес функции таймера, которая будет вызываться при истечении временного интервала. Если параметр равен нулю, таймер вместо этого будет посылать родительскому окну сообщение WM_TIMER.

Если вызов прошел успешно, функция возвратит TimerID. В противном случае, будет возвращен ноль. Вот почему идентификатор таймера не должен быть равен нулю.

case WM_TIMER
SendMessage _
(hwndProgress, _
PBM_STEPIT, _
0,0)
CurrentStep -= 10
if CurrentStep = 0 then
   KillTimer _
  (hWnd, _
  TimerID)
TimerID = 0
SendMessage _
(hwndStatus, _
SB_SETTEXT, _ ' _
0, _
cPtr(LPARAM,Message))
MessageBox(hWnd,Message,AppName,MB_OK+MB_ICONINFORMATION)
SendMessage _
(hwndStatus, _
SB_SETTEXT, _
0, _
0)
SendMessage _
(hwndProgress, _
PBM_SETPOS, _
0, _
0)
end if

Когда истекает указанный временной интервал, таймер посылает сообщение WM_TIMER. Вы можете поместить здесь свой код, который будет выполнен. В данном примере, мы обновляем Progress bar, а затем проверяем, было ли достигнуто максимальное значение. Если это так, мы убиваем таймер, после чего устанавливаем текст статус-окна с помощью сообщения SB_SETTEXT. Отображается message box, и когда юзер кликает OK, мы очищаем текст в status bar'е и progress bar'е.

[C] Iczelion, пер. Aquila.


Последний раз редактировалось: electrik (Вт Май 23, 2017 5:33 pm), всего редактировалось 1 раз(а)

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Re: платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 18 - Common Control'ы

Сообщение  electrik в Пн Июн 29, 2009 8:10 pm

Win32 API. Урок 18. Common Control'ы - дополнение от electrik'а

для подробного понимания данного урока, далее идут выдержки из различных источников.

Progress bar,индикатор выполнения.

Каждый раз, когда мы видим индикатор выполнения (Progress bar), мы знаем, что выполняется какой-то процесс. Если индикатор надолго остановился, мы думаем, что программа "зависла" и немедленно перезагружаем компьютер. Поэтому, от того, как вы будете управлять своим индикатором, зависит будет пользователь ждать выполнения процесса или зарекомендует вашу программу, как нерабочую. Наивно конечно думать, что индикатор - это самостоятельный элемент управления, который напрямую связан с событиями, происходящими в программе. На самом деле, это просто "мультик", призванный отвлечь пользователя от грустных мыслей, пока тянется какой-то процесс. Сама полоска индикации никаких сообщений не генерирует, зато охотно их принимает. И вот как это делается:

Сообщения ей передаёт знакомая функция:
function SendMessage (byval hWnd as HWND, byval messg as UINT, byval wParam as WPARAM, byval lParam as LPARAM) as LRESULT

Первый идентификатор hwndProgress- идентификатор окна полосы прокрутки. Поскольку мы создаём её не как ресурс, а создаём динамически, то используем для её создания функцию CreateWindow, следовательно, наша полоса является самым настоящим окном, которому можно посылать сообщения.

messg - сообщение. Оно может принимать значения:

PBM_SETPOS - Установка текущей позиции индикатора. wParam - значение новой позиции, lParam = 0.
PBM_SETRANGE - Установка диапазона значений. wParam = 0, а lParam содержит начальный и конечный диапазоны. Вот как это выглядит:

SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0,50)) ' диапазон от 0 до 50

PBM_SETSTEP - задаёт шаг изменения индикатора. wParam = шаг, lParam = 0.
PBM_STEPIT - заставляет индикатор сделать шаг вперёд, то есть закрасить заданное количество клеточек.

Макрокоманда MAKELPARAM создает значение для использования его в сообщении как параметр lParam. Макрокоманда соединяет заданные величины.

Синтаксис

LPARAM = MAKELPARAM(wLow,wHigh)

Параметры

wLow
Устанавливает младшее слово нового значения.
wHigh
Устанавливает старшее слово нового значения.

Возвращаемые значения
Возвращаемое значение - значение LPARAM.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения