Немодальные диалоги


Процедура создания и обслуживания немодального диалога проиллюстрирована в примере 28-4; вы­вод этой программы показан на рис. 28.9.

//Приложение 28-4. Немодальный диалог

//Файл 28-4.h

#define Dlg 1

#define CM_VIEW 201

#define CM_EXIT 24310

#define IDC_POINTS 101

#define IDC_CURVE 102

#define IDC_HISTO 103
#define FILESIZE

//Файл 28-4.rc #include "28-4.h" MainMenu MENU{ POPUP "Файл"{

MENUITEM "Вид...",CM_VIEW

MENUITEM SEPARATOR

MENUITEM "Выход",CM_EXIT

} }

Dlg DIALOG 100,15,116,66 STYLE WS_CHILD|WS_VISIBLE|WS_CAPTION


266 Глава 28

CLASS "BorDlg_Gray"

CAPTION "Вид графика"

FONT 8, "MS Sans. Serif"{

CONTROL "Точки",IDC_POINTS,"BUTTON",BS_AUTORADIOBUTTON|WS_GROUP, 8,9,60,12

CONTROL "Огибающая",IDC_CURVE,"BUTTON",BS_AUTORADIOBUTTON,8,27,60,12

CONTROL "Гистограмма",IDC_HISTO,"BUTTON",BS_AUTORADIOBUTTON,8,45,60,12

CONTROL "", IDOK,"BorBtn",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE|WS_GROUP,72,29,37,25

}

//Файл 28-4.cpp

#include <owl\framewin.h>

#include <owl\dialog.h>

#include "28-4.h"

#include <stdio.h>

class MyWindow; //Объявим имя класса для последующих ссылок на него

MyWindow* myWin;//Объявим имя указателя на объект главного окна

/*Класс приложения, производный от Tapplication*/

class MyApp:public TApplication{

public:

void InitMainWindow();//Замещаем функцию InitMainWindow

};

/*Класс главного окна, производный от TframeWindow*/ class MyWindow:public TFrameWindow{ public:

int view;/ /Переключатель вида графика

int data[FILESIZE]; //Массив для данных из файла

MyWindow(TWindow*,char far*);

void SetupWindow(); //Замещаем функцию SetupWindow

void Paint(TDC&,bool,TRect&); //Замещаем функцию Paint

void GetWindowClass(WNDCLASS&);//Замещаем функцию GetWindowClass

void CmView(); //Функция отклика на нажатие кнопки "Вид"

DECLARE_RESPONSE_TABLE(MyWindow); //Объявляем таблицу откликов главного окна

};

/*Класс окна диалога, производный от Tdialog*/ class MyDialog:public TDialog{ public:

MyDialog(TWindow* parent,TResId resId):TDialog(parent,resId){}/ /Конструктор

EvInitDialog(HWND) ;//Замещаем функцию EvInitDialog

void CmPoints(); //Функции отклика

void CmCurve(); //на нажатие

void CmHisto(); //альтернативных кнопок

DECLARE_RESPONSE_TABLE(MyDialog); //Объявляем таблицу откликов диалога

};

/*Таблица откликов класса MyWindow*/ DEFINE_RESPONSE_TABLE1(MyWindow,TFrameWindow)

EV_COMMAND(CM_VIEW,CmView), END_RESPONSE_TABLE; /* Конструктор главного окна*/ MyWindow::MyWindow(TWindow*parent,char far*title):TFrameWindow(parent,title){

AssignMenu("MainMenu"); //Назначаем главному окну меню

}

/*3амещающая функция SetupWindow*/ void MyWindow::SetupWindow(){

TWindow::SetupWindow(); //Вызываем замещенную функцию SetupWindow

FILE* fp=fopen("28-4.dat","r"); //Открываем файл для чтения

for(int i=0;i<FILESIZE;i++)

fscanf(fp,"%d",&data[i]); //Читаем символьные данные в массив data,преобразуя в числа

fclose(fp);/ /Закрываем файл

}

/*3амещающая функция GetWindowClass*/ void MyWindow::GetWindowClass(WNDCLASS& wc){

TWindow::GetWindowClass(wc)///Вызываем замещенную функцию

wc.style=CS_VREDRAW;/ /Необходимо, т.к. график рисуется снизу

} void MyWindow::CmView(){

new MyDialog(this,Dig)->Create() ;//Открываем немодальный диалог!

} void MyWindow::Paint(TDC&dc,bool,TRect&){

TPen myPen(TColor::LtBlue,1); //Устанавливаем синее перо

dc.SelectObject(myPen);// для фигур графика

TBrush myBrush(TColor::LtBlue) ;//Устанавливаем синюю


Диалоговые окна 267

dc.SelectObject(myBrush);//кисть для внутренних областей фигур графика TRect wndRect=GetClientRect(); //Получим рабочую область главного окна int i;// Вспомогательная локальная переменная switch(view) {//Переключение формы отображения графика case(IDC_POINTS): //Вывод точек for(i=0;i<FILESIZE;i++)

dc.Ellipse(1*10-1-10-2,wndRect.bottom-data[i]-2,1*10+10+2, // Рисуем кружки

wndRect.bottom-data[i]+2); break; case(IDC_CURVE): //Вывод кривой линии

dc.MoveTo(10,wndRect.bottom-data[0]) ;//Устанавливаем начальную позицию for(i=1;i<FILESIZE;i++)

dc.LineTo(i*10+10,wndRect.bottom-data[i]); //Проводим линии между точками break; case(IDC_HISTO):

for(i=0;i<FILESIZE;i++)

dc.Rectangle(1*10+10,wndRect.bottom-data[i],

1*10+10+9,wndRect.bottom);// Рисуем прямоугольники break; } }

/*Реализация класса MyDialog*/ DEFINE_RESPONSE_TABLE1(MyDialog,TDialog) EV_COMMAND(IDC_POINTS,CmPoints), EV_COMMAND(IDC_CURVE,CmCurve), EV_COMMAND(IDC_HISTO,CmHisto), END_RESPONSE_TABLE; MyDialog::EvInitDialog(HWND hwnd){

TDialog::EvInitDialog(hwnd); //Вызываем замещенную функцию EvInitDialog SendDlgItemMessage(myWin->view,BM_SETCHECK,true,0L);/ /Нажмем кнопку } void MyDialog::CmPoints(){

myWin->view=IDC_POINTS; //Устанавливаем значение переключателя вида графика m yWin->Invalidate(); //Инициируем перерисовку главного окна } void MyDialog::CmCurve(){

myWin->view=IDC_CURVE; //Устанавливаем значение переключателя вида графика myWin->Invalidate(); //Инициируем перерисовку главного окна } void MyDialog::CmHisto(){

myWin->view=IDC_HISTO; //Устанавливаем значение переключателя вида графика myWin->Invalidate(); //Инициируем перерисовку главного окна }

/*Замещающая функция InitMainWindow класса приложения*/ void МуАрр::InitMainWindow(void){ EnableBWCC();

myWin=new MyWindow(0,"Программа 28-4"); //Сохранили указатель на главное окно myWin->view=IDC_POINTS; //Начальное значение переключателя вида графика SetMainWindow(myWin); //Установили главное окно }

/*Главная функция приложения OwlMain*/ int OwlMain(int,char*[]){

return MyApp().Run(); }

В файле 28-4.h определяются значения идентификаторов органов управления диалога и задается чис­ло точек на графике (константа FILESIZE). Из файла 28-4.rc видно, что в меню имеется единственный содержательный пункт "Вид...", который используется для активизации немодального диалога (для уничтожения диалогового окна служит его кнопка "ОК"). Три альтернативные кнопки, имеющие стиль BS_AUTORADIOBUTTON, объединены в группу флажками WS_GROUP. Первый флажок определяет первую альтернативную кнопку, второй - первый управляющий элемент за пределами альтернативной группы. Впрочем, при наличии единственной альтернативной группы флажки WS_GROUP можно опус­тить.

В файле 28-4.срр объявлены две глобальные переменные - класс MyWindow и указатель на объект этого класса myWin. Такое объявление (в котором, обратите внимание, фигурирует только имя класса, но нет никакой информации о его содержимом или подчиненности) позволяет в любом месте программы, в частности, в функции любого класса, сослаться на этот объявленный ранее класс или, через его указа­тель, на любые открытые функции-члены и данные-члены этого класса. В нашем примере такая необхо­димость возникнет в функциях отклика класса диалога, где устанавливается текущее значение перемен­ной view и вызывается функция Invalidate() класса главного окна.


268 Глава 28

В классе главного окна MyWindow объявляется переменная view, которая будет содержать значение режима отображения графика (IDC_POINT, IDC_CURVE или IDC_HISTO). Было бы изящнее объявить ее не int, a enum; это не сделано для сокращения текста программы. Массив data служит для хранения отображаемых на графике данных. Для создания большей иллюзии полезности программы данные не определены в тексте программы, а читаются из файла с заданным заранее именем 28-4.dat; еще лучше было бы включить в программу стандартный диалог Windows для выбора файла и, тем самым, сделать ее гораздо более универсальной.

Далее в классе MyWindow объявляются замещаемые и новые функции-члены и таблица отклика, со­держащая единственную строку-макрос для отклика на пункт главного меню "Вид.

Класс немодального диалога MyDialog содержит объявление замещаемой функции EvInitDialog(), которая удобна для выполнения необходимых инициализирующих действий, а также трех функций от­клика на нажатие альтернативных кнопок диалога. Соответственно в таблицу откликов класса диалога входят три макроса EV_COMMAND.

Подготовительные для всей программы действия - чтение данных из файла - выполняются в заме­щающей функции SetupWindow(). Данные в файле хранятся в символьной форме, т.е. предполагается, что они были введены с клавиатуры. Для разделения таких данных в файле можно использовать различ­ные символы - двоичный нуль, возврат каретки и др. В файле 28-4 dat данные разделяются символом пробела и для графика, изображенного на рис. 28.9, имеют следующий вид:

130 136 141 147 151 153 154 154 152 149 144 139 133 127 121 115 111 107 105 105

Для чтения данных из файла использована функция fscanf(), преобразующая, в процессе чтения, ка­ждое данное в двоичную форму в соответствии с указанным в аргументах функции шаблоном "%d".

Существенным моментом является назначение классу окна стиля CS_VREDRAW. Это назначение выполняется в замещающей функции GetWindowClass(), использование было подробно описано в гл. 26. Стиль CS_VREDRAW определяет полную перерисовку окна (а не только его области вырезки) при лю­бых манипуляциях с размером окна или перемещением по нему окна диалога. Как было показано в гл. 12, полная перерисовка окна, являющаяся неэффективной с точки зрения расходования процессорного времени, необходима в тех случаях, когда изображение в окне строится относительно его нижней (или правой) границы, что типично для вывода графиков.

Открытие немодального диалога осуществляется в функции отклика на нажатие кнопки "Вид..." CmView(). С помощью оператора new создается безымянный объект класса MyDialog и в том же пред­ложении для него вызывается функция класса TDialog Create(), которая служит для вывода на экран не­модального диалогового окна. Вспомним, что для активизации модального диалога мы использовали функцию Execute(), а для его завершения - функцию DestroyWindow(). Немодальный же диалог завер­шать нет особой необходимости, так как он, будучи выведен на экран, не препятствует использованию любых других органов управления главного окна.

Назначение диалога в данном примере заключается в установлении режима вывода графика, для чего предусмотрены три функции отклика: CmPoints(), CmCurves() и CmHisto(). В каждой из этих функций переключателю режима отображения view присваивается соответствующее значение, после чего вызо­вом функции Invalidate() для объекта главного окна инициируется полная его перерисовка.

Вывод графика осуществляется, как и положено, в функции Paint() главного окна. В ней прежде все­го создаются и загружаются в контекст устройства синее перо и синяя кисть, а затем в зависимости от значения переменной view на экран выводятся либо маленькие (радиусом 2 пиксела) кружки, либо ли­нии, соединяющие точки графика, либо прямоугольники, образующие гистограмму. Число 10, фигури­рующее в координатах вывода, характеризует смещение графика на 10 пикселов относительно левой границы окна. Ради простоты в программе не выполняется никаких действий по масштабированию гра­фика и не анализируется число введенных данных.

Как уже отмечалось, графики рисуются относительно нижней границы окна, реальное значение ко­торой зависит от текущего размера окна на экране. Необходимым элементом такой техники является вы­зов функции GetClientRect(), которая возвращает структуру wndRect типа TRect с текущими размерами рабочей (клиентной) области окна. Значение wndRect.Bottom и определяет нижнюю границу.


Глава 29


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



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