Автор работы: Пользователь скрыл имя, 09 Января 2013 в 09:11, курсовая работа
Цель курсового проекта: получение навыков по разработке программы на языке C\C++ , с использованием WinAPI, для реализации пользовательского интерфейса, а также реализация простенького графического редактора.
Программный продукт написан на языке программирования С++. Реализация темы курсовой работ
Введение 4
1. Анализ задания и постановка задач 5
2. Теоретическая часть 6
3. Проектирование программы 11
4. Реализация программы 12
5. Тестирование программы 14
Заключение 21
Литература 22
void Spray(int iDens) – обработчик инструмента «Распылитель».
Функция осуществляет генерацию точек распылителя, определение координат вывода и вывод точек на экран(лист рисования).
Функция не возвращает значений.
void ClearChecks() – обнуление выбора.
Функция по идентификатору обнуляет выбор размеров кисти.
В функцию не передаются значения и она не возвращает значений.
void ZeroMem(char* ptr, int len) – обнуление памяти.
Функция по передаваемому указателю и длине обнуляет память.
Функция не возвращает значений.
bool OpenSaveDlg(bool bSave, HWND hDlg) – диалог открытия/сохранения файла.
Функция осуществляет подготовку и
вызов диалога открытия/
В функцию передается признак сохранения. Возвращаемым значением является сам диалог сохранения/открытия.
void UpdateMenuBmp(HBITMAP bmp, COLORREF clr) – обновление области рисования.
int __stdcall WMain() – инициализация главного окна программы.
Функция осуществляет создание главного окна программы, инициализацию заголовка окна.
В функцию не передается параметров.
int __stdcall WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd ) – функция вызова главного окна программы.
Функция осуществляет вызов главного окна программы и оно же является возвращаемым значением.
При запуске программы открывается главное окно программы(Рисунок 1). По умолчанию программа создает пустую область рисования.
Рисунок 1 – Главное окно программы
Меню «Файл»(Рисунок 2) и его подпункты позволяют создать графический файл, открыть существующий, сохранить созданный или измененный графический файл. Диалог сохранения/открытия файла приведен на рисунке 3.
Рисунок 2 – Меню «Файл»
Рисунок 3 – Диалог открытия/сохранения файла
Рисунок 4 позволяет увидеть главное окно программы с загруженным графическим файлом.
Рисунок 4 – Загруженный файл
Меню «Правка», подпункт «Отмена» позволяет осуществить откат произведенных изменений(Рисунок 5).
Рисунок 5 – Меню «Правка->Отмена»
Меню «Цвет» позволяет
выбрать цвета пера, соответствующих
правой и левой кнопке мыши, а
также производить обмен
Рисунок 6 – Меню «Цвет»
Диалог выбора цвета приведен на рисунке 7.
Рисунок 7 – Диалог выбора цвета пера
Для выбора толщины кисти нужно воспользоваться меню «Толщина кисти»(Рисунок 8), где можно выбрать один из множества вариантов. На рисунке 9 приведен пример всех возможных вариантов толщины кисти программы.
Рисунок 8 – Меню «Толщина кисти»
Рисунок 9 – Примеры толщин кистей
Меню «Инструменты»(Рисунок 10) позволяет выбрать один из возможных инструментов рисования, таких как кисть, прямоугольник, окружность, примая, а также инструменты заливки и рапылителя.
Рисунок 10 – Меню «Инструменты»
На рисунке 11 приведены примеры всех инструментов рисования доступных в программе.
Рисунок 11 – Примеры инструментов рисования
Для просмотра инвормации о программе надо выбрать пункт меню «О программе…»(Рисунок 12).
Для выхода из программы необходимо воспользоваться пунктом меню «Файл->Выход».
В курсовом проекте была реализована программа, позволяющая производить операции открытия, создания, редактирования и сохранения графических файлов, позволяет рисовать прямоугольники, окружности, прямые, рисовать кистью и распылителем. Поддерживаются выбираемые два цвета (фоновый и главный), смена размера кисти, загрузка картинок в формате JPG, GIF, PNG, BMP и сохранение в GIF, PNG, BMP. Были получены навыки и умения проектирования программного продукта на WinAPI.
Программа была протестирована, проверена на правильность выполнения операций: открытия, создания, редактирования и сохранения графических файлов и рисования с помощью графических примитивов.
Меню программы доступно и понятно пользователю.
Функциональная схема программы
Листинг программы
Модуль Main.cpp
#include "StdAfx.h"
#include "Main.h"
#include <math.h>
#ifdef NDEBUG
#pragma comment(linker,"/ALIGN:4096")
#pragma comment(linker,"/SUBSYSTEM:
#pragma comment(linker,"/MERGE:.rdata=
#pragma comment(linker,"/ENTRY:WMain")
#pragma comment(linker,"/NODEFAULTLIB"
#endif
#define CANVASWIDTH 1600
#define CANVASHEIGHT 1200
bool bDraw;
int x, y, x2, y2, x3, y3;
int px = 0, py = 0;
HBITMAP bmpBack, bmpUndo, bmpRedo, bmpForeMenu, bmpBackMenu;
HDC dcBack, dcMenuBmp, dcUndo, dcRedo, dcItemPaint;
HPEN pen;
HBRUSH brush;
wchar_t cBuf[1024];
OPENFILENAMEW ofn;
HDC dc;
int i, j;
DRAWITEMSTRUCT* disItem = NULL;
RECT rcTmp;
Gdiplus::GdiplusStartupInput gpsiGPSI;
Gdiplus::ImageCodecInfo iciArray[20];
ULONG_PTR upGDIP = 0;
Gdiplus::Bitmap* bmpLoaded;
Gdiplus::Graphics* grBack;
CHOOSECOLOR ccColor;
COLORREF crBrushColor, crBackColor, crTmp;
COLORREF ccArray[16];
char cFormat;
int iPenWidth = 3;
int iTool = 0;
HMENU mnuMain;
bool bFore = true;
int rad, dist;
HCRYPTPROV hProv;
SCROLLINFO sinfo;
template<typename T> int cmpstr(T* str1, T* str2, int iLen)
{
while (iLen > 0)
{
if (*str1 > *str2)
return 1;
if (*str1 < *str2)
return -1;
str1++;
str2++;
iLen--;
}
return 0;
}
template<typename T> void cpystr(T* dst, T* src, int iLen)
{
while (iLen > 0)
{
*dst++ = *src++;
iLen--;
}
}
template<typename T> int lenstr(T* str)
{
int iRes = 0;
while (*str)
{
str++;
iRes++;
}
return iRes;
}
void Spray(int iDens)
{
for (i = 0; i < iDens; i++)
{
CryptGenRandom(hProv, sizeof(x3), (BYTE*)&x3);
CryptGenRandom(hProv, sizeof(y3), (BYTE*)&y3);
x3 = x3 % iPenWidth;
y3 = y3 % iPenWidth;
SetPixel(dcBack, x3 + x2 + px, y3 + y2 + py, bFore ? crBrushColor : crBackColor);
SetPixel(dc, x3 + x2, y3 + y2, bFore ? crBrushColor : crBackColor);
}
}
void ClearChecks()
{
for (i = ID_40016; i <= ID_40028; i++)
CheckMenuItem(mnuMain, i, MF_UNCHECKED);
}
void ZeroMem(char* ptr, int len)
{
while (len--)
{
if (len) *ptr = 0;
ptr++;
}
}
bool OpenSaveDlg(bool bSave, HWND hDlg)
{
ZeroMem((char*)&ofn, sizeof(ofn));
cBuf[0] = '\0';
ofn.lStructSize = sizeof(OPENFILENAMEW);
ofn.hwndOwner = hDlg;
ofn.hInstance = GetModuleHandle(NULL);
if (!bSave)
ofn.lpstrFilter = L"Картинки (*.bmp;*.jpg;*.gif;*.png)\0*.
else
ofn.lpstrFilter = L"BMP\0*.bmp\0GIF\0*.gif\0PNG\
ofn.nMaxFile = sizeof(cBuf);
ofn.lpstrFile = &cBuf[0];
if (bSave)
ofn.lpstrTitle = L"Сохранить файл";
else
ofn.lpstrTitle = L"Открыть файл";
ofn.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
if (bSave)
ofn.Flags |= OFN_OVERWRITEPROMPT;
ofn.nFilterIndex = 1;
ofn.lpstrInitialDir = L".\\";
if (bSave)
{
if (!GetSaveFileNameW(&ofn)) return false;
}
else
{
if (!GetOpenFileNameW(&ofn)) return false;
}
return true;
}
void UpdateMenuBmp(HBITMAP bmp, COLORREF clr)
{
HDC dcTmp = CreateCompatibleDC(dcMenuBmp);
SelectObject(dcTmp, bmp);
rcTmp.left = 0;
rcTmp.right = 16;
rcTmp.top = 0;
rcTmp.bottom = 16;
brush = CreateSolidBrush(clr);
FillRect(dcTmp, &rcTmp, brush);
FrameRect(dcTmp, &rcTmp, (HBRUSH)GetStockObject(BLACK_
DeleteObject(brush);
DeleteDC(dcTmp);
}
BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
dcItemPaint = GetDC(GetDlgItem(hDlg, IDC_STATICPAINT));
bmpBack = CreateCompatibleBitmap(
bmpUndo = CreateCompatibleBitmap(
bmpRedo = CreateCompatibleBitmap(
dcBack = CreateCompatibleDC(
dcUndo = CreateCompatibleDC(dcBack);
dcRedo = CreateCompatibleDC(dcBack);
SelectObject(dcBack, bmpBack);
SelectObject(dcUndo, bmpUndo);
SelectObject(dcRedo, bmpRedo);
rcTmp.left = 0;
rcTmp.right = CANVASWIDTH;
rcTmp.top = 0;
rcTmp.bottom = CANVASHEIGHT;
FillRect(dcBack, &rcTmp, (HBRUSH)GetStockObject(WHITE_
FillRect(dcUndo, &rcTmp, (HBRUSH)GetStockObject(WHITE_
FillRect(dcRedo, &rcTmp, (HBRUSH)GetStockObject(WHITE_
Gdiplus::GdiplusStartup(&
cFormat = 'g';
crBrushColor = 0x000000;
crBackColor = 0xFFFFFF;
mnuMain = GetMenu(hDlg);
CheckMenuItem(mnuMain, ID_40013, MF_CHECKED);
CheckMenuItem(mnuMain, ID_40018, MF_CHECKED);
CheckMenuItem(mnuMain, ID_40031, MF_CHECKED);
dc = GetDC(hDlg);
bmpForeMenu = CreateCompatibleBitmap(dc, 16, 16);
bmpBackMenu = CreateCompatibleBitmap(dc, 16, 16);
dcMenuBmp = CreateCompatibleDC(dc);
ModifyMenu(mnuMain, ID_40011, MF_BITMAP, ID_40011, (LPCSTR)bmpForeMenu);
ModifyMenu(mnuMain, ID_40100, MF_BITMAP, ID_40100, (LPCSTR)bmpBackMenu);
UpdateMenuBmp(bmpForeMenu, crBrushColor);
UpdateMenuBmp(bmpBackMenu, crBackColor);
sinfo.cbSize = sizeof(sinfo);
sinfo.fMask = SIF_ALL;
sinfo.nMin = 0;
sinfo.nPage = 10;
sinfo.nPos = 0;
sinfo.nTrackPos = 0;
GetClientRect(hDlg, &rcTmp);
sinfo.nMax = CANVASWIDTH - rcTmp.right;
SetScrollInfo(hDlg, SB_HORZ, &sinfo, TRUE);
sinfo.nMax = CANVASHEIGHT - rcTmp.bottom;
SetScrollInfo(hDlg, SB_VERT, &sinfo, TRUE);
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
ReleaseDC(GetDlgItem(hDlg, IDC_STATICPAINT), dcItemPaint);
ReleaseDC(hDlg, dc);
return (TRUE);
case WM_CLOSE:
Gdiplus::GdiplusShutdown(
CryptReleaseContext(hProv, 0);
DestroyWindow(hDlg);
ExitProcess(0);
return (TRUE);
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
SetCapture(hDlg);
bDraw = true;
x = LOWORD(lParam);
y = HIWORD(lParam);
x3 = x;
y3 = y;
bFore = message == WM_LBUTTONDOWN;
BitBlt(dcUndo, 0, 0, CANVASWIDTH, CANVASHEIGHT, dcBack, 0, 0, SRCCOPY);
break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
if (!bDraw)
return FALSE;
ReleaseCapture();
bDraw = false;
x2 = (signed short)LOWORD(lParam);
y2 = (signed short)HIWORD(lParam);
pen = CreatePen(PS_SOLID, iPenWidth, bFore ? crBrushColor : crBackColor);
SelectObject(dcBack, pen);
SelectObject(dcBack, GetStockObject(HOLLOW_BRUSH));
switch (iTool)
{
case 0:
MoveToEx(dcBack, x + px, y + py, NULL);
LineTo(dcBack, x2 + px, y2 + py);
break;
case 1:
Rectangle(dcBack, x3 + px, y3 + py, x2 + px, y2 + py);
break;
case 2:
Ellipse(dcBack, x3 + px, y3 + py, x2 + px, y2 + py);
break;
case 3:
MoveToEx(dcBack, x3 + px, y3 + py, NULL);
LineTo(dcBack, x2 + px, y2 + py);
break;
case 4:
brush = CreateSolidBrush(bFore ? crBrushColor : crBackColor);
SelectObject(dcBack, brush);
ExtFloodFill(dcBack, x2 + px, y2 + py, GetPixel(dcBack, x2 + px, y2 + py), FLOODFILLSURFACE);
DeleteObject(brush);
break;
case 5:
Spray(iPenWidth);
break;
}
DeleteObject(pen);
InvalidateRect(GetDlgItem(
return TRUE;
case WM_MOUSEMOVE:
if (!bDraw)
break;
x2 = (signed short)LOWORD(lParam);
y2 = (signed short)HIWORD(lParam);
if (x2 > CANVASWIDTH - iPenWidth)
x2 = CANVASWIDTH - iPenWidth;
if (y2 > CANVASHEIGHT - iPenWidth)
y2 = CANVASHEIGHT - iPenWidth;
dc = GetDC(GetDlgItem(hDlg, IDC_STATICPAINT));
pen = CreatePen(PS_SOLID, iPenWidth, bFore ? crBrushColor : crBackColor);
SelectObject(dc, pen);
SelectObject(dcBack, pen);
switch (iTool)
{
case 0:
MoveToEx(dc, x, y, NULL);
LineTo(dc, x2, y2);
MoveToEx(dcBack, x + px, y + py, NULL);
LineTo(dcBack, x2 + px, y2 + py);
break;
case 1:
i = SetROP2(dc, R2_NOTXORPEN);
Rectangle(dc, x3, y3, x, y);
Rectangle(dc, x3, y3, x2, y2);
SetROP2(dc, i);
break;
case 2:
i = SetROP2(dc, R2_NOTXORPEN);
SelectObject(dc, GetStockObject(HOLLOW_BRUSH));
Ellipse(dc, x3, y3, x, y);
Ellipse(dc, x3, y3, x2, y2);
SetROP2(dc, i);
break;
case 3:
i = SetROP2(dc, R2_NOTXORPEN);
MoveToEx(dc, x3, y3, NULL);
LineTo(dc, x2, y2);
MoveToEx(dc, x3, y3, NULL);
LineTo(dc, x, y);
SetROP2(dc, i);
break;
case 5:
Spray(iPenWidth);
break;
}
x = x2;
y = y2;
DeleteObject(pen);
ReleaseDC(hDlg, dc);
break;
case WM_HSCROLL:
case WM_VSCROLL:
sinfo.fMask = SIF_POS | SIF_RANGE;
GetScrollInfo(hDlg, message == WM_HSCROLL ? SB_HORZ : SB_VERT, &sinfo);
switch(LOWORD(wParam))
{
case SB_PAGEUP:
i = sinfo.nPos - sinfo.nPage;
break;
case SB_PAGEDOWN:
i = sinfo.nPos + sinfo.nPage;
break;
case SB_LINEUP:
i = sinfo.nPos - 10;
break;
case SB_LINEDOWN:
i = sinfo.nPos + 10;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
i = HIWORD(wParam);
break;
}
i < 0 ? i = 0 : i = i;
i > sinfo.nMax ? i = sinfo.nMax : i = i;
sinfo.fMask = SIF_POS;
sinfo.nPos = i;
SetScrollInfo(hDlg, message == WM_HSCROLL ? SB_HORZ : SB_VERT, &sinfo, TRUE);
if (message == WM_HSCROLL)
px = i;
else
py = i;
InvalidateRect(GetDlgItem(
return FALSE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case ID_40005:
case ID_ACCELERATOR40055:
rcTmp.left = 0;
rcTmp.right = CANVASWIDTH;
rcTmp.top = 0;
rcTmp.bottom = CANVASHEIGHT;
FillRect(dcBack, &rcTmp, (HBRUSH)GetStockObject(WHITE_
InvalidateRect(GetDlgItem(
return TRUE;
case ID_40006:
case ID_ACCELERATOR40056:
if (!OpenSaveDlg(false, hDlg)) return FALSE;
rcTmp.left = 0;
rcTmp.right = CANVASWIDTH;
rcTmp.top = 0;
rcTmp.bottom = CANVASHEIGHT;
FillRect(dcBack, &rcTmp, (HBRUSH)GetStockObject(WHITE_
InvalidateRect(GetDlgItem(
bmpLoaded = Gdiplus::Bitmap::FromFile(ofn.
grBack = Gdiplus::Graphics::FromHDC(
grBack->DrawImage(bmpLoaded, 0, 0);
delete bmpLoaded;
delete grBack;
InvalidateRect(GetDlgItem(
return TRUE;
case ID_40007:
case ID_ACCELERATOR40057:
if (!OpenSaveDlg(true, hDlg)) return FALSE;
switch(ofn.nFilterIndex)
{
case 1:
if (cmpstr<wchar_t>(&ofn.
cpystr<wchar_t>(&ofn.
cFormat = 'b';
break;
case 2:
if (cmpstr<wchar_t>(&ofn.
cpystr<wchar_t>(&ofn.
cFormat = 'g';
break;
case 3:
if (cmpstr<wchar_t>(&ofn.
cpystr<wchar_t>(&ofn.
cFormat = 'p';
break;
}
DeleteFileW(ofn.lpstrFile);
bmpLoaded = Gdiplus::Bitmap::FromHBITMAP(
Gdiplus::GetImageEncodersSize(
Gdiplus::GetImageEncoders(i, j, &iciArray[0]);
i = 0;
while (iciArray[i].MimeType[6] != cFormat) i++;
bmpLoaded->Save(ofn.lpstrFile, &iciArray[i].Clsid, NULL);
delete bmpLoaded;
return TRUE;
case ID_40009:
case ID_ACCELERATOR40058:
SendMessage(hDlg, WM_CLOSE, 0, 0);
return TRUE;
case ID_40010:
MessageBox(hDlg, "MicroPaint\nВерсия 2.0", "О программе...", MB_ICONINFORMATION);
return TRUE;
case ID_40011:
case ID_40100:
ZeroMem((char*)&ccColor, sizeof(ccColor));
ccColor.lStructSize = sizeof(ccColor);
ccColor.hwndOwner = hDlg;