最近老师让我们自己做一个项目,刚好前段时间学过图形学,于是就有了下面画图工具,
转载请说明出处
项目环境:Visual studio2019
直接上代码,可直接复制运行
test.cpp文件:
#include"tool.h"
TCHAR a[100];
void Kaishi()
{
initgraph(520, 360, NULL);
IMAGE bgp;
loadimage(&bgp, L"./am.jpg", 520, 360, false);//加载图片
putimage(0, 0, &bgp);
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
settextstyle(40, 30, L"宋体");
outtextxy(20, 130, L"欢迎使用");
Sleep(3000);
closegraph;
}
void Shubiao()
{
A:Caidanlan();//菜单栏
int x = 0, y = 0;//存储鼠标坐标
int i = 0, j = 0;
MOUSEMSG m;// 定义消息变量
while (true)
{
m = GetMouseMsg();// 获取一条鼠标或按键消息
setfillcolor(BLACK);
solidrectangle(0, 570, 100, 600); //用黑色矩形(界面是黑色)覆盖上次的坐标
//因为鼠标在移动的过程中坐标位置是不断变化的
_stprintf_s(a, _T("[%d,%d]"), m.x, m.y);//将坐标写到字符串a中
//setcolor(WHITE);
outtextxy(0, 580, a);//循环打印当前坐标位置
if (m.uMsg == WM_LBUTTONDOWN)//判断鼠标点击位置
{
x = m.x, y = m.y;
if (x >= 40 && x <= 80 && y >= 10 && y <= 40)//白
i = 1;
else if (x >= 100 && x <= 140 && y >= 10 && y <= 40)//蓝
i = 2;
else if (x >= 160 && x <= 200 && y >= 10 && y <= 40)//黄
i = 3;
else if (x >= 200 && x <= 260 && y >= 10 && y <= 40)//红
i = 4;
else if (x >= 330 && x <= 390 && y >= 10 && y <= 40)//画笔
{
j = 1;
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(330, 10, 390, 40);//画一个实心的绿色矩形
setfillcolor(GREEN); //设置实心颜色为绿
solidrectangle(333, 13, 393, 43);//画一个实心的绿色矩形
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
outtextxy(333 + 14, 20, L"画笔");
Sleep(100);
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(330, 10, 393, 43);//画一个实心的绿色矩形
setcolor(WHITE);
rectangle(330, 10, 390, 40); //画一个矩形边框
outtextxy(330+14, 17, L"画笔");
}
else if (x >= 410 && x <= 470 && y >= 10 && y <= 40)//直线
{
j = 2;
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(410, 10, 470, 40);//画一个实心的绿色矩形
setfillcolor(GREEN); //设置实心颜色为绿
solidrectangle(413, 13, 473, 43);//画一个实心的绿色矩形
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
outtextxy(413 + 14, 20, L"直线");
Sleep(100);
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(410, 10, 473, 43);//画一个实心的绿色矩形
setcolor(WHITE);
rectangle(410, 10, 470, 40); //画一个矩形边框
outtextxy(410 + 14, 17, L"直线");
}
else if (x >= 490 && x <= 550 && y >= 10 && y <= 40)//曲线
{
j = 3;
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(490, 10, 550, 40);//画一个实心的绿色矩形
setfillcolor(GREEN); //设置实心颜色为绿
solidrectangle(493, 13, 553, 43);//画一个实心的绿色矩形
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
outtextxy(493 + 14, 20, L"曲线");
Sleep(100);
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(490, 10, 553, 43);//画一个实心的绿色矩形
setcolor(WHITE);
rectangle(490, 10, 550, 40); //画一个矩形边框
outtextxy(490 + 14, 17, L"曲线");
}
else if (x >= 570 && x <= 630 && y >= 10 && y <= 40)//圆
{
j = 4;
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(570, 10, 630, 40);//画一个实心的绿色矩形
setfillcolor(GREEN); //设置实心颜色为绿
solidrectangle(573, 13, 633, 43);//画一个实心的绿色矩形
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
outtextxy(573 + 14, 20, L"画圆");
Sleep(100);
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(570, 10, 633, 43);//画一个实心的绿色矩形
setcolor(WHITE);
rectangle(570, 10, 630, 40); //画一个矩形边框
outtextxy(570 + 14, 17, L"画圆");
}
else if (x >= 650 && x <= 710 && y >= 10 && y <= 40)//填充
{
j = 5;
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(650, 10, 710, 40);//画一个实心的绿色矩形
setfillcolor(GREEN); //设置实心颜色为绿
solidrectangle(653, 13, 713, 43);//画一个实心的绿色矩形
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
outtextxy(653 + 14, 20, L"填充");
Sleep(100);
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(650, 10, 713, 43);//画一个实心的绿色矩形
setcolor(WHITE);
rectangle(650, 10, 710, 40); //画一个矩形边框
outtextxy(650 + 14, 17, L"填充");
}
else if (x >= 730 && x <= 790 && y >= 10 && y <= 40)//清空
{
j = 6;
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(730, 10, 790, 40);//画一个实心的绿色矩形
setfillcolor(GREEN); //设置实心颜色为绿
solidrectangle(733, 13, 793, 43);//画一个实心的绿色矩形
setbkmode(TRANSPARENT); //字符透明
settextcolor(RGB(97, 274, 255));
outtextxy(733 + 14, 20, L"重启");
Sleep(100);
setfillcolor(BLACK); //设置实心颜色为绿
solidrectangle(730, 10, 793, 43);//画一个实心的绿色矩形
setcolor(WHITE);
rectangle(730, 10, 790, 40); //画一个矩形边框
outtextxy(730 + 14, 17, L"重启");
}
}
i = Izhi(i);//判断i值在哪个颜色区域内并闪烁一次绿色,执行相应功能并重置i值为0
//Jzhi(j);//判断j值并执行相应功能
if (j == 1 && m.y >= 50)
{
Huabi(i);//画笔工具
}
if (j == 2 && m.y >= 50)
{
ZhixianYuan(i,j);//直线工具
}
if (j == 3 && m.y >= 50)
{
Quxian(i);//曲线工具
}
if (j == 4 && m.y >= 50)
{
ZhixianYuan(i,j);//画圆工具
}
if (j == 5)
{
Tianchong();//填充工具
}
if (j == 6 )
{
cleardevice();//用背景色清空屏幕
goto A;
}
}
}
int main()
{
Kaishi();//开始
initgraph(800, 600);
IMAGE bgp;
loadimage(&bgp, L"./am.jpg", 80, 40, false);//加载图片
putimage(720, 560, &bgp);
Shubiao();//开始判断鼠标坐标
_getch(); // 按任意键继续
closegraph(); // 关闭图形界面
return 0;
}
tool.cpp文件:
#include"tool.h"
TCHAR b[100];
void Caidanlan()//菜单栏
{
setcolor(WHITE);
outtextxy(10, 10, L"颜");
outtextxy(10, 30, L"色");
setfillcolor(WHITE); //设置实心颜色为白
solidrectangle(40, 10, 80, 40);//画一个实心的红色矩形
setfillcolor(BLUE); //设置实心颜色为蓝
solidrectangle(100, 10, 140, 40);//画一个实心的红色矩形
setfillcolor(YELLOW); //设置实心颜色为黄
solidrectangle(160, 10, 200, 40);//画一个实心的红色矩形
setfillcolor(RED); //设置实心颜色为红
solidrectangle(220, 10, 260, 40);//画一个实心的红色矩形
outtextxy(300, 10, L"工");
outtextxy(300, 30, L"具");
rectangle(330, 10, 390, 40); //画一个矩形边框
outtextxy(344, 17, L"画笔"); //将这两字写在上面画的矩形边框里
rectangle(410, 10, 470, 40); //画一个矩形边框
outtextxy(424, 17, L"直线"); //将这两字写在上面画的矩形边框里
rectangle(490, 10, 550, 40); //画一个矩形边框
outtextxy(504, 17, L"曲线"); //将这两字写在上面画的矩形边框里
rectangle(570, 10, 630, 40); //画一个矩形边框
outtextxy(584, 17, L"画圆"); //将这两字写在上面画的矩形边框里
rectangle(650, 10, 710, 40); //画一个矩形边框
outtextxy(664, 17, L"填充"); //将这两字写在上面画的矩形边框里
rectangle(730, 10, 790, 40); //画一个矩形边框
outtextxy(744, 17, L"重启"); //将这两字写在上面画的矩形边框里
setcolor(WHITE);
line(0, 50, 800, 50);//菜单栏分界线
}
int Izhi(int i)//i值
{
switch (i)//判断i值并给出相应回应
{
case 1:
setfillcolor(GREEN); //点击变化颜色
solidrectangle(40, 10, 80, 40);//画一个实心的绿色矩形
Sleep(100);
setfillcolor(WHITE); //点击变化颜色
solidrectangle(40, 10, 80, 40);//画一个实心的白色矩形
setcolor(WHITE);
return 0;
case 2:
setfillcolor(GREEN); //点击变化颜色
solidrectangle(100, 10, 140, 40);//画一个实心的绿色矩形
Sleep(100);
setfillcolor(BLUE); //点击变化颜色
solidrectangle(100, 10, 140, 40);//画一个实心的白色矩形
setcolor(BLUE);
return 0;
case 3:
setfillcolor(GREEN); //点击变化颜色
solidrectangle(160, 10, 200, 40);//画一个实心的绿色矩形
Sleep(100);
setfillcolor(YELLOW); //点击变化颜色
solidrectangle(160, 10, 200, 40);//画一个实心的黄色矩形
setcolor(YELLOW);
return 0;
case 4:
setfillcolor(GREEN); //点击变化颜色
solidrectangle(220, 10, 260, 40);//画一个实心的绿色矩形
Sleep(100);
setfillcolor(RED); //点击变化颜色
solidrectangle(220, 10, 260, 40);//画一个实心的红色矩形
setcolor(RED);
return 0;
default:
return 0;
}
}
void Huabi(int i)//实现画笔工具
{
MOUSEMSG m;
int x = 0;
int y = 0;
int flag = 0;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
flag = 0;
while (1)
{
m = GetMouseMsg();
x = m.x, y = m.y;
setfillcolor(BLACK);
solidrectangle(0, 570, 100, 600);
_stprintf_s(b, _T("[%d,%d]"), x, y);
//setcolor(WHITE);
outtextxy(0, 580, b);
i = Izhi(i);//判断i值在哪个颜色区域内并闪烁一次绿色,执行相应功能并重置i值为0
if (m.y >= 0 && m.y < 50)//判断鼠标是否在可画区域内
{
break;
}
if (m.uMsg == WM_LBUTTONDOWN)//判断鼠标是否按下
{
if (flag == 0)
{
x1 = m.x;
y1 = m.y;
flag = 1;
}
}
else if (m.uMsg == WM_MOUSEMOVE && flag == 1)//判断鼠标是否连续滑动
{
x2 = m.x;
y2 = m.y;
line(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}
if (m.uMsg == WM_LBUTTONUP)//判断鼠标是否弹起
flag = 0;
}
}
void ZhixianYuan(int i,int j)//实现直线工具和画圆
{
MOUSEMSG m;
int x = 0;
int y = 0;
int flag = 0;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
flag = 0;
while (1)
{
m = GetMouseMsg();
x = m.x, y = m.y;
setfillcolor(BLACK);
solidrectangle(0, 570, 100, 600);
_stprintf_s(b, _T("[%d,%d]"), x, y);
//setcolor(WHITE);
outtextxy(0, 580, b);
i = Izhi(i);//判断i值在哪个颜色区域内并闪烁一次绿色,执行相应功能并重置i值为0
if (m.y >= 0 && m.y < 50)//判断鼠标是否在可画区域内
{
break;
}
if (m.uMsg == WM_LBUTTONDOWN)//判断鼠标是否按下
{
if (flag == 0)
{
x1 = m.x;
y1 = m.y;
flag = 1;
}
}
else if (m.uMsg == WM_LBUTTONUP && flag == 1)//判断鼠标是否弹起
{
x2 = m.x;
y2 = m.y;
if (j == 2)
{
line(x1, y1, x2, y2);//中点画线算法
}
if (j == 4)
{
Yuan(x1, y1, x2, y2);//中点画圆算法
}
flag = 0;
}
}
}
void Quxian(int i)//实现曲线工具
{
MOUSEMSG m;
int x = 0;
int y = 0;
int flag = 0;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0;
flag = 0;
while (1)
{
m = GetMouseMsg();
x = m.x, y = m.y;
setfillcolor(BLACK);
solidrectangle(0, 570, 100, 600);
_stprintf_s(b, _T("[%d,%d]"), x, y);
//setcolor(WHITE);
outtextxy(0, 580, b);
i = Izhi(i);//判断i值在哪个颜色区域内并闪烁一次绿色,执行相应功能并重置i值为0
if (m.y >= 0 && m.y < 50)//判断鼠标是否在可画区域内
{
break;
}
if (m.uMsg == WM_LBUTTONDOWN && flag == 0)//判断鼠标是否按下
{
x1 = m.x;
y1 = m.y;
flag = 1;
}
else if (m.uMsg == WM_LBUTTONUP && flag == 1)//判断鼠标是否弹起
{
x2 = m.x;
y2 = m.y;
line(x1, y1, x2, y2);
flag = 2;
}
else if (m.uMsg == WM_LBUTTONDOWN && flag == 2)//判断鼠标是否再次按下
{
x3 = m.x;
y3 = m.y;
BezierQuxian(x1, y1, x2, y2, x3, y3);//Bezier曲线
setcolor(BLACK);
line(x1, y1, x2, y2);//用背景色覆盖之前的直线
setcolor(WHITE);//恢复默认白色,避免无法显示坐标
flag = 0;
}
}
}
void Tianchong()//实现填充工具
{
MOUSEMSG m;
int x = 0;
int y = 0;
int flag = 0;
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
flag = 0;
int newcolor;
while (1)
{
m = GetMouseMsg();
x = m.x, y = m.y;
setfillcolor(BLACK);
solidrectangle(0, 570, 100, 600);
_stprintf_s(b, _T("[%d,%d]"), x, y);
outtextxy(0, 580, b);
if (m.x >= 330 && m.x <= 800 && m.y >= 0 && m.y < 50)//判断鼠标是否在可画区域内
{
break;
}
if (m.uMsg == WM_LBUTTONDOWN && flag == 0)//判断鼠标是否按下
{
x = m.x, y = m.y;
if (x >= 40 && x <= 80 && y >= 10 && y <= 40)//白
{
newcolor = WHITE;
flag = 1;
}
else if (x >= 100 && x <= 140 && y >= 10 && y <= 40)//蓝
{
newcolor = BLUE;
flag = 1;
}
else if (x >= 160 && x <= 200 && y >= 10 && y <= 40)//黄
{
newcolor = YELLOW;
flag = 1;
}
else if (x >= 200 && x <= 260 && y >= 10 && y <= 40)//红
{
newcolor = RED;
flag = 1;
}
}
else if (m.uMsg == WM_LBUTTONUP && flag == 1)//判断鼠标是否弹起
{
flag = 2;
}
else if (m.uMsg == WM_LBUTTONDOWN && flag == 2)//判断鼠标是否再次按下
{
x2 = m.x;
y2 = m.y;
FloodFILL(x2, y2, BLACK, newcolor);//四连通泛填充算法
flag = 0;
}
}
}
tool.h文件:
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include// 引用图形库头文件 #include #include #include using namespace std; //tool.cpp void Caidanlan();//菜单栏 int Izhi(int i);//i值 void Huabi(int i);//画笔 void ZhixianYuan(int i,int j);//直线和圆 void Quxian(int i);//曲线 void Tianchong();//填充 //algorithm.cpp void Yuan(float x1, float y1, float x2, float y2);//圆 void BezierQuxian(int x1,int y1, int x2,int y2,int x3,int y3);//曲线 void FloodFILL(int x, int y, int black, int newcolor);//填充
algorithm.cpp文件:
#include"tool.h"
void Yuan(float x1, float y1, float x2, float y2)//中点画圆算法
{
float r = 0;
float x0 = (x1 + x2) / 2, y0 = (y1 + y2) / 2;
r = (sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))) / 2;
float x, y, d;
x = 0;
y = r; //(x,y)用于确定第一个点
d = 1 - r; //取得初始d
float H; //用于判断x或y循环的次数
H = 1.414 * r / 2;
for (int i = 1; i <= H+1; i++) {
line(x + x0, y + y0, x + x0, y + y0);
line(y + x0, x + y0, y + x0, x + y0);
line(-x + x0, y + y0, -x + x0, y + y0);
line(-y + x0, x + y0, -y + x0, x + y0);
line(x + x0, -y + y0, x + x0, -y + y0);
line(y + x0, -x + y0, y + x0, -x + y0);
line(-x + x0, -y + y0, -x + x0, -y + y0);
line(-y + x0, -x + y0, -y + x0, -x + y0);
if (d < 0) {
x = x + 1;
d = d + 2 * x + 3;
}
else {
x = x + 1;
y = y - 1;
d = d + 2 * (x - y) + 5;
}
}
}
void FloodFILL(int x, int y, int bodercolor, int newcolor)//四连通泛填充算法
{
int color = getpixel(x, y);
if (color == bodercolor ) //判断是否到了边界
{
putpixel(x, y, newcolor);
FloodFILL(x, y + 1, bodercolor, newcolor);
FloodFILL(x, y - 1, bodercolor, newcolor);
FloodFILL(x - 1, y, bodercolor, newcolor);
FloodFILL(x + 1, y, bodercolor, newcolor);
}
}
void BezierQuxian(int x1,int y1,int x2,int y2,int x3,int y3)//Bezier曲线
{
float t = 0;
for (t = 0.001; t < 1; t = t + 0.00001)
{
float px01 = (1 - t) * x1 + t * x3;
float px11 = (1 - t) * x3 + t * x2;
float py01 = (1 - t) * y1 + t * y3;
float py11 = (1 - t) * y3 + t * y2;
float px02 = (1 - t) * px01 + t * px11;
float py02 = (1 - t) * py01 + t * py11;
line(px02, py02, px02, py02);
}
}
am.jpg文件:
一共有test.cpp、tool.cpp、tool.h、algorithm.cpp四个代码文件和一个am.jpg图片文件,
根据老师要求,其中的绘制算法都是根据计算机图形学这本书自己写的,并非直接调用函数库,所以代码有点多。
演示效果如下:



