Интерфейс пользователя Оконный интерфейс Windows Desktop Window При






































![Пользовательский ввод Сообщения мыши Активность мыши в клиентской области окна WM_MOUSEMOVE WM_[L,R,M,X]BUTTONUP/WM_[L,R,M,X]BUTTONDOWN WM_[L,R,M,X]BUTTONDBLCLK Пользовательский ввод Сообщения мыши Активность мыши в клиентской области окна WM_MOUSEMOVE WM_[L,R,M,X]BUTTONUP/WM_[L,R,M,X]BUTTONDOWN WM_[L,R,M,X]BUTTONDBLCLK](https://present5.com/presentacii-2/20171211\22542-11_windows-1part.ppt\22542-11_windows-1part_39.jpg)

















22542-11_windows-1part.ppt
- Количество слайдов: 56
Интерфейс пользователя Оконный интерфейс Windows
Desktop Window При запуске Windows автоматически создаётся системное окно desktop window Это окно отображается как фон на экране Это окно служит базовым для всех остальных окон Получить дескриптор этого окна можно с помощью GetDesktopWindow()
Окно приложения Каждое графическое приложение создаёт минимум одно окно, называемое главным окном приложения Клиентская область Область, где приложение отображает информацию Не клиентская область Заголовок Меню Кнопки минимизации, максимизации, закрытия Рамка Полосы прокрутки Иконка Отображается системой
Диалоговые окна и control’ы Control – специальное окно, которое используется для отображения или ввода определённого фрагмента информации Кнопки Списки … Диалоговое окно – окно, в котором расположено несколько control’s. Как правило его не клиентская область устроена проще, чем главное окно приложения. Окно сообщений – специальный вид диалогового окна для отображения сообщений, создаётся функцией MessageBox()
Атрибуты окна Имя класса Имя окна Стиль окна Расширенный стиль Позиция Размер Окно родитель и окно владелец Дескриптор меню или идентификатор дочернего окна Идентификатор экземпляра приложения Пользовательский параметр Дескриптор окна
Атрибуты окна Класс окна Каждое окно принадлежит к какому-нибудь классу. Класс окна определяет его поведение. Один из главных параметров класса – оконная процедура, обрабатывающая сообщения Класс регистрируется функциями RegisterClass()/RegisterClassEx()
Атрибуты окна Стили Стили задают: Тип окна Наличие элементов не клиентской области Тип рамки Видимость окна Вид и функциональность control’ов
Атрибуты окна Окно родитель и окно хозяин Окно родитель: Задаёт координатную систему Дочернее окно перемещается при перемещении родителя Задаёт область отображения Дочернее окно не может отображаться за пределами родительского окна Окно владелец: Окно, которым владеют, отображается поверх окна-владельца Окно, которым владеют, прячется, когда прячется окно-владелец Окно, которым владеют, уничтожается когда уничтожается окно-владелец.
Типы окон Overlapped Окно верхнего уровня, у которого есть заголовок, рамка и клиентская область. WS_OVERLAPPED или WS_OVERLAPPEDWINDOW. Pop-up Окно верхнего уровня которого может не быть заголовка, обычно диалоговое окно. WS_POPUP. Child Дочернее окно. WS_CHILD Layered Полупрозрачные окна. WS_EX_LAYERED. Message-Only Не отображаются, только для получения сообщений. Создаётся как дочернее для окна HWND_MESSAGE.
Оконные сообщения Система передаёт окну информацию с помощью сообщений Сообщение обрабатывается функцией окна (определённой в классе окна) следующего вида: LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) hWnd – дескриптор окна message – тип сообщения wParam и lParam – параметры сообщения (зависят от типа)
Оконные сообщения Типы сообщений Системные сообщения (0x0000-0x03FF) Ввод с клавиатуры и мыши Создание и удаление окна Изменение состояния и параметров окна Запросы информации у окна Управление control’ами … Пользовательские сообщения (WM_USER=0х0400-0x7FFF) Могут использоваться для классов окон приложения Для приложений версии 4.0 предусмотрен дополнительный диапазон 0х8000-0хBFFF RegisterWindowMessage() позволяет регистрировать уникальные в рамках системы сообщения из диапазона 0хС000-0хFFFF
Оконные сообщения Цикл сообщений Сообщения передаются через очередь сообщений, которая создаётся для каждого потока приложения, который создавал окна. Поток должен извлекать сообщения из очереди (GetMessage()), и передавать их соответствующим окнам (DispatchMessage()). Необработанные сообщения функция окна передаёт функции DefWindowProg() которая обеспечивает обработку по умолчанию.
Оконные сообщения Отправка сообщений Сообщение окну отправляются функцией SendMessage: LRESULT SendMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) Если нам не важен код возврата можно воспользоваться PostMessage: BOOL PostMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Оконные сообщения Некоторые полезные сообщения WM_SIZE – изменён размер окна WM_PAINT – требуется отрисовать окно WM_MOUSEMOVE – движение мыши в окне WM_LBUTTONDOWN/WM_LBUTTONUP – щелчок левой кнопки мыши WM_RBUTTONDBLCLK – двойной щелчок правой кнопки WM_KEYDOWN/WM_KEYUP – нажатие и отпускание клавиши WM_CHAR – пользователь ввёл букву WM_COMMAND – активирована команда меню или control WM_NOTIFY – уведомление от control’ов
Создание окна Если создаём своё окно необходимо зарегистрировать класс вызвав RegisterClass()/RegisterClassEx() Для создания окна вызываем CreateWindow()/CreateWindowEx() Для главного окна вызываем ShowWindow() и UpdateWindow() для отображения окна. При создании окно получает сообщения WM_NCCREATE и WM_CREATE
Удаление окна Окно уничтожается вызовом функции DestroyWindow() Функция DestroyWindow(): Посылает сообщение WM_DESTROY и окну, а затем его потомкам Уничтожает потомков и само окно Последнее получаемое окном сообщение – WM_NCDESTROY. Для выхода из программы (цикла обработки сообщений) при уничтожении главного окна нужно вызвать PostQuitMessage().
Пример Регистрация класса bool RegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)My_WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_MY_ICON); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (LPCTSTR)IDC_MY_MENU; wcex.lpszClassName = “My_Win_Class"; wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); return RegisterClassEx(&wcex)!=0; }
Пример Cоздание главного окна HWND CreateMainWindow(HINSTANCE hInstance, int nCmdShow) { HWND _hWnd = CreateWindow(“My_Win_Class",“MyWindow", WS_OVERLAPPED|WS_CAPTION, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!_hWnd) { return 0; } ShowWindow(_hWnd, nCmdShow); UpdateWindow(_hWnd); return _hWnd; }
Пример Функция WinMain int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; HWND MainWnd; if(!RegisterClass(hInstance)) return FALSE; if((MainWnd=CreateMainWindow(hInstance,nCmdShow))==NULL) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; }
Пример Функция окна LRESULT CALLBACK My_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: if (LOWORD(wParam)==IDM_EXIT) { DestroyWindow(hWnd); return TRUE; } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); FillRect(dc,&ps.rcPaint,(HBRUSH)GetStockObject(WHITE_BRUSH)); EndPaint(hWnd, &ps); return TRUE; case WM_DESTROY: PostQuitMessage(0); return TRUE; } return DefWindowProc(hWnd, message, wParam, lParam); }
Диалоговые окна / Dialog Box Используются для: Запроса дополнительной информации у пользователя Отображение информации/ввод опций пока пользователь работает в другом окне Типы: Модальные диалоговые окна Немодальные диалоговые окна
Диалоговые окна Общие свойства Автоматически создаются Windows вместе с дочерними окнами на основе заданного шаблона – ресурса Автоматически обеспечивают обработку дополнительных команд с клавиатуры (переход между control’ами) Имеются стандартные диалоговые окна: Открытие/сохранение файлов Печать Выбор цвета Выбор шрифта Вывод сообщений …
Диалоговые окна Модальные диалоговые окна Создаётся для ввода параметров без возможности работать с другими окнами приложения Должно быть окном верхнего уровня (pop-up) При создании становится активным окном и остаётся таким до завершения работы Автоматически отключается (disable) окно-владелец и все его дети, и соответственно они не получают ввода пользователя Сообщения обрабатываются в специальном цикле сообщений.
Диалоговые окна Немодальные диалоговые окна Создаётся для одновременной работы с другими окнами приложения Должно быть окном верхнего уровня (pop-up) При создании становится активным окном, но в процессе работы может стать не активным Не отключает окно-владельца За обработку сообщений отвечает приложение. Приложение должно закрыть все немодальные диалоговые окна перед выходом.
Модальные диалоговые окна Работа с окном Создаётся шаблон в редакторе ресурсов Разрабатывается функция диалогового окна Окно создаётся функциями INT_PTR DialogBox(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc); или INT_PTR DialogBoxParam(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam ); Для завершения работы окна вызывается функция BOOL EndDialog( HWND hDlg, INT_PTR nResult ); Код возврата, переданный EndDialog, возвращается функцией DialogBox/DialogBoxParam
Немодальные диалоговые окна Работа с окном Создаётся шаблон в редакторе ресурсов Разрабатывается функция диалогового окна Окно создаётся функциями HWND CreateDialog(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc); или HWND CreateDialogParam(HINSTANCE hInstance, LPCTSTR lpTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam ); Для корректной работы окна в цикле обработки сообщений необходимо вызывать функцию BOOL IsDialogMessage( HWND hDlg, LPMSG lpMsg); Окно уничтожается BOOL DestroyWindow(HWND hDlg)
Диалоговые окна Функция окна BOOL CALLBACK DlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) Обрабатывает сообщения, адресованные диалоговому окну, например: WM_INITDIALOG Посылается после создания диалогового окна и всех контролов WM_COMMAND Посылается окну контролами, когда пользователь выполняет над ними действие (нажимает на кнопку, …) Для необработанных сообщений возвращаем FALSE
Диалоговые окна Функции для работы с контролами Вместо дескриптора используется идентификатор дочернего окна, назначаемый в редакторе ресурсов. Получить дескриптор дочернего окна HWND GetDlgItem( HWND hDlg, int nIDDlgItem); Установить/получить текст окна BOOL SetDlgItemText( HWND hDlg, box int nIDDlgItem, LPCTSTR lpString); UINT GetDlgItemText( HWND hDlg, box int nIDDlgItem, LPTSTR lpString, int nMaxCount); Установить/получить состояние кнопки BOOL CheckDlgButton( HWND hDlg, int nIDButton, UINT uCheck); UINT IsDlgButtonChecked( HWND hDlg, int nIDButton);
Пример Диалоговое окно IDOK IDCANCEL IDC_EDIT1 IDD_DIALOG
Пример – модальный диалог Функция окна BOOL CALLBACK My_DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { bool ok; int val; switch (message) { case WM_INITDIALOG: SetDlgItemInt(hDlg,IDC_EDIT1,100,false); return TRUE; case WM_COMMAND: if (LOWORD(wParam)==IDOK) { val=GetDlgItemInt(hDlg,IDC_EDIT1,&ok,false); if(ok) EndDialog(hDlg,val); else MessageBeep(0xFFFFFFFF); } else if (LOWORD(wParam)==IDCANCEL) EndDialog(hDlg,-1); return TRUE; default: return FALSE; } }
Пример – модальный диалог Использование диалогового окна int val; val=DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG),hMainWnd, My_DlgProc); if(val>0) { // пользователь ввёл число } else { // нажата кнопка отмена }
Пример – не модальный диалог Функция окна BOOL CALLBACK My_DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { char str[100]; switch (message) { case WM_INITDIALOG: SetDlgItemText(hDlg,IDC_EDIT1,(char *)lParam); return TRUE; case WM_COMMAND: if (LOWORD(wParam)==IDOK) { GetDlgItemText(hDlg,IDC_EDIT1,str,99); SendMessage(hMainWnd,WM_USER,0,(LPARAM)str); } if(LOWORD(wParam)==IDCANCEL) DestroyWindow(hDlg); default: return FALSE; } }
Пример – не модальный диалог Создание и цикл сообщений … HWND hDlg=CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG), hMainWnd, My_DlgProc, (LPARAM)“Default Text”); … MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { if(!IsDialogMessage(hDlg,&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
Пользовательский ввод
Пользовательский ввод Модель ввода с клавиатуры При нажатии на клавишу клавиатура генерирует два скан-кода: при нажатии и отпускании клавиши Драйвер клавиатуры транслирует скан-коды в виртуальный код клавиши. Сообщение, включающее скан-код, виртуальный код и другую информацию помещается в системную очередь ввода Из системной очереди сообщение перемещается в очередь одного из приложений Цикл сообщений приложения извлекает сообщение из очереди и передаёт его на обработку окну
Пользовательский ввод Фокус клавиатуры Фокус – временное свойство окна, которое определяет какому окну передаются сообщения о клавиатурном вводе Окно, которое обладает фокусом это либо активное окно, либо потомок активного окна Узнать/установить фокус можно функциями: HWND GetFocus(VOID); HWND SetFocus(VOID); Система уведомляет окна об изменении фокуса сообщениями WM_KILLFOCUS WM_SETFOCUS
Пользовательский ввод Виды сообщений клавиатуры Нажатие на системные клавиши (нажат ALT) WM_SYSKEYDOWN WM_SYSKEYUP Cодержат виртуальный код, скан-код, счётчик повтора,… Нажатие на обычные клавиши WM_KEYDOWN WM_KEYUP Cодержат виртуальный код, скан-код, счётчик повтора,… Символьные сообщения WM_SYSCHAR WM_CHAR Генерируются функцией TranslateMessage. Содержат код символа, скан-код, счётчик повтора,…
Пользовательский ввод Состояние клавиш Как узнать, нажат ли shift, ctrl, ещё какие-то клавиши? Во время генерации обрабатываемого сообщения: SHORT GetKeyState( int nVirtKey // virtual-key code ); Сейчас: SHORT GetAsyncKeyState( int vKey // virtual-key code );
Пользовательский ввод Сообщения мыши Активность мыши в клиентской области окна WM_MOUSEMOVE WM_[L,R,M,X]BUTTONUP/WM_[L,R,M,X]BUTTONDOWN WM_[L,R,M,X]BUTTONDBLCLK Активность мыши в неклиентской области окна WM_NCMOUSEMOVE WM_NC[L,R,M,X]BUTTONUP/WM_NC[L,R,M,X]BUTTONDOWN Сообщение WM_NCHITTEST Отправляется системой при каждом действии мыши, для определения области окна, в которой находится мышь. Обрабатывается DefWindowProc. Колесо прокрутки WM_MOUSEWHEEL
Пользовательский ввод Захват мыши Обычно система отправляет сообщения о перемещении мыши тому окну, над которым находится указатель. Можно заставить систему направлять сообщения всегда одному окну с помощью HWND SetCapture( HWND hWnd ); Отказаться от этого режима можно вызвав BOOL ReleaseCapture(VOID); Только активное окно может захватить мышь
Графика в окнах
Графика в окнах За рисование в окнах отвечает модуль GDI Рисовать мы можем только на графическом контексте. Контексты бывают Для окна Для принтера Для рисования на битмапе в памяти Стили рисования задаются специальными объектами Pen Brush Font
Графический контекст для рисования в окне Контекст для рисования в клиентской области HDC GetDC( HWND hWnd); Контекст для рисования во всём окне HDC GetWindowDC( HWND hWnd); Освобождение контекста int ReleaseDC( HWND hWnd, HDC hDC); Внутри обработчика WM_PAINT обязательно использовать: Для получения контекста HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lpPaint); Для освобождения контекста HDC EndPaint( HWND hwnd, CONST PAINTSTRUCT *lpPaint);
Стили линий и контуров Стиль линий и контуров задаётся объектом Pen HPEN CreatePen( int fnPenStyle, // pen style (PS_SOLID,PS_DOT,…) int nWidth, // pen width COLORREF crColor // pen color RGB(red,green,blue) ); Для активации стиля его нужно «выбрать»: HGDIOBJ SelectObject( HDC hdc, // handle to DC HGDIOBJ hgdiobj // handle to object ); После использования стиль нужно удалить BOOL DeleteObject( HGDIOBJ hObject // handle to graphic object );
Стили заливки Стиль линий и контуров задаётся объектом Brush HBRUSH CreateSolidBrush( COLORREF crColor // brush color value ); HBRUSH CreateHatchBrush( int fnStyle, // hatch style COLORREF clrref // foreground color ); HBRUSH CreatePatternBrush( HBITMAP hbmp // handle to bitmap ); …
Стандартные стили и цвета Стандартные стили HGDIOBJ GetStockObject( int fnObject); BLACK_BRUSH, DKGRAY_BRUSH, GRAY_BRUSH, LTGRAY_BRUSH, WHITE_BRUSH, NULL_BRUSH BLACK_PEN, WHITE_PEN, … Системные цвета DWORD GetSysColor( int nIndex); COLOR_3DDKSHADOW, COLOR_ACTIVEBORDER,… Системные кисти HBRUSH GetSysColorBrush( int nIndex);
Система координат По умолчанию начало координат в верхнем левом углу ось x направлена направо ось у направлена вниз единица измерения соответствует 1 пикселю Могут быть заданы другие координатные системы, имеющие другую ориентацию осей, масштабы,… Преобразование координат происходит в три этапа Пользовательская СК в СК страницы СК страницы в СК устройства СК устройства в физическую СК
Функции рисования Линии BOOL MoveToEx( HDC hdc, int X, int Y, LPPOINT lpOldPos); BOOL LineTo( HDC hdc, int nXEnd, int nYEnd); Прямоугольники int FillRect( HDC hDC, CONST RECT *lprc, HBRUSH hbr); BOOL RoundRect( HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidth, int nHeight); Эллипсы BOOL Ellipse( HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); …
Текст и шрифты Стиль шрифта задаётся объектом Font, создаваемым функцией CreateFont(). Цвет текста и фона COLORREF SetTextColor( HDC hdc, COLORREF crColor); COLORREF SetBkColor( HDC hdc, COLORREF crColor); Выравнивание UINT SetTextAlign( HDC hdc, UINT fMode); TA_TOP, TA_BOTTOM, TA_LEFT,TA_RIGHT,… Вывод BOOL TextOut( HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString); BOOL ExtTextOut …
Порядок перерисовки окна Порядок поступления сообщений: WM_ERASEBACKGORUND По умолчанию обрабатывается DefWindowProc, которая закрашивает всю клиентскую область цветом фона, указанным при регистрации класса окна. WM_PAINT Обрабатывается только функцией окна пользователя. Необходимо использовать BeginPaint и EndPaint для того, чтобы Windows могла обновить информацию о корректно отрисованных областях окна. Такая двухуровневая схема приводит к мерцанию изображения в окне при перерисовке
Как избавиться от мерцания? Надо рисовать всё в одном месте: Перехватить WM_ERASEBACKGORUND и ничего не делать, всё рисовать (включая фон) при обработке WM_PAINT. Ничего не рисовать в обработке WM_PAINT, всё рисовать в обработчике WM_ERASEBACKGORUND. Мерцание может сохраниться, так как мы всё равно как правило сначала «стираем» фон, а затем рисуем на нём текст, линии,… Также может потребоваться рисование перекрывающихся объектов. От этого спасет только двойная буферизация
Двойная буферизация Создаём графический контекст для памяти Создаём битмап размером с нашу клиентскую область (или картинку) и выбираем его в созданный контекст Долго рисуем на этом контексте сложную картинку - пользователь этого не видит Копируем получившееся изображение на графический контекст окна – вся картинка появляется единовременно Если изменений не было, то мы можем использовать готовую картинку в обработчике WM_PAINT / WM_ERASEBACKGROUND Небольшие динамические вещи (выделение объектов, отслеживание мыши) можно рисовать «обычным» способом после копирования или через второй буфер. В обработчике WM_SIZE (изменение размеров окна) пересоздаём битмап правильного размера
Двойная буферизация Создаём графический контекст для памяти HDC CreateCompatibleDC( HDC hdc); // hdc=NULL Создаём битмап размером с нашу клиентскую область (или картинку) HBITMAP CreateCompatibleBitmap( HDC hdc, int nWidth, int nHeight); HBITMAP CreateDIBSection(…); - если нам нужен прямой доступ к памяти изображения и выбираем его в созданный контекст HGDIOBJ SelectObject( HDC hdc, HGDIOBJ hgdiobj); Копируем получившееся изображение на графический контекст окна BOOL BitBlt( … ); BOOL StretchBLT( … ); …
Очереди сообщений
Очереди сообщений Очередь сообщений создаётся для каждого потока, который использует функции USER или GDI Способы помещения сообщений в очередь: Post Send Как поместить сообщение в очередь, не указывая окно В очередь своего потока - задать NULL вместо идентификатора окна Использовать PostThreadMessage(). Широковещательная передача Указать HWND_BROADCAST – всем окнам верхнего уровня BroadcastSystemMessage – можно указать получателей (драйвера,...) Некоторые сообщения доставляются напрямую процедуре окна
Очереди сообщений Порядок извлечения сообщений Отправленные Send Отправленные Post Сообщения аппаратного ввода и внутренние системные сообщения Отправленные Send WM_PAINT – если было несколько, объединяются; остаются в очереди пока не будут обработаны. WM_TIMER

