Лабораторная работа № 4. Работа с таймером

Цель:Изучить способы обработки событий в WinAPI. Рассмотреть функции KillTimer, SetTimer, InvalidateRectдля создания анимации.

Краткие теоретические сведения:

Функция InvalidateRect добавляет прямоугольник области обновления определяемого окна. Область модификации представляет собой часть клиентской области окна, что переписывается заново. Функция InvalidateRect добавляет прямоугольник области обновления определяемого окна. Область модификации представляет собой часть клиентской области окна, что переписывается заново.

SetTimer создает таймер с заданным значением времени ожидания.

KillTimer уничтожает заданный таймер.

ReleaseCapture освобождает мышь из окна в текущем потоке и восстанавливает нормальную обработку ввода мыши. Окно, которое захватило мышь получает весь ввод мыши, независимо от положения курсора, кроме случаев, когда нажатие кнопки мыши, когда курсор горячая точка находится в окне другого потока.

Задание:

4.1. Машинка движется по клиентской области слева направо, когда уходит за область, то вновь появляется слева или разворачивается и возвращается.

Дополнительные эффекты для учебной практики:

¾ движение с ускорением/замедлением;

¾ изменение цвета при приближении к стенке;

¾ движение по наклонной;

¾ видно вращение колес;

¾ выезд за область постепенный, по частям машины.

Сообщения:

- WM_CREATE – создать таймер;

- WM_PAINT – нарисовать машинку в текущей позиции;

- WM_TIMER – изменить текущую позицию машинки и сообщить о необходимости обновить клиентскую область.

4.2. Светофор. Обеспечить переключение цветов.

4.3. В клиентской области расположены три круга разных цветов. Щелчок левой кнопкой мыши по кругу приводит к его «миганию» (увеличение/уменьшение диаметра). Щелчок правой кнопкой мыши по кругу останавливает мигание.

Сообщения:

- WM_CREATE – создать таймер;

- WM_PAINT – нарисовать три круга в соответствующем состоянии;

- WM_TIMER – изменить состояния кругов и сообщить о необходимости обновить клиентскую область;

- WM_LBUTTONDOWN – добавить соответствующий круг к «мигающим» (функция GetPixel() позволит определить цвет пикселя, на который попал курсор мыши, и, следовательно, узнать, в область какого круга попал курсор мыши);

- WM_RBUTTONDOWN – удалить соответствующий круг из «мигающих».

4.4. График функции

Нарисовать график функции y=f(x) на отрезке [a,b]. График масштабируется в зависимости от размеров клиентской области. Щелчок по графику приводит к отображению значений (x,y). Проверить для различных функций.

4.5. Шарик катится по синусоиде туда и обратно.

Анализ реализации алгоритма

В первом задании для обеспечения движения автомобиля по наклонной плоскости используем объект класса XFORM, позволяющий изменить систему координат. Чтобы показать вращение колес, применяю соответствующие тригонометрические функции. Используя специальные переменные при обработке сообщения WM_TIMER, придадим машине ускорение.

Исходный код:

lpXform.eM11 = sin(t);

lpXform.eM21 = cos(t);

lpXform.eM22 = -sin(t);

lpXform.eM12 = cos(t);

Rectangle(hdc, x - 120, -70, x - 20, -10);

Rectangle(hdc, x - 20, -70, x + 10, 10);

DeleteObject(hbrush1);

hbrush1 = CreateSolidBrush(RGB(255, 255, 0));

SelectObject(hdc, hbrush1);

Ellipse(hdc, x - 100, -80, x - 80, -60);

Ellipse(hdc, x - 30, -80, x - 10, -60);

DeleteObject(hbrush1);

Line(hdc, (x - 90) + 10 * sin(-x / 10), -80 + (10 - 10 * cos(-x / 10)), (x - 90) - 10 * sin(-x / 10), -(10 - 10 * cos(-x / 10)) - 60);

Line(hdc, (x - 20) + 10 * sin(-x / 10), (-80) + (10 - 10 * cos(-x / 10)), (x - 20) - 10 * sin(-x / 10), -(10 - 10 * cos(-x / 10)) - 60);

Скриншоты реализации можно просмотреть в приложении 2.

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

Исходный код:

case WM_TIMER:

{

A[0]->red = A[1]->red = A[1]->green = A[2]->green = 100;

switch (Color)

{

case Red:

A[0]->red += 150;

Color = Yellow;

break;

case Yellow:

A[1]->red += 150;

A[1]->green += 150;

Color = Green;

break;

case Green:

A[2]->green += 150;

Color = Red;

break;

}

InvalidateRect (hWnd, NULL, true);

break;

}

Скриншоты реализации можно просмотреть в приложении 2.

В третьем задании, используя специально описанную структуру Circle, по нажатию соответствующей клавиши мыши изменяю значения ее полей. Для работы с неколькими кругами использую вектор заданного типа Circle. Нажатие левой клавиши мыши обрабатывается посредтсвом WM_LBUTTONDOWN, правой клавиши - WM_RBUTTONDOWN.

Исходный код:

case WM_LBUTTONDOWN:

{

hdc = GetDC(hWnd);

xMs = GET_X_LPARAM(lParam);

yMs = GET_Y_LPARAM(lParam);

COLORREF MsClick = GetPixel(hdc, xMs, yMs);

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

{

if ( MsClick == RGB(A[i]->red, A[i]->green, A[i]->blue) && condition[i] == NoBlink)

condition[i] = BlinkStandart;

}

InvalidateRect (hWnd, NULL, true);

break;

}

WM_RBUTTONDOWN работает аналогично.

Скриншоты реализации можно просмотреть в приложении 2.

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

Исходный код:

case WM_CREATE:

{

GetClientRect(hwnd, &R);

T = new Table(R, marg,a,b);

F = new Function (T->GetCell(), T->GetMarg(), a, b);

}

case WM_PAINT:

{

hDC = GetDC(hwnd);

hDC = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &R);//

T = new Table(R, marg,a,b);//

F = new Function (T->GetCell(), T->GetMarg(), a, b);//

Point = T->DrawingTable(hDC);

F->Drawing(hDC, Point, Func);

EndPaint(hwnd, &ps);

break;

}

case WM_LBUTTONDOWN:

{

hDC = GetDC(hwnd);

xMs = GET_X_LPARAM(lParam);

yMs = GET_Y_LPARAM(lParam);

GetClientRect(hwnd, &R);//

T = new Table(R, marg,a,b);//

F = new Function (T->GetCell(), T->GetMarg(), a, b);//

Point = T->DrawingTable(hDC);//

if( F->HitTheTarget(xMs, yMs, Point, Func))

{

P = F->GetCoordinates(xMs, yMs, Point, Func);

F->DrawCoordinates(hDC, xMs, yMs, P);

}

break;

}

Скриншоты реализации можно просмотреть в приложении 2.

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

Исходный код:

void SetXC (double x0, int PixToCM)

{

double r = (double)R/PixToCM;

double cosin = cos(x0);

double xCG = x0 - r*cosin/sqrt(cosin*cosin+1);

double yCG = sin(x0) + sqrt(r*r - (x0-xCG)*(x0-xCG));

xC = xCG*PixToCM;

yC = rect.bottom/2 - (int)(yCG*PixToCM);

double xNEW = r*cos(alpha)+xCG, yNEW = r*sin(alpha)+yCG;

xN = xNEW*PixToCM;

yN = rect.bottom/2 - (int)(yNEW*PixToCM);

}

case WM_PAINT:

{

hdc = BeginPaint(hWnd,&ps);

int PixToCM = rect.right/15;

C.SetXC((double)x0/PixToCM, PixToCM);

HBRUSH hbro, hbr = CreateSolidBrush(C.Color);

hbro = (HBRUSH)SelectObject(hdc,hbr);

Ellipse (hdc, C.xC-C.R, C.yC-C.R, C.xC+C.R, C.yC+C.R);

DeleteObject(SelectObject(hdc,hbro));

HPEN oldpen, pen = CreatePen(PS_SOLID, 1, RGB(255,255,255));

oldpen = (HPEN)SelectObject (hdc, pen);

MoveToEx(hdc, C.xC, C.yC, 0);

LineTo(hdc, C.xN, C.yN);

DeleteObject(SelectObject(hdc,oldpen));

for (int i=0; i<=rect.right; i++)

{

double xG, yG;

int yP;

xG = (double)i/PixToCM;

yG = sin(xG);

yP = yG*PixToCM;

SetPixel(hdc, i, rect.bottom/2 - yP, RGB(200,0,0));

}

EndPaint(hWnd,&ps);

break;

}

Скриншоты реализации можно просмотреть в приложении 2.

Выводы:Использовав функцииInvalidateRect, SetTimer, KillTimer, ReleaseCapture, описанные в кратких теоретических сведениях, а также функции BeginPaint, EndPaint, MessageBox, Ellipse и другие, изученные ранее, научилась обрабатывать события.

Индивидуальное задание. Создание анимации

Цель:Научиться создавать анимации при помощи WinApi.

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

Задание.Необходимо создать следующую анимацию:

В лесу танцует избушка на курьих ножках. По нажатию клавиши пробел в окошке появляется баба Яга и затем вылетает из него.

Анализ реализации алгоритма:

Для начала я выбрала подходящий фон. Затем выбрала подходящее изображение избушки и создала его зеркальное отображение, чтобы затем показать танец, меняя эти изображения. Используя приложение Paint, я нарисовала бабу Ягу в окне избушки. Затем, указав начальное положение бабы Яги в окошке, и после этого меняя ее положение, я изобразила вылет бабы Яги из окошка.

Исходный код:

case WM_KEYDOWN:

switch (wParam){

case VK_SPACE:

run = false;

break;

}

break;

case WM_PAINT:

GetClientRect(hWnd, &rect);

hdc = BeginPaint(hWnd, &ps);

hdc2 = CreateCompatibleDC(hdc);

SelectObject(hdc2, hFon);

StretchBlt(hdc, 0, 0, rect.right, rect.bottom, hdc2, 0, 0, fon.bmWidth, fon.bmHeight, SRCCOPY);

DeleteDC(hdc2);

hdc2 = CreateCompatibleDC(hdc);

if (tick%20>=0 && tick%20<10 && dance){

SelectObject(hdc2, hHouse1);

TransparentBlt(hdc, rect.right/3, rect.bottom/4, rect.right/3,rect.bottom*2/3, hdc2, 0, 0,house1.bmWidth, house1.bmHeight, RGB(255,255,255));}

else if (tick%20>=10 && dance){

SelectObject(hdc2, hHouse);

TransparentBlt(hdc, rect.right/3, rect.bottom/4, rect.right/3,rect.bottom*2/3, hdc2, 0, 0,house.bmWidth, house.bmHeight, RGB(255,255,255));}

else if (!dance && tick<=30){

SelectObject(hdc2, hHouse1);

TransparentBlt(hdc, rect.right/3, rect.bottom/4, rect.right/3,rect.bottom*2/3, hdc2, 0, 0,house1.bmWidth, house1.bmHeight, RGB(255,255,255));}

else if (!dance && tick>30 && tick<71){

SelectObject(hdc2, hHouse2);

TransparentBlt(hdc, rect.right/3, rect.bottom/4, rect.right/3,rect.bottom*2/3, hdc2, 0, 0,house1.bmWidth, house2.bmHeight, RGB(255,255,255));}

else if (!dance && go){

SelectObject(hdc2, hHouse1);

TransparentBlt(hdc, rect.right/3, rect.bottom/4, rect.right/3,rect.bottom*2/3, hdc2, 0, 0,house1.bmWidth, house1.bmHeight, RGB(255,255,255));}

DeleteDC(hdc2);

if (go){

hdc2 = CreateCompatibleDC(hdc);

SelectObject(hdc2, hLady);

TransparentBlt( hdc, pos1.x, pos1.y, rect.right/5,rect.bottom/3, hdc2, 0, 0,lady.bmWidth, lady.bmHeight, RGB(255,255,255));

DeleteDC(hdc2);

}

EndPaint(hWnd, &ps);

break;

Скриншоты реализации можно просмотреть в приложении 2.

Выводы:Использовав навыки, приобретенные при выполнении предыдущих заданий, я создала анимацию при помощи WinApi.

С#

Лабораторная работа №1. Простейшее приложение Windows Forms

Цель:Изучить способы работы с текстовыми файлами в C#. Рассмотреть создание диаграмм, меню, диалоговых окон средствами C#.

Краткие теоретические сведения:

Класс Form представляет собой заготовку формы, от которой наследуются классы форм приложения. Помимо множества унаследованных элементов, в этом классе определено большое количество собственных элементов. В библиотеке .NET нет специального класса для представления диалоговых окон. Вместо этого устанавливаются определенные значения свойств в классе обычной формы. В диалоговом окне можно располагать те же элементы управления, что и на обычной форме. Для вывода линий, геометрических фигур, текста и изображений необходимо создатьэкземпляр класса Graphics, описанного в пространстве имен System.Drawing.

Задание:Разработайте приложение Windows Forms при помощи MS Visual Studio C#.

При реализации интерфейса следуйте рекомендациям стандарта CUI (Common User Interface).

Программа должна иметь главное меню, строку состояния и клиентскую область (область рисования).

Главное меню приложения обязательно должно содержать следующие команды (в формате Подменю/Команда):

– File/Open - выбор файла

– File/Quit - завершение приложения после подтверждения пользователя

– Help/About - вывод диалогового окна которое печатает условие задачи и информацию о разработчике (ФИО студента, группа, курс, факультет, ВУЗ)

– (команды) - команды необходимые для решения вашей задачи, например, View/Fonts для выбора шрифта, View/Colors для настройки цвета и т.п.

Постройте диаграмму опроса в сети отображающую процентное соотношение проголосовавших.

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

Для выбора файла входных данных использовать стандартный диалог.

Анализ реализации алгоритма:

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

Исходный код:

private void ReadData()

{

ClearValues();

using (StreamReader SourceFile = new StreamReader(FileName, System.Text.Encoding.GetEncoding(1251)))

{

string Temp;

NameOfPoll = SourceFile.ReadLine();

int Sum = 0;

while (!SourceFile.EndOfStream)

{

Temp = SourceFile.ReadLine();

int index = Temp.IndexOf(' ');

string StrNum = Temp.Substring(0, index);

Sum += Int32.Parse(StrNum);

CountsOfPoll.Add(Int32.Parse(StrNum));

ModelsOfPoll.Add(Temp.Substring(index + 1));

}

int SumPercents = 0;

for (int i = 0; i < CountsOfPoll.Count - 1; i++)

{

PercentsOfPoll.Add((int)Math.Round(100 * (double)CountsOfPoll[i] / Sum));

SumPercents += PercentsOfPoll[i];

}

PercentsOfPoll.Add(100 - SumPercents);

this.Text = NameOfPoll;

}

}

private void FillDiagram()

{

chart1.Series.Clear();

Series series = new Series();

series.ChartType = SeriesChartType.Pie;

chart1.Series.Add(series);

chart1.Series[0].Points.DataBindXY(ModelsOfPoll, PercentsOfPoll);

chart1.Series[0].IsValueShownAsLabel = true;

}

Результат работы программы можно увидеть в приложении 3.

Выводы:Я изучила способы работы с текстовыми файлами в C#. Рассмотрела создание диаграмм, меню, диалоговых окон средствами C#.


Наши рекомендации