随波逐流的空间

希望每天黎明有着希望的光茫,照耀着并希望着,我们每天思考一步,就要想到做第三步。

EasyX 绘图库硬核实现基于配置文件动态创建 GUI 按钮实例教程

更新

1.新增在按钮函数内直接填写按钮文本(2022 - 9 - 14)
2.新增在 WIN10 系统下分辨率不会被系统更改变大使的程序更加精致,除了个别 WIN10 系统不会因此项增加改变外,原因不明(2022 - 9 - 14)

更新后使用例子:

	while (true)
		{
			mouse = getmessage(EM_MOUSE | EM_KEY);

			if (mouse.message == WM_MOUSEMOVE)
			{

				button(10, 10, 110, 45, mouse.x, mouse.y, 14, 15, _T("GUI 按钮实例"), _T("GUI 按钮实例"), 0);

			}

			if (mouse.message == WM_LBUTTONDOWN)
			{

				if (button(10, 10, 110, 45, mouse.x, mouse.y, 14, 15, _T("GUI 按钮实例"), _T("GUI 按钮实例"), 1) == 1)
					MessageBox(GetHWnd(), L"已点击", L"提示", MB_ICONWARNING);

			}

		}

作者前言 

奈叶敬在学校时期曾接触过名为 graphics.h 的绘图库,当时也查过是绘图库,该绘图库是直接在 devcpp 编译器上运行的,年代似乎没记错的话该编译器版本是 2004 年来着?编译器是偷偷用电脑传输图片功能传进来的,是把压缩包改成 JPG 格式的后缀,就传进去了,很是神奇的 BUG。当时电脑禁用 USB 文件传输。过去了这么久,用现在的眼光来看 EasyX 这个绘图库就觉得很有趣,大家也一样觉得吧?嘿嘿!尽管知道当初的绘图库不是 EasyX,没办法谁叫官方教程制作的太好了呢!因为现在需要一个门店收入汇总的小程序,之前都是用 devcpp 写的命令行版本,说的就是界面还是黑黑呼呼的那个。一点也不人性化,其实!就是不好看啊呀!对吧?突然哇,有一次我突灵光一现的在本子上绘制汇总小程序界面草图,一直到用 Excel 表格把本子上的草图绘制出来。

就偶然想起了 EasyX 绘图库,用了一点时间照着慢羊羊的官方教程去使用 EasyX 开发,初写程序就是图片 x、y 文字坐标定位器和 PS 取色器,硬是把 Excel 上的汇总小程序的表格模板,一点点的绘图,改成图形界面,然后嘛就做出来了啦!!果然和表格数据的界面一模一样,这就是绘图库的诱人的魅力吗?对于人性化的程序简直就是光!但是发现那个汇总小程序需要按钮和输入框,EasyX 但也只是绘图库,没有这些东东怎么办呢?丰衣自足呀?所以把汇总小程序里的按钮实现方式给有需要做 EasyX GUI 程序的小伙伴门参考一下,绘图库它可不是简简单单的绘图作用哎!

高亮按钮简单原理

就是绘制一个有颜色边框且又有填充颜色的矩形,然后使用 drawtext 函数,把文字居中在该矩形坐标里内,这样一个基本按钮界面就画好了。然后还需要鼠标移动到按钮界面上,把这个矩形颜色和按钮字体颜色改变,就有一种按钮被选中的视觉差。这里我定义了一个函数,把按钮位置坐标、和传入的时实鼠标坐标、和按钮输出文本、和按钮字体大小、都封装在一起。当调用 button 按钮创建函数时,鼠标坐标没有移动到该按钮内部里时,会画一下按钮没有被选中时的矩形颜色,就是基本文字按钮界面,当 button 函数里的 if 判断鼠标坐标移动到该按钮上的坐标里,就使用 button 函数内另一个画有颜色的矩形,和别一个 drawtext 输出文体。从而复盖原有的矩形颜色和文本,简单来说就是刷新了按钮。刷新成被鼠标选中的高亮按钮样式!然后就有一种按钮被选中的视觉差,如果该按钮被点击了就会返回一个 1,这个值很重要,可以通过 if 去判断鼠标是否被点中。

现在介绍一下按钮关键的函数,button 按钮创建函数和 buttonparm 鼠标坐标传参函数

配置文件创建按钮原理

button 函数介绍 

button 函数(简单型按钮创建函数)

button 按钮创建函数如果被点击了会返回一个值,那个值就是 1 可以通过 if 去判断是否被点击了。可以由你任意指定坐标位置进行按钮创建、也可以通过改变坐标位置从而来改变按钮大小、还可以任意设置按钮字体大小、可以任意传入字符数组,任意设置按钮上的文本。另外在此基础上建立由配置文件来创建按钮的功能。

使用 button 函数示例

示例 1:

// 如果该函数的第三个参数等于 1,那就是启用鼠标点击功能,如果等于其他的数,就是单纯的按钮功能,最后一个参数是决定在鼠标点击时候按钮特效,启动参数是 1。
int buttonparm(int mouse_x, int mouse_y, int click, int click_1)
{
	FlushBatchDraw(); // 批量绘图的开始处。
	if (button(10, 10 + 3, 240, 50, mouse_x, mouse_y, 18, 21, button_string[0][0], button_string[1][0], click_1) == click)system("mspaint");
	// 创建按钮,判断鼠标移动到这按钮启动高亮,且点击该按钮打开画图板。
	if (button(10, 55, 240, 92, mouse.x, mouse.y, 15, 16, _T("在按钮函数内直接填写按钮文本"), _T("像字符输出函数一样不需要数组"), click_1)== click)system("mspaint");
	// 或者直接在函数内填写按钮文本,创建按钮,判断鼠标移动到这按钮启动高亮,且点击该按钮打开画图板。

	EndBatchDraw();	// 批量绘图的结束处。
	return 0;
}

示例 2:

ExMessage mouse;

// 嵌入式死循环。
while (true)
{
	mouse = getmessage(EM_MOUSE | EM_KEY);

	if (mouse.message == WM_MOUSEMOVE)
	{
		// 创建按钮,判断鼠标移动到这按钮启动高亮,且点击该按钮打开画图板。
		if (button(10, 10 + 3, 240, 50, mouse.x, mouse.y, 18, 21, _T("打开画板"), _T("——打开画板—"), 1) == 22)system("mspaint");					
	}

	if (mouse.message == WM_LBUTTONDOWN)
	{
		// 创建按钮,判断鼠标移动到这按钮启动高亮,且点击该按钮打开画图板。
		if (button(10, 10 + 3, 240, 50, mouse.x, mouse.y, 18, 21, _T("打开画板"), _T("——打开画板—"), 1) == 1)system("mspaint");					
		flushmessage(EM_MOUSE);
	}
}

buttonparm 函数介绍
buttonparm 函数(鼠标的坐标传输函数)(把鼠标的坐标传入到 button 函数里,就不用在 EasyX 绘图库里的鼠标移动和鼠标点击两个模式里重复定一堆创建按钮函数(指 button 函数),然后通过参数开关选择函数功能)。

简单来说这个 buttonparm 函数就是在鼠标参数 WM_LBUTTONDOWN 与 WM_MOUSEMOVE 中调用。而不是在里边创建大量一堆的 button 函数,那样难看又复杂,该函数可以在程序开头调用来绘制你所有创建的按钮界面,而不是鼠标移动到软件界面再创建绘制出所有按钮界面。

可以在程序初始化的时候调用这个,只要把点击和移动的工能禁用就行了,这是机制问题。

该函数:

有四个参数,前一二个是参数鼠标的坐标 X 和 Y 第三个是代码参数,分别对应,控制启用”鼠标点击“和”鼠标移动高亮按钮“和”什么都不干只绘制所有按钮功能“代码参数分别是” 1 “ 和” 22 “和” 33 “,最后一个参数是决定在鼠标点击时候按钮特效,启动参数是 1。

该函数有四个功能:

第一:显示你创建的基本按钮!得在程序初始化的地方调用,至少是声明鼠标类型之前,即鼠标移动到按钮上不高亮,也不让鼠标点击判断按钮被点击,就是基本绘制你创建的所有按钮图形界面,等于显示按钮。配合 buttonparm 函数使用(就是把所有的 button 写到 buttonparm 函数里,然后在鼠标函数调用 buttonparm 函数。请在 EasyX 初始化相关的地方里的这样调用 buttonparm(NULL, NULL, 33, NULL);。控制启用什么都不干,但只绘制按钮图形的功能,代码参数是 33,例子:buttonparm(NULL, NULL, 33, 1);。

第二:显示鼠标移动到该按钮上的高亮按钮,就是鼠标走到那个按钮,那个按钮就高亮视觉差,就是被选择了的按钮效果。(但是要把所有的 button 创建按钮函数写到 buttonparm 函数里,然后在鼠标函数移动中调用 buttonparm 函数,并输入鼠标坐标参数,好让 button 知道鼠标在哪个位置),

请在 EasyX 鼠标相关的函数里的这样调用 if (SB.message == WM_MOUSEMOVE)buttonparm(SB.x, SB.y, 33, 0);。控制启用鼠标移动高亮按钮,代码参数是 33,例子:buttonparm(SB.x, SB.y, 33, 0);。

第三:实现点击哪个按钮,哪个按钮就干什么,哪个按钮点击了,就是调用对应的功能。请在 EasyX 鼠标相关的函数里的这样调用 if (SB.message == WM_LBUTTONDOWN)buttonparm(SB.x, SB.y, 1, 1);。控制启用鼠标点击,代码参数是 1 例子:buttonparm(SB.x, SB.y, 1, 1);。

button 函数如果被点击了会返回一个值,那个值就是 1,可以通过 if 去判断是否被点击了,从而进行处理。

第四:鼠标点击时候按钮特效,启动参数是 1,关闭参数是 0。

使用 buttonparm 函数示例

示例 1:

	ExMessage mouse;
	// 嵌入式死循环。
	while (true)
	{
		mouse = getmessage(EM_MOUSE | EM_KEY);
	
		// 获取鼠标消息,然后判断鼠标移动中遇到的事,调用 buttonparm 按钮综合函数。
		// 参数 33 代表不开启鼠标点击功能,只创建和绘制按钮加,鼠标移动到按钮坐标上边会有高亮按钮。
		// 最后一个参数是决定在鼠标点击时候按钮特效,关闭参数是 0。
		if (mouse.message == WM_MOUSEMOVE)
		{
			buttonparm(mouse.x, mouse.y, 33, 0);
		}
	
		if (mouse.message == WM_LBUTTONDOWN)
		{
			if (buttonparm(mouse.x, mouse.y, 1, 1) == 1)break;
		}
		// 获取鼠标消息,然后判断鼠标在点击中遇到的事,调用 buttonparm 按钮综合函数。
		// 参数 1 代表不开启鼠标移动到按钮上的高亮,如果鼠标点击到按钮上,那么 buttonparm 函数会判断发生的事情。
		// 最后一个参数是决定在鼠标点击时候按钮特效,启动参数是 1。
		// 非常灵活的返回值,自由设定返回值,返回功能,这里返回 1 我就结束主循环退出程序。任意设定。
	}

程序截图如下

程序运行截屏

程序截屏

完整代码如下

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
*	本程序名称:EasyX 绘图库硬核实现 GUI 简单按钮程序实例教程。
*	编译环镜:Microsoft Visual Studio Community 2019
*	绘图库:EasyX_20211109
*	电脑系统:Win10 1809
*	作者:奈叶敬 2963787923@qq.com
*	程序起始时间:2021 - 7 - 10
*	程序最后结束修改时间:2022 - 3 - 9 0:19
*
*	更新内容:
*	1.新增鼠标位置显示。
*	2.新增按扭点击特效。
*	3.新增按钮点击声效。
*	4.新改按钮界面并美化。
*	5.新增按钮颜色修改函数,自由修改颜色,本次预设按钮颜色有,稚红按钮,紫爱按钮,紫白按钮,原色按钮,轻绿按钮,粉紫按钮,青暗按钮,红亮按钮。
*	6.2022 年 3 月 9 日内容大改造,基于配置文件动态生成按钮。
*	7.新增在按钮函数内直接填写按钮文本(2022 - 9 - 14)
*	8.新增在 WIN10 系统下分辨率不会被系统更改变大使的程序更加精至,除了个别 WIN10 系统不会因此项增加改变外,原因不明(2022 - 9 - 14)
*	目的:使用按钮封闭函数自由方便的批量创建按钮,实现用 EasyX 绘图库做一个简单的鼠标按钮操作,给需要编写 GUI 程序的小伙伴们一个硬核参考,之后如果可以编写一套完整的 GUI 控件。
*	历史:本程序源码历史能运行的,最长源码 300 行,历史最长最短源码 67 行,历史最长折中源码 80 多行,换过无数种思路。
*	编译调试建议:无。
*
*	代码函数定义位置顺序排列如下:
*	setbuttonini -> getbuttonini - > setgetbuttonini - > setbuttoncolor - > button_textzise - >
*	button_function -> button -> buttonparm - > X_Y - > lnitial_drawing
*
*/

// 设定操作系统版本为 Win10(需要放到 #include <graphics.h> 前面)
#define WINVER 0x0A00
#define _WIN32_WINNT 0x0A00

#include <graphics.h>							// 绘图库头文件。
#include <conio.h>								// 函数 _getch 的所在库。
#include <windows.h>							// 系统库。
#include <stdio.h>								// 标准库。
#include <string.h>								// 字集处理库。
#include <ShlObj.h>								// 获取桌面壁纸的函数的头文件。
#include<mmsystem.h>							// 音乐播放 API 函数所在库。
#include <ShellScalingApi.h>					// 引用头文件
#pragma comment(lib, "winmm.lib")				// 音乐播放相关。
#pragma comment(lib, "Shcore.lib")				// 链接库文件

#define width 250								// 程序宽。
#define high 750								// 程序高。

// 程序函数目录,10 个核心函数构成本程序。

// 定义设置原始按钮位置,字符串,字体大小,的配置文件,并导出成模版函数,内容由读取配置文件函数读取,并打开程序只执行一次。
void setbuttonini(TCHAR buttonstring[], TCHAR x1[], TCHAR y1[], TCHAR x2[], TCHAR y2[], TCHAR buttonstr1[], TCHAR buttonstr2[], TCHAR textsize1[], TCHAR textsize2[]);
// 定义加载读取配置文件里定义的按钮函数。
void getbuttonini();
// 定义调用设置按钮函数和读取配置文件里定义的按钮函数。
void setgetbuttonini();
// 定义按钮颜色修改函数。
void setbuttoncolor(int button_r1, int button_g1, int button_b1, int button_r2, int button_g2, int button_b2);
// 修改按钮字体大小函数。
void button_textzise(int zise);
// 定义按钮点击功能函数 button_function 传入相对应的按钮序号来判断按钮点击后对应设置的功能。
int button_function(int i);
// 定义按钮创建函数。
int button(int x1, int y1, int x2, int y2, int mouse_x, int mouse_y, int textsize1, int textsize2, LPCSTR button_string1, LPCSTR button_string2, int click_1);
// 定义按钮传输参数函数。
int buttonparm(int mouse_x, int mouse_y, int click, int click_1);
// 定义显示鼠标移动的坐标函数。
int X_Y(int zise, long mouse_x, long mouse_y);
// 定义 GUI 图形界面的初始化。
void lnitial_drawing();

int button_rgb1[3][1] = { 19, 113, 171 };		// 声明颜色 RGB 变量,可以修改这个改变按钮前景或者背景颜色,并可以初始化颜色。
int button_rgb2[3][1] = { 201, 222, 245 };		// 声明颜色 RGB 变量,可以修改这个改变按钮前景或者背景颜色,并可以初始化颜色。
int button_quantity = 0;						// 决定读取配置文件里的按钮数量的值,用于打印按钮。
int button_int[100][7] = { 0 };					// 由读取配置函数,存放配置文件里的各各按钮坐标位置,字体大小,并用于按钮函数打印出内容的整形数组。
TCHAR button_stringchar[256][9][155] = { 0 };	// 由读取配置函数,存放配置文件里的各各按钮字符串,并用于按钮函数打印出内容字符型数组。
TCHAR button_string[256][9][100] =				// 三维数组的巧妙应用于,鼠标移动到按钮位置发生不一样选择,原始按的钮坐标,按钮文本,字体大小数据用于生成模版配置文件。
{
	{_T("10"), _T("555 "), _T("65"), _T("588"), _T("轻绿按钮"), _T("轻绿按钮"), _T("13"), _T("12")},
	{_T("68"), _T("555 "), _T("122"), _T("588"), _T("粉紫按钮"), _T("粉紫按钮"), _T("13"), _T("12")},
	{_T("125"), _T("555 "), _T("179"), _T("588"), _T("青暗按钮"), _T("青暗按钮"), _T("13"), _T("12")},
	{_T("182"), _T("555"), _T("238"), _T("588"), _T("红亮按钮"), _T("红亮按钮"), _T("13"), _T("12")},
	{_T("10"), _T("509"), _T("65"), _T("544"), _T("稚红按钮"), _T("稚红按钮"), _T("13"), _T("12")},
	{_T("68"), _T("509"), _T("122"), _T("544"), _T("紫爱按钮"), _T("紫爱按钮"), _T("13"), _T("12")},
	{_T("125"), _T("509"), _T("179"), _T("544"), _T("紫白按钮"), _T("紫白按钮"), _T("13"), _T("12")},
	{_T("182"), _T("509"), _T("238"), _T("544"), _T("原色按钮"), _T("原色按钮"), _T("13"), _T("12")},
	{_T("10"), _T("13"), _T("240"), _T("50"), _T("打开画板"), _T("-打开画板-"), _T("15"), _T("18")},
	{_T("10"), _T("58"), _T("240"), _T("98"), _T("计算器"), _T("-计算器-"), _T("15"), _T("18")},
	{_T("10"), _T("103"), _T("240"), _T("143"), _T("打开任务管理"), _T("-打开任务管理-"), _T("15"), _T("18")},
	{_T("10"), _T("148"), _T("240"), _T("188"), _T("打开终端"), _T("-打开终端-"), _T("15"), _T("18")},
	{_T("10"), _T("193"), _T("240"), _T("233"), _T("查看电脑版本"), _T("-查看电脑版本-"), _T("15"), _T("18")},
	{_T("10"), _T("238"), _T("240"), _T("278"), _T("打开 VS "), _T("-打开 VS -"), _T("15"), _T("18")},
	{_T("10"), _T("283"), _T("240"), _T("323"), _T("打开资源管理器"), _T("-打开资源管理器-"), _T("15"), _T("18")},
	{_T("10"), _T("328"), _T("240"), _T("368"), _T("打开 EasyX 绘图库官网"), _T("-打开 EasyX 绘图库官网-"), _T("15"), _T("18")},
	{_T("10"), _T("373"), _T("240"), _T("413"), _T("打开 codebus 官网"), _T("-打开 codebus 官网-"), _T("15"), _T("18")},
	{_T("10"), _T("418"), _T("240"), _T("458"), _T("打开有问必答官网"), _T("-打开有问必答官网-"), _T("15"), _T("18")},
	{_T("10"), _T("464"), _T("74"), _T("499"), _T("关机电脑"), _T("关机电脑"), _T("14"), _T("15")},
	{_T("79"), _T("464"), _T("145"), _T("499"), _T("重启电脑"), _T("重启电脑"), _T("14"), _T("15")},
	{_T("149"), _T("464"), _T("240"), _T("499"), _T("取消关机重启"), _T("取消关机重启"), _T("14"), _T("15")},
	{_T("10"), _T("598"), _T("240"), _T("638"), _T("退出小程序"), _T("-退出小程序-"), _T("15"), _T("18")},
};

/// @brief 设置原始按钮位置,字符串,字体大小,的配置文件,并导出成模版函数,内容由读取配置文件函数读取,并打开程序只执行一次。
/// @param buttonstring 按钮名称。
/// @param x1 按钮左上角 X 坐标
/// @param y1 按钮左上角 Y 坐标
/// @param x2 按钮右下角 X 坐标
/// @param y2 按钮右下角 y 坐标
/// @param buttonstr1 按钮没选中时的文本大小
/// @param buttonstr2 按钮没被选中里的文本
/// @param textsize1 按钮被选中里的文本
/// @param textsize2 按钮被选中里的文本
void setbuttonini(TCHAR buttonstring[], TCHAR x1[], TCHAR y1[], TCHAR x2[], TCHAR y2[], TCHAR buttonstr1[], TCHAR buttonstr2[], TCHAR textsize1[], TCHAR textsize2[])
{
	WritePrivateProfileString(buttonstring, _T("按钮左上角 X 坐标"), x1, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮左上角 Y 坐标"), y1, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮右下角 X 坐标"), x2, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮右下角 y 坐标"), y2, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮没选中时的文本大小"), textsize1, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮被选中时的文本大小"), textsize2, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮没被选中里的文本"), buttonstr1, _T(".\\buttontese.ini"));
	WritePrivateProfileString(buttonstring, _T("按钮被选中里的文本"), buttonstr2, _T(".\\buttontese.ini"));
}
// 加载读取配置文件里定义的按钮函数。
void getbuttonini()
{
	TCHAR button_quantity1[155] = { 0 };			// 用于读取按钮的字节暂存值。
	for (int i = 0; ; i++)
	{
		swprintf(button_quantity1, 30, _T("%d"), i); // 转化 i 整形成字符型,用于读取函数。
		button_int[i][0] = GetPrivateProfileInt(button_quantity1, _T("按钮左上角 X 坐标"), 0, _T(".\\buttontese.ini"));
		button_int[i][1] = GetPrivateProfileInt(button_quantity1, _T("按钮左上角 Y 坐标"), 0, _T(".\\buttontese.ini"));
		button_int[i][2] = GetPrivateProfileInt(button_quantity1, _T("按钮右下角 X 坐标"), 0, _T(".\\buttontese.ini"));
		button_int[i][3] = GetPrivateProfileInt(button_quantity1, _T("按钮右下角 y 坐标"), 0, _T(".\\buttontese.ini"));
		button_int[i][4] = GetPrivateProfileInt(button_quantity1, _T("按钮没选中时的文本大小"), 15, _T(".\\buttontese.ini"));
		button_int[i][5] = GetPrivateProfileInt(button_quantity1, _T("按钮被选中时的文本大小"), 5, _T(".\\buttontese.ini"));
		GetPrivateProfileString(button_quantity1, _T("按钮没被选中里的文本"), _T(""), button_stringchar[i][0], 155, _T(".\\buttontese.ini"));
		GetPrivateProfileString(button_quantity1, _T("按钮被选中里的文本"), _T(""), button_stringchar[i][1], 155, _T(".\\buttontese.ini"));
		button_quantity++;							// 记录读取多少个按钮的数量,用于后续按钮打印。

		if (button_int[i][0] == 0) { break; };		// 听我说如果读取到,按钮的末尾或者没有按钮读取了就断开这个加载配置文件函数。

	}
}

// 定义调用设置按钮函数和读取配置文件里定义的按钮函数。
void setgetbuttonini()
{
	int teru1 = 1;									// 真假断定,用于让初始化配置函数只执行一次,如果配置文件被册就再调用生成配置文件模版,1 执行,0 不执行。
	TCHAR button_quantity1[225] = { 0 };			// 生成配置文件里的按钮数量的暂存值,把 for 循环 i 值,转化成按钮字符。
	teru1 = GetPrivateProfileInt(_T("true"), _T("只生成一次"), 1, _T(".\\buttontese.ini"));

	if (teru1 == 1)
	{
		for (int i = 0; i < 22; i++)
		{
			swprintf(button_quantity1, 30, _T("%d"), i);
			setbuttonini(button_quantity1, button_string[i][0], button_string[i][1], button_string[i][2], button_string[i][3], button_string[i][4], button_string[i][5], button_string[i][6], button_string[i][7]);
		}
	}
	WritePrivateProfileString(_T("true"), _T("只生成一次"), _T("0"), _T(".\\buttontese.ini"));

	getbuttonini();
}

/// @brief setbuttoncolor 按钮颜色修改函数
/// @param button_r1	按钮背景色 r 色值
/// @param button_g1	按钮背景色 g 色值
/// @param button_b1	按钮背景色 b 色值
/// @param button_r2	按钮被选中的高亮色 r 色值
/// @param button_g2	按钮被选中的高亮色 g 色值
/// @param button_b2	按钮被选中的高亮色 b 色值
void setbuttoncolor(int button_r1, int button_g1, int button_b1, int button_r2, int button_g2, int button_b2)
{
	button_rgb1[0][0] = button_r1;
	button_rgb1[1][0] = button_g1;
	button_rgb1[2][0] = button_b1;

	button_rgb2[0][0] = button_r2;
	button_rgb2[1][0] = button_g2;
	button_rgb2[2][0] = button_b2;
}

/// @brief button_textzise 修改按钮字体大小函数
/// @param zise	字体大小数值
void button_textzise(int zise)
{
	LOGFONT f;
	gettextstyle(&f);									// 获取当前字体设置。
	f.lfHeight = zise;									// 设置字体高度为 48。

	_tcscpy_s(f.lfFaceName, _T("宋体"));
	f.lfQuality = ANTIALIASED_QUALITY;					// 设置输出效果为抗锯齿。

	settextstyle(&f);
	setbkmode(TRANSPARENT);								// 设置透明的背景。
}
// 定义按钮点击功能函数 button_function 传入相对应的按钮序号来判断按钮点击后对应设置的功能。
int button_function(int i)
{	// 判断配置文件里的对应按钮序号,颜色修改函数,轻绿按钮。
	if (i == 0)setbuttoncolor(17, 153, 142, 56, 239, 125);
	// 判断配置文件里的对应按钮序号,颜色修改函数,粉紫按钮。
	if (i == 1)setbuttoncolor(127, 0, 225, 255, 140, 163);
	// 判断配置文件里的对应按钮序号,颜色修改函数,青暗按钮。
	if (i == 2)setbuttoncolor(6, 185, 171, 16, 124, 139);
	// 判断配置文件里的对应按钮序号,颜色修改函数,红亮按钮。
	if (i == 3)setbuttoncolor(221, 24, 24, 79, 235, 240);
	// 判断配置文件里的对应按钮序号,颜色修改函数,稚红按钮。
	if (i == 4)setbuttoncolor(254, 67, 100, 252, 157, 153);
	// 判断配置文件里的对应按钮序号,颜色修改函数,紫爱按钮。
	if (i == 5)setbuttoncolor(194, 174, 255, 246, 177, 200);
	// 判断配置文件里的对应按钮序号,颜色修改函数,紫白按钮。
	if (i == 6)setbuttoncolor(102, 102, 204, 252, 244, 237);
	// 判断配置文件里的对应按钮序号,颜色修改函数,原色按钮。
	if (i == 7)setbuttoncolor(19, 113, 171, 201, 222, 245);
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开画图板。
	if (i == 8)system("mspaint");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开计算器。
	if (i == 9)system("start calc");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开电脑任务管理器。
	if (i == 10)system("start taskmgr");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开终端命令行。
	if (i == 11)system("start cmd");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开电脑信息。
	if (i == 12)system("start winver");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开 VS。
	if (i == 13)system("start devenv");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开资源管理器。
	if (i == 14)system("explorer");
	// 判断配置文件里的对应按钮序号,打开 EASYX 官网。
	if (i == 15)ShellExecuteW(NULL, _T("open"), _T("IEXPLORE"), _T("https://docs.easyx.cn/"), NULL, SW_SHOWMAXIMIZED);
	// 判断配置文件里的对应按钮序号,打开 EASYX codebus 官网。
	if (i == 16)ShellExecuteW(NULL, _T("open"), _T("IEXPLORE"), _T("https://codebus.cn/"), NULL, SW_SHOWMAXIMIZED);
	// 判断配置文件里的对应按钮序号,打开 EASYX 有问必答官网。
	if (i == 17)ShellExecuteW(NULL, _T("open"), _T("IEXPLORE"), _T("https://qa.codebus.cn/"), NULL, SW_SHOWMAXIMIZED);
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开关机。
	if (i == 18)system("shutdown -s -t 30");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开重启电脑。
	if (i == 19)system("shutdown -r -t 30");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮取消关机重启。
	if (i == 20)system("shutdown -a");
	// 判断配置文件里的对应按钮序号,判断鼠标移动到这按钮启动高亮,且点击该按钮打开退出。
	if (i == 21)return 1;

	return 0;
};

/// @brief button 按钮创建函数
/// @param x1		按钮左上角 x 坐标
/// @param y1		按钮左上角 y 坐标
/// @param x2		按钮右下角 x 坐标
/// @param y2		按钮右下角 y 坐标
/// @param mouse_x	鼠标 x 座标
/// @param mouse_y	鼠标 y 座标
/// @param textsize1	鼠标没选中按钮时字体大小
/// @param textsize2	鼠标选中按钮时字体大小
/// @param button_string1	鼠标没选中按钮时显示的文本
/// @param button_string2	鼠标选中按钮时显示的文本
/// @param click_1		按钮点击特效参数: 1.启动 0.不启动
/// @return 返回一个判断按钮是否点击的参数:被点击返回 1 没有被点击返回 0

int button(int x1, int y1, int x2, int y2, int mouse_x, int mouse_y, int textsize1, int textsize2, LPCTSTR button_string1, LPCTSTR button_string2, int click_1)
{
	button_textzise(textsize1);																// 设置字体大小函数。

	setlinestyle(PS_NULL);
	setlinecolor(RGB(button_rgb2[0][0], button_rgb2[1][0], button_rgb2[2][0]));				// 设置按钮颜色的外框线体函数。
	settextcolor(WHITE);																	// 设置按钮白色的字体函数。
	setfillcolor(RGB(button_rgb1[0][0], button_rgb1[1][0], button_rgb1[2][0]));				// 使用修改颜色的 RGB 数组,可改变数组从而来自由改变颜色。

	fillroundrect(x1, y1, x2, y2, 20, 20);													// 画按钮矩形,有圆角 20,对接按钮的前四个坐标数组。
																							// 设置居中显示按钮的文字。
	outtextxy((((x2 - x1) / 2) + x1) - (textwidth(button_string1) / 2), (((y2 - y1) / 2) + y1) - (textheight(button_string1) / 2), button_string1);
	// 特制按钮,字体居中算法,不知是否比自带的效率高?但失去了一些强大的功能。

	if (mouse_x > x1 && mouse_y > y1 && mouse_x < x2 && mouse_y < y2)						// 判断鼠标是否在按钮内部,如果是就执行高亮按钮代码。
	{
		setlinestyle(PS_ENDCAP_FLAT);

		button_textzise(textsize2);															// 设置选中的按钮字体大小,产生选中字体的视觉差。

		setlinecolor(RGB(button_rgb1[0][0], button_rgb1[1][0], button_rgb1[2][0]));			// 选中按钮后把线条变颜色。
		settextcolor(WHITE);																// 选中按钮后,把文字变成白色。
		setfillcolor(RGB(button_rgb2[0][0], button_rgb2[1][0], button_rgb2[2][0]));			// 使用修改颜色的 RGB 数组,可改变数组从而来自由改变颜色。
		setbkmode(TRANSPARENT);																// 把文字背景设置成透明的。

		fillroundrect(x1, y1, x2, y2, 20, 20);												// 填充的矩形,画选中的,按钮的意思。

		outtextxy((((x2 - x1) / 2) + x1) - (textwidth(button_string2) / 2), (((y2 - y1) / 2) + y1) - (textheight(button_string2) / 2), button_string2);
		// 特制按钮,字体居中算法:按钮长度减按钮起点除一半得没有起点的一半,再加上起点得按钮宽度中心点减字符串宽度的一半得居左右中字体
		if (click_1 == 1)																	// 如果点击等于 1 就启动点击按钮特效。
		{
			settextcolor(WHITE);															// 选中按钮后,把文字变成白色。
			button_textzise(textsize2 - 3);
			fillroundrect(x1, y1, x2, y2, 20, 20);											// 填充的矩形,画选中的,按钮的意思。
																							// 在填充的矩形显示居中的高亮放大的文字。
			outtextxy((((x2 - x1) / 2) + x1) - (textwidth(button_string2) / 2), (((y2 - y1) / 2) + y1) - (textheight(button_string2) / 2), button_string2);
			// 特制按钮,字体居中算法:按钮高度减按钮高度起点除一半得没有高度起点的一半,再加上起点得按钮高度中心点减字符串疝度的一半得上下居中字体
			Sleep(100);																		// 显示按钮被点击的效果。
			settextcolor(WHITE);															// 选中按钮后,把文字变成蓝色。
			button_textzise(textsize2);
			fillroundrect(x1, y1, x2, y2, 20, 20);											// 填充的矩形,画选中的,按钮的意思。
																							// 在填充的矩形显示居中的高亮放大的文字。
			outtextxy((((x2 - x1) / 2) + x1) - (textwidth(button_string2) / 2), (((y2 - y1) / 2) + y1) - (textheight(button_string2) / 2), button_string2);
		}

		return 1;																			// 返回 1 说明,鼠标点到了该按钮,可以通过 if 函数来判断返回值 1 要干什么。
	}
	return 0;																				// 如果按钮没有被鼠标选中就返回 0。
}

/// @brief buttonparm 按钮传输参数函数
/// @param mouse_x	传入鼠标 x 坐标
/// @param mouse_y	传入鼠标 y 坐标
/// @param click		选择功能参数:1.启用鼠标点击功能 33.单纯的按钮功能
/// @param click_1		按钮点击特效参数: 1.启动 0.不启动
/// @return			可以通过 if 来返回其他参数来帮助程序退出
int buttonparm(int mouse_x, int mouse_y, int click, int click_1)
{

	FlushBatchDraw();	// 批量绘图的开始处。
	for (int i = 0; i < button_quantity + 1; i++)
	{
		// 这个是打印读取了配置文件里的按钮数据数组,并通过 按钮功能函数 button_function 判断按钮点击后对应设置的功能。
		if (button(button_int[i][0], button_int[i][1], button_int[i][2], button_int[i][3], mouse_x, mouse_y, button_int[i][4], button_int[i][5], button_stringchar[i][0], button_stringchar[i][1], click_1) == click)
		{
			if (button_function(i) == 1)return 1;	// 返回 1 代表退出,按钮点击功能函数 button_function 传入相对应的按钮序号来判断按钮点击后对应设置的功能。
		}
		// 这个是打印读取了配置文件里的按钮数据数组,并通过 按钮功能函数 button_function 判断按钮点击后对应设置的功能。
		

		
	}
	EndBatchDraw();		// 批量绘图的结束处。
	return 0;
}

/// @brief X_Y 显示鼠标移动的坐标函数
/// @param zise		设定显示鼠标 x, y 坐标数值
/// @param mouse_x	传入鼠标 x 坐标
/// @param mouse_y	传入鼠标 y 坐标
/// @return	0
int X_Y(int zise, long mouse_x, long mouse_y)
{
	TCHAR xx[40] = { 0 }, yy[40] = { 0 };											// 存储 Y, X 的坐标。

	FlushBatchDraw();

	button_textzise(zise);
	settextcolor(MAGENTA);
	outtextxy(width - 244, high - 65, _T("当前鼠标 X_Y 坐标->"));

	setfillcolor(WHITE);															// 为消除显示 X, Y 的值,准备的白色的矩形填充。
	solidrectangle(width - 110, high - 65, width - 5 - 2, high - 45 - 2);		// 为消除显示 X, Y 的值,准备的白色的矩形填充。

	swprintf(xx, 40, _T("X:%d-"), mouse_x);
	swprintf(yy, 40, _T("-Y:%d"), mouse_y);

	settextcolor(GREEN);
	outtextxy(width - 110, high - 65, xx);

	settextcolor(RED);
	outtextxy(width - 70, high - 65, yy);											// 显示 X 的坐标,前一函数设置字体红色,并设置字体大小。

	FlushBatchDraw();
	return 0;
}
// GUI 图形界面的初始化。
void lnitial_drawing()
{
	// 设置该进程不受系统 DPI 设置影响
	SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
	initgraph(width, high);															// 软件界面的大小定义。

	HWND hWnd = GetHWnd();															// 获得窗口句柄。
	SetWindowText(hWnd, _T("GUI 按钮实例"));											// 使用 Windows API 修改窗口名称。

	// setlinestyle(PS_ENDCAP_FLAT);

	setbkcolor(WHITE);																// 设置背景为白色。
	cleardevice();																	// 刷新白色背景的清屏函数。

	setfillcolor(BLUE);
	fillroundrect(0, 0, width - 1, high - 1, 20, 20);								// 上边是设置蓝色镇充,并画钜形为 20 大小的函数。

	setfillcolor(WHITE);
	fillroundrect(width - (width - 5), width - (width - 5), width - 5, high - 5, 20, 20);	// 是设置白色镇充,并画钜形为 20 大小的函数,设置白色镇充的函数。


	X_Y(15, NULL, NULL);
	buttonparm(NULL, NULL, 33, NULL);												// 调用按钮基本绘制函数,如没有这个,鼠标没有移动到软件里,那么按钮全都是一片空白。

	settextcolor(RED);																// 设置传入坐标 0 即不启动点击功能,也不启动启动点击判断高亮功能,就是显示所以显示在软件内,而且也只执行一次。
	button_textzise(15);
	outtextxy(width - 244, high - 45, _T("EasyX 绘图库硬核实现 GUI 按钮 "));
	outtextxy(width - 244, high - 25, _T("鼠标点击功能-工具箱-参考小程序"));
	button_textzise(5);

}

// 主函数,目的第二个参数藏有本程序运行的当前路径。
int main()
{
	// 调用设置按钮函数和读取配置文件里定义的按钮函数。
	setgetbuttonini();
	// 初始化函数用于绘制底界面,及设置程序标题。
	lnitial_drawing();
	// 声明鼠标类型的变量。

	ExMessage mouse;
	// 嵌入式死循环。
	while (true)
	{
		mouse = getmessage(EM_MOUSE | EM_KEY);

		// 获取鼠标消息,然后判断鼠标移动中遇到的事,调用 buttonparm 按钮综合函数。
		// 参数 33 代表不开启鼠标点击功能,只创建和绘制按钮加,鼠标移动到按钮坐标上边会有高亮按钮。
		// 最后一个参数是决定在鼠标点击时候按钮特效,关闭参数是 0。
		if (mouse.message == WM_MOUSEMOVE)
		{
			buttonparm(mouse.x, mouse.y, 33, 0);
			button(10, 645, 240, 675, mouse.x, mouse.y, 15, 16, _T("在按钮函数内直接填写按钮文本"), _T("像字符输出函数一样不需要数组"), 0);

			X_Y(15, mouse.x, mouse.y);
		}

		if (mouse.message == WM_LBUTTONDOWN)
		{
			mciSendString(_T("open \"C:\\Windows\\media\\Windows Navigation Start.wav\""), NULL, NULL, NULL);	// 打开按钮音效的音乐文件。
			mciSendString(_T("play \"C:\\Windows\\media\\Windows Navigation Start.wav\""), NULL, NULL, NULL);	// 播放按钮音效的音乐。

			if (buttonparm(mouse.x, mouse.y, 1, 1) == 1)break;
			button(10, 645, 240, 675, mouse.x, mouse.y, 15, 16, _T("在按钮函数内直接填写按钮文本"), _T("像字符输出函数一样不需要数组"), 1);

			mciSendString(_T("close \"C:\\Windows\\media\\Windows Navigation Start.wav\""), NULL, NULL, NULL);	// 关闭按钮音效的音乐。
			flushmessage(EM_MOUSE);
		}
		// 获取鼠标消息,然后判断鼠标在点击中遇到的事,调用 buttonparm 按钮综合函数。
		// 参数 1 代表不开启鼠标移动到按钮上的高亮,如果鼠标点击到按钮上,那么 buttonparm 函数会判断发生的事情。
		// 最后一个参数是决定在鼠标点击时候按钮特效,启动参数是 1。
		// 非常灵活的返回值,自由设定返回值,返回功能,这里返回 1 我就结束主循环退出程序。任意设定。
	}

	// 关闭绘图库。
	closegraph();
	// 退出程序并返回零。
	return 0;
}

评论 (8) -

  • 有没有 类似的 和这个按钮 差不多的输入框?
  • 就是有没有精简版的?这个有,复杂,我不好使用?

添加评论