背景
前面一期《孔明棋》写的内容有点多,但是里面的函数功能都没有详细说明,这一期就分解一下前一期中的一些函数功能,讲解一下完成一个弹窗需要哪些函数。
如果我们只是需要一个简简单单的弹窗
只需要一行代码就能实现
MessageBox(NULL, _T("这是一个弹窗"), _T("My Message Box"), MB_YESNO | MB_ICONINFORMATION);
但是如果我们想要一个动态的按钮。
就需要很多行代码
源码
///////////////////////////////////////////////////
// 程序名称:弹窗
// 编译环境:Mictosoft Visual Studio 2022, EasyX_20200315(beta)
// 作 者:luoyh <2864292458@qq.com>
// 公 众 号:C语言研究
// 最后修改:2024-11-20
//
int rW = GetSystemMetrics(SM_CXSCREEN); // 屏幕宽度 像素
int rH = GetSystemMetrics(SM_CYSCREEN); // 屏幕高度 像素
struct Button
{
int X1; // 左上角
int Y1;
int X2; // 右下角
int Y2;
int size; // 字体大小
LPCTSTR str; // 对应文本
};
void Full_Screen(); // 全屏
bool WINDOWS(LPCTSTR str, LPCTSTR str1, LPCTSTR str2); // 弹窗
void DrawButtonT(Button button, COLORREF color, LOGFONT f); // 绘制按钮
// 渐变色
void GradientFill(int left, int top, int right, int bottom, COLORREF startColor, COLORREF endColor);
int main()
{
Full_Screen(); // 全屏
WINDOWS(_T("这是一个弹窗"), _T("确定"), _T("取消")); // 弹窗
return 0;
}
void Full_Screen() // 全屏
{
HWND hwnd = initgraph(rW, rH); // 初始化绘图窗口并获取窗口句柄(以 EasyX 为例)
LONG l_WinStyle = GetWindowLong(hwnd, GWL_STYLE); // 获取窗口信息
// 设置窗口信息 最大化 取消标题栏及边框
SetWindowLong(hwnd, GWL_STYLE, (l_WinStyle | WS_POPUP | WS_MAXIMIZE) & ~WS_CAPTION & ~WS_THICKFRAME & ~WS_BORDER);// 直接修改窗口样式
SetWindowPos(hwnd, HWND_TOP, 0, 0, rW, rH, 0);
setbkcolor(BLACK);
cleardevice(); // 设置背景颜色为黑色
}
void DrawButtonT(Button button, COLORREF color, LOGFONT f) // 绘制按钮
{
setbkmode(TRANSPARENT);
RECT r = { button.X1, button.Y1, button.X2, button.Y2 };
settextcolor(color);
if (color == WHITE)
{
setfillcolor(RGB(30, 30, 30));
setlinecolor(RGB(20, 20, 20));
fillrectangle(button.X1, button.Y1, button.X2, button.Y2);
}
else
{
GradientFill(button.X1, button.Y1, button.X2, button.Y2, WHITE, BLACK);
}
settextstyle(&f); // 设置字体样式
drawtext(button.str, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
bool WINDOWS(LPCTSTR str, LPCTSTR str1, LPCTSTR str2)
{
LOGFONT f;
gettextstyle(&f); // 获取当前字体设置
f.lfHeight = 40; // 设置字体高度为
_tcscpy_s(f.lfFaceName, _T("楷体")); // 设置字体为“黑体”(高版本 VC 推荐使用 _tcscpy_s 函数)
f.lfQuality = ANTIALIASED_QUALITY; // 设置输出效果为抗锯齿
settextstyle(&f); // 设置字体样式
// 弹窗长
int TC = 1000;
// 弹窗高
int TH = 300;
int TX1 = (rW - TC) / 2;
int TX2 = TX1 + TC;
int TY1 = (rH - TH) / 2;
int TY2 = TY1 + TH;
RECT r = { TX1,TY1,TX2,TY2 };
int TXZ = TX1 + TC / 2;
Button button4 = { TX1, TY2, TXZ, TY2 + 65, 40, str1 };
Button button5 = { TXZ, TY2, TX2, TY2 + 65, 40,str2 };
ExMessage msg;
BeginBatchDraw();
bool T = true; // 控制循环
bool R = true; // 控制返回值
int NUMS = 0;
// 游戏的主循环
while (T)
{
FlushBatchDraw();
cleardevice();
setfillcolor(RGB(20, 20, 20));
solidrectangle(TX1, TY1, TX2, TY2);
drawtext(str, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawButtonT(button4, WHITE, f);
DrawButtonT(button5, WHITE, f);
while (peekmessage(&msg, EX_MOUSE)) // 如果获取到了消息就执行
{
switch (msg.message)
{
case WM_MOUSEMOVE:
if (msg.x > button4.X1 && msg.x<button4.X2 && msg.y>button4.Y1 && msg.y < button4.Y2)
{
NUMS = 1;
}
if (msg.x > button5.X1 && msg.x<button5.X2 && msg.y>button5.Y1 && msg.y < button5.Y2)
{
NUMS = 2;
}
break;
case WM_LBUTTONDOWN:
if (msg.x > button4.X1 && msg.x<button4.X2 && msg.y>button4.Y1 && msg.y < button4.Y2)
{
NUMS = 3;
}
if (msg.x > button5.X1 && msg.x<button5.X2 && msg.y>button5.Y1 && msg.y < button5.Y2)
{
NUMS = 4;
}
break;
}
}
switch (NUMS)
{
case 0:break;
case 1:
DrawButtonT(button4, BLACK, f);
DrawButtonT(button5, WHITE, f);
break;
case 2:
DrawButtonT(button5, BLACK, f);
DrawButtonT(button4, WHITE, f);
break;
case 3:
T = false;
R = false; // 确定退出
break;
case 4:
T = false;
R = true;
break; // 开始游戏
}
}
EndBatchDraw();
return R;
}
void GradientFill(int left, int top, int right, int bottom, COLORREF startColor, COLORREF endColor)
{ // 计算水平和垂直方向上的颜色变化量
double dx = right - left;
double dy = bottom - top;
double redStep = (GetRValue(endColor) - GetRValue(startColor)) / dx;
double greenStep = (GetGValue(endColor) - GetGValue(startColor)) / dx;
double blueStep = (GetBValue(endColor) - GetBValue(startColor)) / dx; // 遍历每个像素点,并设置其颜色
for (int x = left; x <= right; x++)
{
COLORREF currentColor = RGB(GetRValue(startColor) + (x - left) * redStep, GetGValue(startColor) + (x - left) * greenStep, GetBValue(startColor) + (x - left) * blueStep);
setfillcolor(currentColor); solidrectangle(x, top, x, bottom); // 填充当前列的颜色
}
}
介绍
实现以上整个功能看起来很复杂,其实总共使用了四个函数。
第一个函数
把界面设置为全屏。
void Full_Screen();
这个函数能够让我们界面为全屏,能够提高程序的观赏性。一般如果想写一个完美的程序,离不开这个功能。
第二个函数
一个渐变色的色条
void GradientFill(int left, int top, int right, int bottom, COLORREF startColor, COLORREF endColor)
这个函数是绘制按钮的组成部分。渐变色就是一个矩形框,然后赋予它起始色,再定义一个终止色。这个函数前面我有一篇文章介绍过可以点击查看,渐变色条。
第三个函数
绘制按钮
void DrawButtonT(Button button, COLORREF color, LOGFONT f); // 绘制按钮
绘制这个按钮还需要一个结构体
struct Button
{
int X1; // 左上角
int Y1;
int X2; // 右下角
int Y2;
int size; // 字体大小
LPCTSTR str; // 对应文本
};
第四个函数
绘制弹窗
bool WINDOWS(LPCTSTR str, LPCTSTR str1, LPCTSTR str2); // 弹窗
前三个函数都是为了绘制弹窗服务。
如果要了解更多细节,建议放到编译器中运行,然后自己动手修改一下参数就知道每一个函数的具体意义了,这是学习的最好方法。