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;

}


 

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

53774. Малювання композиції Дерева у лісі 656 KB
  Провести бесіду В художникаграфіка; розвивати умінняспостерігати і виявляти особливості будови дерев різних порід; ознайомити звиразними особливостями ліній різної товщини навчити прийомам роботи зпаличкою пензлем пером або восковими крейдами на вибір учителя ітушшю; формувати уміння заповнювати зображенням усю площину аркушапаперу; виховувати любов до рідної природи дбайливе ставлення до матеріалівта інструментів акуратність під час роботи з тушшю;...
53775. Дієслова майбутнього часу 65.5 KB
  Життя прожити не поле перейти Хочеш знати не соромся питати Гарно того вчити хто хоче все знати Щоб довго жити треба працю любити Знайдіть дієслова в неозначеній формі. Чи можна визначити за цими дієсловами коли відбулася дія і хто її виконує Чому Не можна бо неозначена форма дієслова не вказує ні на час ні на особу 2. Запитання вчителя : Що називається дієсловом Частина мови що означає дію предмета і відповідає на питання що робити Що робив Що зробив Що робить Що зробить Що буде робити Яким...
53776. Підготовка до творчої роботи. «Мій улюблений герой казки» 58.5 KB
  Мій улюблений герой казки. Мій улюблений герой казки. Що складає основний зміст більшості казок В основі казки захоплива розповідь про вигадані події і явища які сприймаються і переживаються як реальні. Які різновиди казок ви знаєте Казки про тварин фантастичні побутові...
53777. Розвиток національного театру («Березіль» Леся Курбаса та Харківський театр ім. І.Франка). Пєси В.Винниченка, М.Куліша, І. Дніпровського, І. Кочерги 104.5 KB
  Антоніна Куліш дружина митця у своїх мемуарах Спогади про Миколу Куліша завершених у 1953 році у Філадельфії детально виклала один із драматичних моментів його дитячих літ записаний зі слів письменника що засвідчує що мати його неодноразово била за брехню та інші провини. Чаплинські інтелігенти особливо енергійний шкільний вчитель Володимир Пилипович Губенко...
53778. Групи слів за значенням. Омоніми 103 KB
  Мета: поглибити знання учнів набуті у молодшій школі; навчити пятикласників знаходити в тексті омоніми; сприяти виробленню вмінь та навичок правильно використовувати різні за значенням групи слів в усному та писемному монологічному і діалогічному мовленні; за допомогою вправ різнотипного характеру розвивати творчі здібності логічне й образне мислення та мовлення спостережливість пам'ять логіку викладу думокуміння аналізувати експериментувати досліджувати й порівнювати мовний матеріал робити правильні...
53779. Незмінювані іменники 39.5 KB
  Мета: поглибити знання учнів про незмінювані іменники навчити визначати в них рід розвивати вміння вживати незмінювані іменники у звязному мовленні розвивати творче мислення виховувати бажання збагачувати свій лексикон. Лінгвістичний двобій Двоє учнів по черзі ставлять підготовлені вдома питання Яка частина мови називається іменником За чим змінюється іменник Як визначити рід іменника Які іменники належать до власних назв Як пишуться власні назви До якого роду належать назви осіб за професією чи...
53780. Общее укрепление мышечного тонуса, саморазвитие. Воспитание здоровой личности 96.5 KB
  Спина прямая руки прямые по возможности наклоны головы выполняем плавно дыхание ровное.сидя стоя на коленях на вдохе поднять руки вверх на выдохе опустить. 46 раз Следим за осанкой вдох должен быть глубоким руки опускаем плавно вниз выдох удлиненный с одновременным произнесением звуков.
53781. Решение задач. Поиск «лишнего» предмета в группе предметов 788.5 KB
  ЦЕЛЬ: повторить изученное; развивать у учеников внимание, логическое мышление, умение находить общие признаки для группы предметов, лишний предмет в группе предметов; продолжать формировать навыки работы с компьютером.
53782. Общий случай вычитания двузначных чисел с переходом через десяток. Решение задач 196 KB
  ОБОРУДОВАНИЕ: предметные рисунки с изображением сливы яблока и груши; сверток бумаги в виде указа; карта математической страны; аудиозапись сказки О рыбаке и рыбке; картинки с изображением Буратино Незнайки и Знайки совы. Буратино Показ предметного рисунка с изображением Буратино Правильно это Буратино а из какой он сказки Приключение Буратино Сейчас мы узнаем почему он плачет. Буратино потянулся Раз нагнулся два нагнулся Руки в стороны развел Видно ключик не нашел. Оказывается Буратино не может открыть тайную дверь.