Лекция 3. Создание форм

При изменении размеров родительского окна в дочернее поступает сообщение WM_PAINT, по которому в переменной R формируются размеры родительского окна и при помощи функции MoveWindow(hWndC, R.left, R.bottom-iHeight, R.right, R.bottom-iHeight, 1) дочернему окну выделяется нижняя часть родительского окна.

BOOL PostMessage(

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

HWND hWnd,

UINT Msg,

WPARAM wParam,

LPARAM lParam

);

Если вводимый символ не является символьным кодом виртуальной клавиши Enter и количество введённых символов меньше 21, то оконная функция ChldWndProc дочернего окна записывает символы в буфер Password при помощи указателя Str.

После этого выполняется функция InvalidateRect() для порождения сообщения WM_PAINT, которое придет в дочернее окно и обновит отображаемую в нем строку.

10) Основное окно получает сообщение WM_CОMMAND и по значению идентификатора в LОWОRD(wParam) определяет, что оно пришло не от меню, а от дочернего окна, и вызывает функцию обработки пароля OnChild(), передавая ей в качестве второго параметра код извещения. Соответствующий фрагмент кода приведен в листинге:

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_EXIT:

DestroyWindow(hWnd);

break;

case NumC:

OnChld(hWnd,message,HIWORD(wParam),lParam); // Обработка пароля

break;

default:

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

}

break;

11) Код функции обработки пароля приведён в листинге:

void OnChld(HWND hWnd,UINT message,int Length,LPARAM lParam)

{

if(strcmp(PassWord,TruePassWord)||Length)

MessageBox(hWnd, "Надо вспомнить правильный пароль","Скажи \"Пароль\"",0);

else MessageBox(hWnd, "Пароль принят","",0);

}

На основе сравнения строк и проверки длины введенного пароля функция принимает решение о приеме пароля и отображает соответствующее сообщение при помощи функции MessageBox().


15) Создание дочернего окна с дескриптором Chld оформлено отдельной функцией.

BOOL CreateChild(HWND hWnd)

{static WNDCLASS wc;

if(Chld) //Стандартный для WINDOWS прием - чтобы не думать, о

// действиях при попытке нового ввода до завершения предыдущего

DestroyWindow(Chld);

UnregisterClass("ReadStr",GetModuleHandle(NULL));

// Раз было окно, значит был и класс

// Если класс не убрать, получится ошибка при новой регистрации

}

wc.hInstance = GetModuleHandle(NULL);

wc.hbrBackground =(HBRUSH)(COLOR_BTNFACE+1);

wc.lpfnWndProc = ChldWndProc;

wc.lpszClassName = "ReadStr";

if (!RegisterClass(&wc)) return 0;

Chld=0;

Chld=CreateWindowEx (WS_EX_CLIENTEDGE, "ReadStr",

"Значения ", WS_CHILD|WS_VISIBLE, 30,30,60,60,

hWnd, HMENU(NumC),GetModuleHandle(NULL), NULL);

SetFocus(Chld);

return (int)Chld;

}

После первого щелчка в рабочей области родительского окна левой кнопкой мыши и до завершения ввода пароля дескриптор Chld не будет равен нулю. При повторном вызове функции CreateChild (то есть при повторной активизации левой кнопки мыши в клиентской области родительского окна) уничтожается дочернее окно и отменяется регистрация класса.


Пример №1: Создания главного окна с дочерним окном для ввода пароля.

#include "stdafx.h"

#include "resource.h"

#define MAX_LOADSTRING 100

// Global Variables:

HINSTANCE hInst; // current instance

TCHAR szTitle[MAX_LOADSTRING]; // The title bar text

TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text

static TCHAR PassWord[7]; //введенный пользователем пароль

static TCHAR TruePassWord[]=_T("Password"); //Правильный пароль

static HWND Chld;

static WORD i;

static TCHAR *Str=NULL;

static int sMax;

int wHeight=30; //Высота дочернего окна

static TCHAR Sym[80];

// Foward declarations of functions included in this code module:

ATOM MyRegisterClass(HINSTANCE hInstance);

BOOL InitInstance(HINSTANCE, int);

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

BOOL CreateChild(HWND hWnd);

void InitStr(HWND hWnd,TCHAR *s,int Max,TCHAR Sy);

void OnChld(HWND hWnd,UINT message,int Length,LPARAM lParam);

LRESULT APIENTRY ChldWndProc (HWND UkOkn,UINT message, WPARAM wParam,LPARAM lParam);

int APIENTRY WinMain(HINSTANCE hInstance,

HINSTANCE hPrevInstance,

LPSTR lpCmdLine,

int nCmdShow)

{

UNREFERENCED_PARAMETER(hPrevInstance);

UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: Place code here.

MSG msg;

HACCEL hAccelTable;

// Initialize global strings

LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);

LoadString(hInstance, IDC_CHILD_WINDOW, szWindowClass, MAX_LOADSTRING);

MyRegisterClass(hInstance);

// Perform application initialization:

if (!InitInstance (hInstance, nCmdShow))

{

return FALSE;

}

hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_CHILD_WINDOW);

// Main message loop:

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

{

if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

return msg.wParam;

}

LRESULT APIENTRY ChldWndProc(HWND hWndC,UINT message,WPARAM wParam,LPARAM lParam)

{ RECT R;

switch (message)

{

case WM_CHAR:

if (LOWORD(wParam)==VK_RETURN || i>=20)

{

Str[i]=0;

PostMessage(GetParent(hWndC),WM_COMMAND,MAKELONG(NumC, i-sMax),0);

i=0;

DestroyWindow(hWndC);

UnregisterClass(_T("ReadStr"),GetModuleHandle(NULL));

}

else

{

if(++i<=sMax)

Str[i-1]=(char)LOWORD(wParam);

InvalidateRect(hWndC,NULL,1);

}

break;

case WM_PAINT:

{PAINTSTRUCT ps;

GetClientRect(GetParent(hWndC),&R);

MoveWindow(hWndC,R.left,R.top,R.right,R.top+wHeight,1);

BeginPaint(hWndC,&ps);

SetBkMode(ps.hdc, TRANSPARENT);

TextOut(ps.hdc,0,0,_T("Введите пароль: "),14);

TextOut(ps.hdc,17*8,0,Sym,i);

EndPaint(hWndC,&ps);

}

return 0;

default:

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

}

return 0;

}

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 = LoadIcon(hInstance, (LPCTSTR)IDI_CHILD_WINDOW);

wcex.hCursor = LoadCursor(NULL, IDC_ARROW);

wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wcex.lpszMenuName = (LPCWSTR)IDC_CHILD_WINDOW;

wcex.lpszClassName = szWindowClass;

wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

return RegisterClassEx(&wcex);

}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)

{

HWND hWnd;

hInst = hInstance; // Store instance handle in our global variable

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,

400, 300, 500, 500, NULL, NULL, hInstance, NULL);

if (!hWnd)

{

return FALSE;

}

ShowWindow(hWnd, nCmdShow);

UpdateWindow(hWnd);

return TRUE;

}

void OnChld(HWND hWnd,UINT message,int Length,LPARAM lParam)

{

if(_tcscmp(PassWord,TruePassWord)||Length)

MessageBox(hWnd, _T("Надо вспомнить правильный пароль"),_T("Скажи \"Пароль\""),0);

else MessageBox(hWnd, _T(" Пароль принят"),_T(""),0);

}

BOOL CreateChild(HWND hWnd)

{static WNDCLASS wc;

if(Chld) //Стандартный для WINDOWS прием - чтобы не думать, о действих при

{ //попытке нового ввода до завершения

DestroyWindow(Chld); // предыдущего.

UnregisterClass(_T("ReadStr"),GetModuleHandle(NULL));

// Раз было окно, значит,был и класс

// Если класс не убрать, получится ошибка при новой регистрации

}

wc.hInstance = GetModuleHandle(NULL);

wc.hbrBackground =(HBRUSH)(COLOR_BTNFACE+1);

wc.lpfnWndProc = ChldWndProc;

wc.lpszClassName = _T("ReadStr");

if (!RegisterClass(&wc)) return 0;

Chld=0;

Chld=CreateWindowEx

(WS_EX_CLIENTEDGE, _T("ReadStr"), _T(" Значения "),

WS_CHILD|WS_VISIBLE,

30,30,60,60,

hWnd, HMENU(NumC),GetModuleHandle(NULL), NULL);

SetFocus(Chld);

return (int)Chld;

}

void InitStr(HWND hWnd,TCHAR *s,int Max,TCHAR Sy)

{

Str=s;

sMax=Max;

int j;

for (j=0; j<21;j++)Sym[j]=Sy;

Sym[j]=0;

CreateChild(hWnd);

}

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

{

int wmId, wmEvent;

TCHAR szHello[MAX_LOADSTRING];

LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING);

switch (message)

{

case WM_COMMAND:

wmId = LOWORD(wParam);

wmEvent = HIWORD(wParam);

// Parse the menu selections:

switch (wmId)

{

case IDM_EXIT:

DestroyWindow(hWnd);

break;

case NumC:

OnChld(hWnd,message,HIWORD(wParam),lParam); // Обработка пароля

break;

default:

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

}

break;

case WM_LBUTTONDOWN:

InitStr(hWnd,PassWord,8,_T('*'));

break;

case WM_DESTROY:

PostQuitMessage(0);

break;

default:

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

}

return 0;

}


Пример 2: Окно приложения стиля временного окна с кнопкой минимизации и с фоном цвета рабочего стола Windows занимает весь экран. При попытке запустить второй экземпляр приложения на передний план перемещается окно первого экземпляра и завершается работа.

Шаг 1)

Для поиска приложения используется функция FindWindow:

HWND hwnd= FindWindow(szMainClass,szTitle);

Данная функция возвращает дескриптор окна класса szMainClass с заголовком szTitle. Если такого окна нет, то это первый экземпляр приложения и дескриптору hwnd присваивается NULL. Иначе возвращается дескриптор найденного окна.

Если работает экземпляр другого приложения с окном класса с таким же именем szMainClass и заголовком szTitle, то данная функция вернёт дескриптор окна другого приложения иначе переходим к шагу 5.

Шаг 2)

Если «предыдущий экземпляр приложения» обнаружен, то выводим сообщение:

MessageBox(hwnd,”Можно запускать только одну копию приложения!!!\n\n”

“Перемещаю на передний план первый экземпляр”,

szTitle,MB_OK);

Шаг 3)

До перемещения окна на передний план необходимо проверить состояние этого окна и, если оно свёрнуто, то восстанавливаем его предыдущее состояние:

If(IsIconic(hwnd)) ShowWindow(hwnd,SW_RESTORE);

SW_RESTORE - активизирует и отображает окно. Если окно минимизировано или развернуто, Windows восстанавливает его в первоначальном размере и позиции (то же самое, что и SW_SHOWNORMAL).


Шаг 4)

Перемещаем окно первого экземпляра на передний план:

SetForegroundWindow(hwnd);

Затем второй экземпляр приложения завершает работу.

Шаг 5)

В случае, если предыдущий экземпляр приложения не найден, то регистрируем класс окна:

if (!RegClass(WndProc,szMainClass,COLOR_DESKTOP))

return FALSE;

Шаг 6)

Для создания максимально распахнутого окна приложения необходимо определить ширину и высоту экрана в пикселях:

int w=GetSystemMetrics(SM_CXSCREEN);

int h=GetSystemMetrics(SM_CYSCREEN);

Шаг 7)

Создаём окно:

Hwnd=CreateWindow(szMainClass,szTitle,WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE,0,0,w,h,0,0,hInstance,NULL);

Стиль WS_POPUPWINDOW|WS_CAPTION|WS_MINIMIZEBOX|WS_VISIBLE указывает на временное окно с кнопкой минимизации и заголовком.

Шаг 8)

Далее создаём цикл обработки сообщений приложения:

while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg);

Так как приложение не предусматривает обработки сообщений от клавиатуры, то в цикле отсутствует вызов функции трансляции клавиатурных сообщений.


Шаг 9)

Создаём оконную процедуру:

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)

{switch(msg)

{

case WM_DESTROY:

{PostQuitMessage(0); return 0;}

}

return DefWindowProc(hwnd,msg,wParam,lParam);

}


______________________________________________________________

Листинг 1:

#include <windows.h>

#include<tchar.h> // for UNICODE charset

bool RegClass(WNDPROC,LPCTSTR,UINT);

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

HINSTANCE hInstance;

TCHAR szMainClass[]=_T("MainClass");

TCHAR szTitle[]=_T("Пример 1.1");

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,

LPSTR lpszCmdLine, int nCmdShow)

{

MSG msg;

hInstance=hInst;

HWND hwnd=FindWindow(szMainClass,szTitle);

if (hwnd)

{

MessageBox(hwnd,_T("Можно запускать только один экземпляр приложения!\n")

_T("Перемещаю на передний план первый экземпляр"),

szTitle,MB_OK|MB_ICONSTOP);

if (IsIconic(hwnd))

ShowWindow(hwnd,SW_RESTORE);

SetForegroundWindow(hwnd);

return 0;

}

if (!RegClass(WndProc,szMainClass,COLOR_DESKTOP))

return FALSE;

int w=GetSystemMetrics(SM_CXSCREEN)-1;

int h=GetSystemMetrics(SM_CYSCREEN)-1;

hwnd=CreateWindow(szMainClass,szTitle,WS_POPUPWINDOW|WS_CAPTION|

WS_MINIMIZEBOX|WS_VISIBLE,

0,0,w,h,0,0,hInstance,NULL);

if (!hwnd) return FALSE;

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

DispatchMessage(&msg);

return msg.wParam;

}

bool RegClass(WNDPROC Proc,LPCTSTR szName,UINT brBackground)

{

WNDCLASS wc;

wc.style=wc.cbClsExtra=wc.cbWndExtra=0;

wc.lpfnWndProc=Proc;

wc.hInstance=hInstance;

wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);

wc.hCursor=LoadCursor(NULL,IDC_ARROW);

wc.hbrBackground=(HBRUSH)(brBackground+1);

wc.lpszMenuName=(LPCTSTR)NULL;

wc.lpszClassName=szName;

return (RegisterClass(&wc)!=0);

}

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)

{switch(msg)

{

case WM_DESTROY:

{PostQuitMessage(0); return 0;}

}

return DefWindowProc(hwnd,msg,wParam,lParam);

}

Самостоятельно на практике: Приведенный код перевести на ассемблер.

Форма представляет собой объект базы данных Access, в котором разработчик размещает элементы управления, принимающие действия пользователей или служащие для ввода, отображения и изменения данных в полях.

Чаще всего формы создаются в следующих целях:

· ввод и редактирование данных;

· управление ходом выполнения приложения – в этом случае формы используются для запуска макросов;

· вывод сообщений – с помощью форм можно вывести на экран информацию, предупреждение или сообщение об ошибках.

Access предлагает 2 основных способа создания форм:

1. Конструктор форм. Этот способ позволяет разрабатывать собственные экранные формы с заданными свойствами для просмотра, ввода и редактирования данных.

2. Мастер форм. Позволяет достаточно быстро создать форму на основе выбранных для нее данных.

Создание форм с помощью мастера на основе одной таблицы

1. На вкладке Создание выбрать кнопку Мастер форм.

2. В окне Создание формы можно выбрать только одну таблицу в качестве источника данных для формы.

3. Выбрать поля, которые будут включены в экранную форму. Поля могут переноситься в форму по одному и все сразу.

4. Выбрать внешний вид формы, стиль формы.

5. Создание формы завершается заданием ее имени.

Созданная экранная форма может не полностью соответствовать потребностям разработчика. Чтобы ее подправить, можно сразу перейти в режим конструктора, выбрав альтернативу Изменение макета формы, а можно это сделать и потом, перейдя в режим конструктора из режима формы или открыв ранее созданную форму в режиме конструктора.

Работа с формой в режиме Конструктора

При открытии окна Конструктора форма содержит только один раздел - область данных. Помимо этого, она может содержать разделы заголовка и примечания формы, верхний и нижний колонтитулы.

Для добавления или удаления разделов формы используются команды Заголовок/Примечание формы и Колонтитулы на вкладке Конструктор. Каждый раздел отделен горизонтальной линией, на которой написано его название.

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

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

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

Основные свойства формы и особенностей их использования

Форма имеет множество свойств, которые определяют ее источник данных, внешний вид, поведение, а также допустимые при работе с ней операции. Изменить свойства формы можно в окне Свойства.

Свойства формы распределены по четырем вкладкам: Макет, Данные, События, Другие, на вкладке Все они собраны вместе.

Свойства вкладки События используются при программировании.

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

· Подпись — задает текст, который появляется в заголовке окна формы. (По умолчанию текст заголовка совпадает с названием формы).

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

· Режим формы, Режим таблицы, Режим сводной таблицы, Режим сводной диаграммы - предоставляют возможность переключения в соответствующий режим.

· Полосы прокрутки - появляются в случае необходимости, но только если разрешены.

· Область выделения и Кнопки перехода - соответствуют одноименным элементам таблиц.

· Разделительные линии - используются в основном для зрительного разделения записей в ленточной форме.

· Автоматический размер и Выравнивание по центру - относятся к представлению окна формы на экране.

· Тип границы — определяет тип окна формы (к границе окна относится и его заголовок, включая все его кнопки). Вариант Отсутствует применяется в основном для подчиненных форм, так как при его выборе невозможно управлять окном (свертывать/развертывать его, изменять размер, перемещать и закрывать) при помощи мыши. При выборе варианта Изменяемая получается обычное рабочее окно. Вариант Тонкая отличается от варианта Окно диалога только набором кнопок в заголовке.

· Кнопка оконного меню, Кнопки размеров окна (Свернуть и Развернуть), Кнопка закрытия и Кнопка контекстной справки — вместе со свойством Тип границы определяют набор кнопок в заголовке окна. Не все сочетания кнопок являются допустимыми. Кроме того, при типе границы Окно диалога кнопки Свернуть и Развернуть не отображаются, несмотря на значение свойства Кнопки размеров окна.

· Рисунок определяет рисунок, который будет являться фоном формы.

· Тип рисунка - Связанный – рисунок хранится в отдельном документе, и документ-контейнер содержит только указатель на исходный файл рисунка, Внедренный - представляет собой копию файла с рисунком, который сохранен вместе с формой.

Свойства вкладки Данные, определяют источник данных формы и возможности их обработки.

· Источник записей — указывает таблицу или запрос, записи которых отображаются в элементах управления формы.

· Применение фильтров — позволяет запретить для формы использование фильтров.

· Разрешить изменение, Разрешить удаление, Разрешить добавление - определяет возможность изменения, удаления и добавления данных.

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

· На вкладке Другие собраны свойства, которые трудно отнести к той или иной определенной категории.

· Всплывающее окно — открытая форма всегда будет расположена над другими окнами Access.

· Модальное окно — при включении этого свойства из открытой формы нельзя будет перейти в другие окна Access

· Цикл табуляции - определяет возможность перехода между записями с использованием клавиш со стрелками и клавиши Tab.

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

· Файл справки, Идентификатор справки - позволяют связать форму со специально разработанным для нее файлом справки и его конкретным разделом.

Панель элементов

Панель элементов используется для размещения объектов на форме. Обычно панель элементов появляется в режиме Конструктора форм автоматически. Убрать или восстановить ее на экране можно с помощью кнопки Элементы управления на вкладке Конструктор.


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: