Приспособления

В приложении 29-2 демонстрируется методика создания приспособлений, используемых для ввода в программу конкретных значений настраиваемых переменных. В рассматриваемом примере в главном окне приложения создается квадратное дочернее окно-панель с серым фоном, в которое выводятся т.н. фигуры Лиссажу, получаемые при одновременном изменении х- и у- координат точки по синусоидально­му закону. Если х- и у-координаты изменяются с одинаковой частотой, а сдвиг фаз между ними отсутст­вует, то фигура Лиссажу вырождается в прямую линию, наклоненную к осям под углом 45 градусов. При сдвиге фаз между колебаниями по осям, равным пи/2, кривая представляет собой правильную окружность.

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

Для изменения соотношения частот колебаний по осям х и у используется приспособление-ползунок (класс TSlider), который в конкретном примере позволяет изменять соотношение частот от 1 до 10, а для задания Сдвига фаз между колебаниями - линейка прокрутки (класс TScrollBar), за­дающая сдвиг фаз от 0 до я с ша­гом 1/32 пи. Устанавливаемые с помощью приспособлений значе­ния отношения частот и сдвига фаз отображаются в главном окне над соответствующими приспо­соблениями.

На рис. 29.3 изображен вид окна приложения с примером фигуры Лиссажу.

//Приложение 29-2. Дочернее окно, ползунок и линейка прокрутки

//Файл 29-2.h

#define ID_FREQUENCYSLIDER 100

#define ID_FREQUENCYTEXT 101

#define ID_FREQUENCYLEGEND 102

#define ID_PHASEBAR 103

#define ID_PHASETEXT 104

#define ID_PHASELEGEND 105


274 Глава 29

//Файл 29-2. rc

#include <owl\slider.rc> //Включение в наш файл изображения ползунка

//Файл 29-2.срр

#include <owl\framewin.h>

#include <owl\slider.h>

#include <owl\static.h>

#include <owl\slider.h>

#include <math.h>

#include "29-2.h"

const float PI=3.1415926; \//Число пи

int kf,ph;// Значения частоты и фазы, снимаемые с приспособлений

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

class MyApp:public TApplication{

public:

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

/*Класс дочернего окна-панели Panel, производный от класса Twindow*/ class Panel:public TWindow{ public:

Panel(TWindow* parent,char far* title);

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

}; Panel::Panel(TWindow* parent,char far* title):TWindow(parent,title){

Attr.Style=WS_CHILD|WS_VISIBLE|WS_BORDER;;

Attr.X=10;Attr.Y=10;Attr.W=220;Attr.H=240;

SetBkgndColor(TColor::LtGray);

}

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

MyWindow(TWindow*parent,char far*title);

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

TSlider* frequencySlider; //Указатель на объект -ползунок

TScrollBar* phaseBar; //Указатель на объект-линейку прокрутки

TStatic *frequencySliderValue, *phaseBarValue, *frequencyLegend, *phaseLegend;

void UpdateFrequency(UINT=0); //Функция настройки частоты

void UpdatePhase(UINT=0) ;//Функция настройки фазы

Panel* panel; //Указатель на объект-панель

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

}; DEFINE_RESPONSE_TABLE1(MyWindow,TFrameWindow) //Таблица откликов от приспособлений

EV_CHILD_NOTIFY^ALL_CODES(ID_FREQUENCYSLIDER,UpdateFrequency),

ЕV_СНILD_NOTIFY_ALL_CODES(ID_PHASEBAR,UpdatePhase), END_RESPONSE_TABLE; /*Функции-члены класса MyWindow*/ MyWindow::MyWindow(TWindow*parent,char far*title):TFrameWindow(parent,title){

panel=new Panel(this,NULL); //Создаем окно-панель без заголовка

frequencySlider=new THSlider(this,ID_FREQUENCYSLIDER, 250, 50,150,32); //Ползунок

phaseBar=new TScrollBar(this,ID_PHASEBAR,250,180,150,0,TRUE) ;//Линейка прокрутки

frequencySliderValue=new TStatic(this,-1,"",250,20,200,25);

frequencyLegend=new TStatic(this,-1,

"1 10,250,85,200,25);

phaseBarValue=new TStatic (this, -1,"", 250,150,200,25);

phaseLegend=new TStatic(this,-1,

"0 32",250,215,200,25);

} void MyWindow::UpdateFrequency(UINT notifyCode){

char str[50];

if(notifyCode==SB_THUMBTRACK||notifyCode==SB_ENDSCROLL) return;

else{

kf=frequencySlider->GetPosition(); wsprintf(str,"Отношение частот = %d",kf); frequencySliderValue->SetText (str);

panel->Invalidate(); }

} void MyWindow::UpdatePhase(UINT){

char str[50];

ph=phaseBar->GetPosition();

wsprintf(str,"Сдвиг фаз = PI/32 * %d",ph);

phaseBarValue->SetText(str);


Окна и их оформление 275

panel->Invalidate(); } /*3амещающая функция SetupWindow*/

void MyWindow::SetupWindow(){

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

frequencySlider->SetRange(1,10); //Нижний и верхний пределы шкалы

freguencySlider->SetRuler(1,TRUE) ;//Шаг шкалы и фиксация

frequencySlider->SetPosition(1) ;//Начальное положение ручки

phaseBar->SetRange(0,32); //Нижний и верхний пределы шкалы

phaseBar->SetPosition(16); //Начальное положение ручки

UpdateFrequency();//

UpdatePhase();//

}

/*Функция Paint для окна-панели*/ void Panel::Paint(TDC&dc,bool,TRect&){

for(float i=0;i<2*PI*1000;i++) {//В цикле из 1000 шагов float x=sin(i/100)*100; //х-координата текущей точки float y=sin((i/100+PI/32*ph)*kf)*100;//у-координага текущей точки dc.Rectangle(x+110,y+110,x+112,y+112) ;11Квадратики вместо точек }

}

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

SetMainWindow(new MyWindow(0,"Программа 29-2"));

} /*Главная функция приложения OwlMain*/

int OwlMain(int,char*[]){

return MyApp{).Run();

}

Для создания дочернего окна-панели в программе объявляется класс Panel, производный от TWindow и включающий всего две функции - конструктор и замещающую функцию Paint(). В конструкторе клас­са устанавливается (с помощью структуры Attr) стиль окна - дочернее, видимое и без рамки, а также за­даются его координаты и цвет фона. В функции Paint() в цикле из 1000 шагов вычисляются х- и у-координаты точек фигуры Лиссажу с учетом введенных пользователем значений отношения частот kf и сдвига фаз ph. Каждая точка рисуется в виде квадратика с размером сторон 2 пиксела. Число шагов в цикле и шаг изменения координат выбраны так, чтобы в графики состояли из достаточно большого числа точек. Рассмотренный алгоритм рисования двумерного графика использован по причине его наглядности и, строго говоря, не выдерживает никакой критики. По-настоящему следовало для каждой х-координаты с шагом в 1 пиксел вычислять соответствующую ей у-координату. Это устранило бы наложения и разры­вы точек и позволило бы обойтись гораздо меньшим числом шагов в цикле, однако усложнило бы фор­мулы для вычисления координат.

Главное окно приложения, представленное классом MyWindow, производным от TWindow, содержит в себе, помимо дочернего окна Panel, еще ряд управляющих элементов: горизонтальный ползунок, гори­зонтальную же линейку прокрутки и четыре статических элемента для вывода шкал и поясняющих над­писей. Среди данных-членов класса MyWindow объявлены указатели на все эти элементы, а также две прикладные функции UpdateFrequency() и UpdatePhase(), служащие для съема данных с динамических элементов управления и модификации статических. Эти функции являются функциями отклика на сооб­щения, поступающие от элементов управления.

В таблицу откликов класса MyWindow включены всего два макроса EV_CHILD_NOYIFY_ALL_CODES, каждый из которых предназначен для вызова функции отклика для своего элемента управления при поступлении любого сообщения от этого (дочернего) элемента. Анализ приходящих сообщений, если он нужен, возлагается на функции отклика, при этом нотификационный код сообщения передается макросом в функцию отклика в качестве ее параметра.

В конструкторе класса MyWindow создаются объекты для окна-панели, двух динамических элемен­тов управления классов THSlider и TScrollBar (см. рис. 28.5), а также для трех статических элементов класса TStatic. Для всех объектов указываются их идентификаторы и расположение в главном окне, а для статических элементов - выводимый текст. Ползунок и линейка прокрутки пока получают настройки по умолчанию, которые, скорее всего, не соответствуют тому, что нужно нам в данном конкретном случае.

Настройка динамических элементов управления осуществляется в замещающей функции SetupWin-dow(). Здесь прежде всего необходимо вызвать исходную, замещенную функция класса TWindow, кото­рая создает все порожденные окна (в нашем случае - дочернее окно и элементы управления), для кото­рых в конструкторе класса MyWindow мы создали OWL-объекты. Если позабыть вызвать замещенную функцию SetupWindow(), главное окно останется пустым. Далее вызовом соответствующих функций классов THSlider и TScrollBar устанавливаются требуемые настройки приспособлений - пределы и шаг шкал, а также начальные положения ручек. Наконец, прямым вызовом функций откликов UpdateFre-quency() и UpdatePhase() выполняется начальное снятие значений с элементов управления и формирова­ние изображения в главном окне.


276 Глава 29

Функции откликов активизируются при выполнении пользователем каких-либо манипуляций с эле­ментами управления. В них вызовом OWL-функции GetPosition() для соответствующего элемента снима­ется текущее положение его ручки, функцией wspintf() формируется текущее содержимое надписи, и функцией TStatic::SetText() новая надпись выводится в дочернее окно, соответствующее статическому объекту. Для того, чтобы изменения отобразились на экране, вызывается функция Invalidate() для главно­го окна.

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


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



double arrow