68903

Скелет оконной программы

Лекция

Информатика, кибернетика и программирование

Функцию создания окна. Для его создания необходимо выполнить два шага: регистрацию класса окна и вызвать функцию создания окна. Оба этих действия определяют основные свойства видимые и невидимые характеристики окна.

Русский

2014-09-27

95.5 KB

0 чел.

Лекция 2 Скелет оконной программы

Вступление

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

Представьте себе автомобиль и его составные части. Внутри корпуса машины закреплены несколько независимых систем: управление (руль, система передачи, поворачиваемые колеса); двигатель, управляемый зажиганием, педалью акселератора, коробка распределения, ведущие колеса; тормозная система, электрооборудование и т.п. Все эти системы работают параллельно, и, в общем-то, независимо. Точно также проектируется и современная программа. В нее изначально закладываются составные элементы, которые, работая параллельно и обеспечивая реализацию специфической функции, в совокупности обеспечивают полноценное функционирование приложения в среде ОС WINDOWS.

Кроме того, программа под ОС должна выполнять ряд стандартных действий, которые позволяют полноценно "включить" ее в состав исполняемого программного обеспечения.

Рассмотрим эти шаги и составные части программ.

Четыре составные части программы под WINDOWS

Любое оконное приложение, написанное под Windows должно содержать в себе следующие элементы:

  1.  Функцию регистрации класса окна.
  2.  Функцию создания окна.
  3.  Оконную процедуру.
  4.  Цикл обработки сообщений.

Ранее уже говорилось, что большинство программ под WINDOWS должны иметь хотя бы одно окно. Для его создания необходимо выполнить два шага: регистрацию класса окна и вызвать функцию создания окна. Оба этих действия определяют основные свойства (видимые и невидимые характеристики) окна. Основное отличие первого шага от второго заключается в том, что на основе зарегистрированного класса окна можно создавать бесконечное число окон. Таким образом, при регистрации класса окна задаются свойства, общие (одинаковые) для всех последующих окон свойства. Функция создания окна создает очередной экземпляр окна, добавляя уже конкретные свойства окна, такие как положение на экране, размеры, содержание текста и т.п.

Регистрация окна проводится в два этапа. Во-первых, заполняется структура WNDCLASSEX (поля которой как раз и содержат общую информацию), после чего выполняется функция RegisterClassEx, в которую передается указатель на заполненную структуру. Ниже приведен фрагмент программы с комментариями к полям заполняемой структуры:

 

WNDCLASSEX wcex; // объявление переменной типа структура оконного класса

wcex.cbSize = sizeof(WNDCLASSEX); // размер структуры в байтах

wcex.style  = CS_HREDRAW | CS_VREDRAW; // стиль окна

wcex.lpfnWndProc = (WNDPROC)WndProc; //адрес оконной процедуры

wcex.cbClsExtra  = 0;      

wcex.cbWndExtra = 0;

wcex.hInstance  = hInstance;  // описатель приложения

wcex.hIcon  = MyIcon1;  // определение иконки

wcex.hCursor  = LoadCursor(NULL, IDC_ARROW); // определение курсора

wcex.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); // установка фона

wcex.lpszMenuName = NULL;  // определение меню

wcex.lpszClassName = "MyWindow"; // имя класса

wcex.hIconSm  = NULL; //определение маленькой иконки

  RegisterClassEx(&wcex); // регистрация класса окна

В дальнейшем, мы вернемся к рассмотрению отдельных полей структуры.

После того, как класс окна зарегистрирован, можно создавать окна, что выполняется следующим образом:

hWnd=CreateWindow(      "MyWindow", // имя класса окна

"Строка заголовка",   // имя приложения

WS_OVERLAPPEDWINDOW, // стиль окна

CW_USEDEFAULT, // положение по Х

CW_USEDEFAULT,  // положение по Y

CW_USEDEFAULT,    // размер по Х

CW_USEDEFAULT,    // размер по Y

NULL, // описатель родительского окна

NULL,       // описатель меню окна

hInstance,  // указатель приложения

NULL);     // параметры создания.

Функция CreateWindow возвращает описатель вновь созданного окна. Если возвращаемое значение равно NULL, это значит, что окно не было создано по какой-либо причине.

Чтобы созданное окно появилось на экране, необходимо выполнить последовательно две функции:

ShowWindow(hWnd, nCmdShow);  // Показать окно

UpdateWindow(hWnd);   // Обновить окно

Следующие важные элементы программы – это оконная процедура и цикл обработки сообщений. Адрес оконной процедуры использовался при регистрации класса окна (WndProc).  Для их рассмотрения сделаем небольшое отступление. В первой лекции обсуждался вопрос о событиях и сообщениях. Настало время более подробно рассмотреть этот вопрос.

Порядок обработки сообщений, цикл обработки сообщений

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

Рис. 2.1. Порядок прохождения сообщения

Сформированное операционной системой сообщение помещается в системную очередь сообщений. Каждое сообщение предназначено конкретному окну. ОС определяет какому приложению предназначено сообщение и помещает его в очередь сообщений программы. Далее программа сама должна заботиться об обработке сообщения.

Цикл обработки сообщения выбирает очередное сообщение из программной очереди и вызывает оконную процедуру (ОП) того окна, которому оно предназначено. Если программа в это время занята обработкой другого сообщения, вновь прибывшее сообщение ожидает в очереди завершения обработки предыдущего сообщения (это особенно заметно на медленных машинах, когда например, набранное слово на клавиатуре появляется на экране спустя некоторое время).

Стандартный цикл обработки сообщений имеет вид:

 MSG msg;

while (GetMessage(&msg, NULL, 0, 0))

{

  TranslateMessage(&msg);

  DispatchMessage(&msg);

}

Функция GetMessage выбирает очередное сообщение из программной очереди. Результатом выполнения функции является заполнение структуры msg, которая содержит всю необходимую информацию о полученном сообщении: описатель окна, которому предназначено сообщение, тип сообщения, параметры сообщения (зависящие от типа сообщения) и время возникновения сообщения. Функция также возвращает некоторое число, которое отлично от нуля для всех сообщений кроме сообщения о закрытии программы. В последнем случае цикл обработки сообщений прерывается и программа завершается.

Функция TranslateMessage преобразует сообщение в соответствии с системными настройками (например, преобразовывает код нажатой клавиши клавиатуры согласно выбранного в настоящее время языка).

Функция DispatchMessage определяет какому окну приложения послано сообщение и вызывает соответствующую оконную процедуру.

Оконная процедура

Оконная процедура является центральной частью программы. Не будет большим преувеличением сказать, что более девяносто процентов алгоритма программы заключено в оконной процедуре. Оконная процедура соответствует одному (или более)  окну программы и содержит в себе программную реализацию поведения окна. Подпрограммы рисования элементов окна, реакция на действия мыши, клавиатуры, закрытия окна – все это заключено внутри оконной процедуры.

Оконная процедура имеет стандартный вид:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

. . . . .

switch (message)

{

 case WM_CREATE: // Сообщение приходит при создании окна

  . . . . . . .

  break;

 case WM_PAINT:  // Перерисовать окно

  . . . . . . .

  break;

 case WM_DESTROY: // Завершение работы

  . . . . . . .

  break;

 default:

// Обработка сообщений, которые не обработаны пользователем

  return DefWindowProc(hWnd, message, wParam, lParam);

  }

return 0;

}

Оконная процедура вызывается только тогда, когда пришло какое-либо сообщение, предназначенное соответствующему окну. Обратите внимание, что оконная процедура задается в классе регистрации окна, то есть для нескольких окон существует только один экземпляр оконной процедуры. Какому именно окну послано сообщение определят первый параметр функции WndProc – описатель окна hWnd.

Второй параметр функции - message -определяет  тип сообщения и принимает одно значение из множества WM_<сообщение>. Например, когда message равно WM_CREATE, это означает, что пришло сообщение о создании окна (данное сообщение является первым сообщением, приходящим в оконную процедуру после создания окна и приходит только один раз).

Третий и четвертый параметры - wParam  и lParam сопутствуют сообщению и зависит от его типа. Например, если приходит сообщение о нажатии мыши, в этих параметрах содержится информация о координатах мыши в момент нажатия и состоянии управляющих клавиш.

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

В заключение лекции приведем полностью текст программы, которая является полноправным оконным приложением. В результате выполнения программы на экране появляется окно, содержащее стандартные элементы (заголовок, рамку, кнопки управления)  и надпись "Первая программа для WINDOWS".  Окно можно перемещать, минимизировать, максимизировать, свертывать. Можно также изменять его размеры с помощью мыши и наблюдать программу на панели задач.

#include <windows.h>         // подключение библиотеки с функциями API

// Глобальные переменные:

HINSTANCE hInst;  // Указатель приложения

// Предварительное описание функций

ATOM  MyRegisterClass(HINSTANCE hInstance);

BOOL  InitInstance(HINSTANCE, int);

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// Основная программа

int APIENTRY WinMain(HINSTANCE hInstance,  HINSTANCE hPrevInstance, LPSTR     lpCmdLine,

                    int       nCmdShow)

{

MSG msg;

// Регистрация класса окна

MyRegisterClass(hInstance);

// Создание окна приложения

if (!InitInstance (hInstance, nCmdShow))

{

 return FALSE;

}

// Цикл обработки сообщений

while (GetMessage(&msg, NULL, 0, 0))

{

  TranslateMessage(&msg);

  DispatchMessage(&msg);

}

return msg.wParam;

}

//  FUNCTION: MyRegisterClass()

//  Регистрирует класс окна

ATOM MyRegisterClass(HINSTANCE hInstance)

{

WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style  = CS_HREDRAW | CS_VREDRAW; // стиль окна

wcex.lpfnWndProc = (WNDPROC)WndProc; // оконная процедура

wcex.cbClsExtra  = 0;      

wcex.cbWndExtra = 0;

wcex.hInstance  = hInstance;  // указатель приложения

wcex.hIcon  = MyIcon1; // определение иконки

wcex.hCursor  = LoadCursor(NULL, IDC_ARROW);  // определение курсора

wcex.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); // установка фона

wcex.lpszMenuName = NULL;  // определение меню

wcex.lpszClassName = "MyClass"; // имя класса

wcex.hIconSm  = NULL;

return RegisterClassEx(&wcex); // регистрация класса окна

}

// FUNCTION: InitInstance(HANDLE, int)

// Создает окно приложения и сохраняет указатель приложения в переменной hInst

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

  HWND hWnd;

  hInst = hInstance; // сохраняет указатель приложения в переменной hInst

  hWnd=CreateWindow("MyClass", // имя класса окна

 "My first program",   // имя приложения

WS_OVERLAPPEDWINDOW, // стиль окна

CW_USEDEFAULT, // положение по Х

CW_USEDEFAULT,  // положение по Y

CW_USEDEFAULT,    // размер по Х

CW_USEDEFAULT,    // размер по Y

NULL, // описатель родительского окна

NULL,       // описатель меню окна

hInstance,  // указатель приложения

NULL);     // параметры создания.

  if (!hWnd) // Если окно не создалось, функция возвращает FALSE

  {

     return FALSE;

  }

  ShowWindow(hWnd, nCmdShow); // Показать окно

  UpdateWindow(hWnd);   // Обновить окно

  return TRUE;    //Успешное завершение функции

}

//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)

//  Оконная процедура. Принимает и обрабатывает все сообщения, приходящие в приложение

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

{

PAINTSTRUCT ps;

HDC hdc;

RECT rt;

switch (message)

{

 case WM_CREATE: // Сообщение приходит при создании окна

  break;

 case WM_PAINT:  // Перерисовать окно

  hdc = BeginPaint(hWnd, &ps); // Начать графический вывод

  GetClientRect(hWnd, &rt); // Область окна для рисования

  DrawText(hdc, " Первая программа для WINDOWS ", -1, &rt,

DT_SINGLELINE|DT_CENTER | DT_VCENTER);

   EndPaint(hWnd, &ps); // Закончить графический вывод

  break;

 case WM_DESTROY: // Завершение работы

   PostQuitMessage(0);

  break;

 default:

// Обработка сообщений, которые не обработаны пользователем

  return DefWindowProc(hWnd, message, wParam, lParam);

  }

return 0;

}


 

А также другие работы, которые могут Вас заинтересовать

64228. Органы чувств и сенсорные способности низших многоклеточных беспозвоночных 28 KB
  Предполагается что первичные органы чувств вообще обладали лишь общей присущей всей живой материи чувствительностью но в повышенной степени. Согласно приведённой гипотезе все органы чувств многоклеточных животных развились из наименее дифференцированных осязательных рецепторов.
64229. Общая характеристика моторной активности низших многоклеточных беспозвоночных 25.5 KB
  Большинство же червей ползают и роются в придонном иле проглатывая его вместе с органическими остатками или собирают с поверхности дна мелких животных и мёртвые организмы. У кольчатых червей впервые в эволюции животного мира появляются настоящие парные конечности...
64230. Таксисы у низших беспозвоночных 26 KB
  Кюн выделил следующие категории высших таксисов которые в полной мере развиты лишь у высших животных: тропотаксисы телотаксисы менотаксисы и мнемотаксисы. Низшим беспозвоночным свойственны в разной степени только первые три формы высших таксисов. Особенно значимы эти два вида таксисов для хищников.
64231. Характеристика моторной активности животных с низшим уровнем развития перцептивной психики (на примере насекомых) 24 KB
  Членистоногие являются первыми наземными животными в истории Земли. Переход на сушу был сопряжён с развитием особых органов передвижения – конечностей в виде сложных рычагов, состоящих из отдельных, соединённых суставами, члеников.
64232. Характеристика сенсорной активности животных с низшим уровнем развития перцептивной психики (на примере насекомых) 28 KB
  Дело в том что зрительные рецепторы у насекомых очень лабильны и за единицу времени у них формируется больше последовательных образов чем у позвоночных. Таким образом характеризуя способности насекомых также как и головоногих моллюсков к оптическому...
64233. Таксисы 24.5 KB
  Насекомые обладают всеми примитивными формами таксисов особенно на стадии личинок хемотаксисы фототаксисы клинотаксисы и так далее однако у взрослых насекомых чаще всего встречаются чётко выраженные высшие таксисы.
64234. Инстинкт и научение в поведении насекомых 26 KB
  Можно считать что научение у них стоит на службе у инстинктивного поведения обеспечивая пластичность инстинктивных действий. Неизменных форм поведения нет даже там где прежде всего требуется стереотипность а именно в сигнальных позах и телодвижениях.
64235. Общая характеристика высшего уровня развития перцептивной психики 25.5 KB
  Представители этих наиболее совершенных в эволюционном плане видов способны к предметному восприятию однако наиболее полно эта способность развита только у позвоночных.
64236. Характеристика двигательных способностей высших позвоночных 30 KB
  У высших позвоночных эта сегментарность уже нарушена что связано с выполнением сложных движений. В ходе эволюции наибольшие преимущества имели животные с разнообразными реакциями в том числе с большим набором элементарных двигательных координаций с лучшей дифференцированностью и точностью движений.