主页
最近更新
DevGUI 使用方法
最后更新于 2025-05-01 16:04:53
作者
rzh123
分类
个人记录
复制 Markdown
更新文章内容
# DevGUI 使用方法 [ $\leftarrow$ 返回 DevGUI 说明](https://www.luogu.com.cn/blog/rzh123haha/DevGUI-Info) ## 一、最简单的 DevGUI 程序 安装完 DevGUI 后,打开 Dev-C++,新建源代码,输入以下程序: ```cpp #include <dgui.h> int main(){ setup(); keepwindow(); return 0; } ``` 运行效果: [](https://imgtu.com/i/H330UI) 那个白色的窗口就是著名的 GUI 界面。 这里面的 `setup` 是创建窗口,`keepwindow` 是等待窗口关闭后才返回。 就这么简单。 ## 二、DevGUI 基本结构 DevGUI 图形库主要由几个头文件构成,所有内容都在一个名字空间 `dgui_ns` 中(v2.1 及之前为 `dgui`,旧版程序可以使用[此方法](https://www.luogu.com.cn/paste/3hyfugo8))。 dgui.h 里有 `using namespace dgui_ns;`,所以程序中不需要写。如果不想自动包含,可以 **在 `#include <dgui.h>` 之前** 写上以下代码: ```cpp #define _DGUI_NOUSINGNAMESPACE_ ``` DevGUI 图形库自动包含以下标准库头文件: ```cpp #include <cstdio> #include <cstdlib> #include <cctype> #include <cstring> #include <cstdarg> #include <cmath> #include <vector> #include <string> #include <queue> #include <map> ``` 自动包含以下 Windows 头文件: ```cpp #include <process.h> #include <windows.h> #include <mmsystem.h> ``` 自动 `using` 以下内容: ```cpp using std::vector; using std::string; using std::queue; using std::map; ``` **(不包含 `using namespace std;`)** DevGUI 有两种模式:源代码和项目,Dev-C++ 直接新建出来的代码就是源代码,Dev-C++ 的 “文件 -> 新建” 里还可以新建项目。 源代码比较常用,因此大部分内容在源代码中测试。如果要在项目中使用,用法基本相同,但是需要 **在 `#include <dgui.h>` 之前** 加上以下代码: ```cpp #define PROJECT ``` 注意:这个只能在项目中使用,在源代码中使用会导致大量编译错误。 ## 三、DevGUI 中的函数等 注意:只列出常用的,不是 DevGUI 的所有内容。 ### 1.窗口基本操作 #### `setup` 函数——创建窗口 `setup` 函数有多种重载的形式: `void setup(int x,int y,int w,int h,string title);` 指定窗口横纵坐标、宽度、高度、标题。 `void setup(int x,int y,int w,int h);` 指定窗口横纵坐标、宽度、高度,标题为 `无标题`。 `void setup(int w,int h,string title);` 指定窗口宽度、高度、标题,使用默认横纵坐标。 `void setup(int w,int h);` 指定窗口宽度、高度,使用默认横纵坐标,标题为 `无标题`。 `void setup(string title);` 指定窗口标题,使用默认横纵坐标、宽度、高度。 `void setup();` 不指定窗口的任何信息,使用默认横纵坐标、宽度、高度,标题为 `无标题`。 #### 修改窗口属性的函数 `void settitle(string wndtitle);` 修改窗口标题。 `void showwindow(int stype);` 显示或隐藏窗口。 其中的 `stype` 有如下取值(定义在系统 winuser.h 的 $143 \sim 157$ 行): ```cpp #define SW_HIDE 0 #define SW_SHOWNORMAL 1 #define SW_NORMAL 1 #define SW_SHOWMINIMIZED 2 #define SW_SHOWMAXIMIZED 3 #define SW_MAXIMIZE 3 #define SW_SHOWNOACTIVATE 4 #define SW_SHOW 5 #define SW_MINIMIZE 6 #define SW_SHOWMINNOACTIVE 7 #define SW_SHOWNA 8 #define SW_RESTORE 9 #define SW_SHOWDEFAULT 10 #define SW_FORCEMINIMIZE 11 #define SW_MAX 11 ``` 它们的作用就是字面意思。 `void showwindow();` 显示窗口。 `void movewindow(int x,int y,int w,int h);` 移动窗口到指定坐标,并将窗口宽度、高度设置为指定数值。 `void poswindow(int x,int y);` 移动窗口到指定坐标。 `void resizewindow(int w,int h);` 设置窗口宽度、高度。 #### 其他 `void hideconsole();` 隐藏控制台。 旧版 bug:旧版中如果屏幕上有其他控制台窗口,这个函数可能会隐藏其他控制台,最新版无此 bug。 `bool windowexist();` 判断程序创建的窗口是否存在。存在返回 $1$,不存在返回 $0$。 `void keepwindow();` 一直等待,直到窗口被关闭。 `long long winfo(string key);` 获取窗口的某一项信息。 有效的调用方式有: ```cpp winfo("x");//窗口横坐标 winfo("x");//窗口纵坐标 winfo("window-x");//窗口横坐标 同 "x" winfo("window-x");//窗口纵坐标 同 "y" winfo("client-x");//窗口客户区横坐标 winfo("client-y");//窗口客户区纵坐标 winfo("width");//窗口客户区宽度 winfo("height");//窗口客户区高度 ``` 如果 `key` 无效,会返回 $-1$。 `void closewindow();` 关闭窗口。 ### 2.画图操作 #### 数据类型 `DPOINT` 表示一个点 + `int x` 横坐标 + `int y` 纵坐标 `DPOINTS` 表示一个 `DPOINT` 类型的数组 `DRECT` 表示一个矩形 + `int x1` 左上角横坐标 + `int y1` 左上角纵坐标 + `int x2` 右下角横坐标 + `int y2` 右下角纵坐标 `DCOLOR` 或 `DCOL` 表示一种颜色(相当于 `unsinged int`) #### 函数 `void ellipse(int x,int y,int r1,int r2);` 指定中心坐标、横向半径、纵向半径,画椭圆。 `void circle(int x,int y,int r);` 指定圆心坐标、半径,画圆。 `void rectangle(DPOINT p1,DPOINT p2);` 指定左上角、右下角的点,画矩形。 `void rectangle(int x,int y,int a,int b);` 指定左上角坐标和横向、纵向边长,画矩形。 `void square(int x,int y,int a);` 指定左上角坐标和边长,画正方形。 `void polygon(int len,DPOINTS pnts);` 指定点数和各点,画多边形。 `void poly(int len,...);` 指定点数和各点坐标(两个数字一组),画多边形。 `void line(int x1,int y1,int x2,int y2);` 指定左上角、右下角坐标,画线段。 `void polyl(int len,...);` 指定点数和各点坐标(两个数字一组),画折线。 `void textout(int x,int y,string txt);` $\color{red}{\bold{\text{旧版中此函数可能存在 Bug:}}}$ [here](https://www.luogu.com.cn/paste/7lbwf20g) 指定左上角坐标和一个字符串,输出文本。 `void textoutf(int x,int y,string fmt,...);` 指定左上角坐标,格式化输出文本。(`fmt` 及之后的参数的写法类似于 `printf`) `void setpxcol(int x,int y,DCOLOR col);` 将指定坐标的像素修改为指定颜色。 `DCOLOR getRGB(int r,int g,int b);` 根据 RGB 值获取颜色。 `DCOLOR getcolor(string colname);` 获取一种颜色。目前支持如下写法: + `getcolor("#XXXXXX")` 其中 `XXXXXX` 为颜色的十六进制表示,字母必须大写 + `getcolor("#XYZ")` 相当于 `getcolor("#XXYYZZ")` + `getcolor("NAME")` 其中 `NAME` 为颜色的英文名,可以参考 [DevGUI 颜色名称表](https://www.luogu.com.cn/paste/7u8wg5jk) 或 DevGUI 中 duser.h 中的 `initcols` 函数。不区分大小写,忽略空格、Tab、换行符。 `DCOLOR makecolor(string colname);` 同 `getcolor`。 `DCOLOR getpxcol(int x,int y);` 获取指定坐标的像素的颜色。 `int colordif(DCOLOR a,DCOLOR b);` 计算 DevGUI 中两种颜色的差异程度,范围为 $[0,25500]$。 `fillarea` 中如果两种颜色的差异小于等于 `tolerance` 就会认为它们相同。 `void fillarea(int x,int y,int tolerance=0);` 指定开始点的坐标、容错程度(不写默认为 $0$),填充区域。 `void fillrect(int x,int y,int w,int h);` 填充矩形区域。 `void clear();` 清空窗口。 `void setpen(int type,DCOLOR col,int wgt);` 设置图形边框样式、颜色、粗细。 边框样式包括: ```cpp #define PNTYPE_TRANSPARENT 0 //无边框 #define PNTYPE_SOLID 1 //实线 #define PNTYPE_DASH 2 //虚线 #define PNTYPE_DOT 3 //点线 ``` `void setpentype(int type);` 设置图形边框样式。 `void setpencolor(DCOLOR col);` 设置图形边框颜色。 `void setpenwidth(int wgt);` 设置图形边框粗细。 `void setfillcolor(DCOLOR col);` 设置图形填充颜色。 `void setfont(string name,int w,int h,int weight,bool ita,bool und,bool del);` 设置字体名称、宽度、高度、粗细、是否倾斜、是否加下划线、是否加删除线。 `void setfontname(string name);` 设置字体名称。 ### 3.图片操作 #### 数据类型 `BMP`(又称 `IMAGE`、`PICTURE`、`DGUIPIC`)表示一张图片的信息 + `int w` 图片宽度 + `int h` 图片高度 + `HBITMAP hbm` 图片句柄(WinAPI 相关) + `bool valid();` 判断图片是否有效 + `void del();` 释放图片占用的系统资源(一个 `BMP` 在作用域结束时会自动释放) **注意:由于 `BMP` 自动释放,如果函数中用 `BMP` 作为参数,请使用指针或引用。** #### 函数 `void loadbmp(BMP &buf,string path,int w,int h);` 指定路径、宽度、高度,将图片文件读取到 `BMP` 类型的变量中。 第一个参数传入的是 `BMP` 类型变量的引用,也就是直接传入变量名,没有取地址符等。 **只支持 `bmp` 文件** `void drawbmp(const BMP &bmp,int x,int y);` 指定左上角坐标,在窗口上输出图片。 `void drawbmppara(const BMP &bmp,DPOINT p1,DPOINT p2,DPOINT p3);` 指定左上角、右上角、左下角坐标,把图片输出到平行四边形中。 `void drawbmprotate(const BMP &bmp,int x,int y,int deg);` 指定左上角坐标,把图片绕中心顺时针旋转 $\deg^{\circ}$ 后输出。 `void drawbmpscale(const BMP &bmp,int x,int y,int w,int h);` 指定左上角坐标和缩放后长宽,把图片缩放后输出。 `void drawbmpmirrorx(const BMP &bmp,int x,int y);` 指定左上角坐标,把图片水平翻转后输出。 `void drawbmpmirrory(const BMP &bmp,int x,int y);` 指定左上角坐标,把图片竖直翻转后输出。 `void windowbmp(BMP &buf,int x,int y,int w,int h);` 将整个窗口客户区中的一块区域存储到 `BMP` 变量。 `bool savebmp(const BMP &bmp,string path);` 把图片保存到文件里。 ### 4.事件操作 DevGUI 用“事件”实现交互功能。 #### 数据类型 `EVENT`:就是 `std::string`,表示事件名称。 `EPARA`:事件附带的参数,实际上是 `void*`,但在不同事件中有不同含义。 `EFUNC`:表示一个可以绑定到事件的函数,就是 `void(*)(EPARA)` 类型。 #### 函数 `void bind(EVENT ev,EFUNC fun);` 将函数绑定到一个事件。事件产生时会调用函数。 `void syncevent(EVENT ev,EPARA para);` 同步触发一个事件。(绑定的函数返回之后这个函数才会返回) `void asyncevent(EVENT ev,EPARA para);` 异步触发一个事件。(使用多线程,调用之后立即返回,绑定的函数在新的线程中运行) `T transepara(EPARA ep);` 将 `EPARA` 类型转换成其他类型。 例如,转 `int`:`transepara<int>(p);` #### 系统自动触发的事件 见 <https://www.luogu.com.cn/paste/vpcptoi2>。 ### 5.滤镜操作 #### 数据类型 `AREADATA`:指针,指向一个存储区域信息的 `AREADADTAMEM` 结构体。 #### 函数 `DCOLOR &getpxfromarea(AREADATA dta,int x,int y);` 获取区域中某个像素的颜色。 `void copyarea(AREADATA src,AREADATA buf);` 复制区域信息。 `void brighten(int x,int y,int w,int h,int deg);` 将指定区域变亮。前四个参数指定区域左上角坐标、宽度、高度,最后一个参数是变亮的程度。 `void darken(int x,int y,int w,int h,int deg);` 将指定区域变暗。`deg` 是变暗的程度。 `void grey(int x,int y,int w,int h);` 将指定区域变为黑白。 `void mosaic(int x,int y,int w,int h,int deg);` 将指定区域变为马赛克。`deg` 是马赛克中每一个正方形的边长。 `void blur(int x,int y,int w,int h,int deg);` 将指定区域变模糊。`deg` 是模糊程度。 #### 自定义滤镜 `void dofilter(FilterT fltr,int x,int y,int w,int h);` 运行自定义滤镜,第一个参数是滤镜,后面指定一个区域。 滤镜的定义方法类似于 `sort` 自定义比较方式。滤镜可以有: 1. 滤镜函数 自定义一个 `void xxx(AREADATA dat);` 这样函数,里面对传入的区域进行操作。 2. 滤镜对象 用结构体或者类,重载 `operator()` 运算符,类型、功能同滤镜函数。然后用这个结构体或类定义一个对象,就可以作为滤镜。 ### 6.菜单操作 #### 基本信息 DevGUI 中菜单用多叉树存储。 一般每一个菜单项上都有文字,是一个字符串。叶子结点的菜单项还可以有命令,命令是 `int` 类型,点击后触发异步事件 `Button-XX` 其中 `XX` 为设置的命令。 例如,一个菜单项命令为 $123$,点击后就会触发 `Button-123` 事件。 某些菜单中间的灰色分割线也视为菜单项。 对于非叶子结点,忽略命令。 对于根结点,忽略文字、命令。 对于分割线,忽略文字、命令。 #### 数据类型 `DMENUNODE` 菜单节点 `MENU`(又称 `DMENUTREE`、`DMENU`) 是指向 `DMENUNODE` 的指针,表示一棵树、一个菜单 如果 `m` 是 `MENU` 类型, - `m->child(idx)` 获取某一个子菜单,编号从 $0$ 开始 - `m->children()` 返回包含所有子菜单的 `vector` - `m->chcnt()` 返回子菜单数量 - `m->leaf()` 判断是否是叶子结点 - `m->settext(str)` 设置菜单项上的文字(`&` + 一个字符 可以实现字符下加下划线,并作为 `Alt` + 字母 的快捷键) - `m->setcmd(c)` 设置菜单项对应的命令 #### 函数 `void newmenu(string txt,uint cmd);` 指定文字、命令,创建菜单结点。 `void newmenu(string txt);` 指定文字,命令为 $0$,创建菜单结点。 `void newseparator();` 创建分割线菜单结点。 `void setmenu(MENU mn);` 将菜单应用到窗口。 `void delmenu(MENU mn);` 删除一个菜单结点及其所有子树,释放内存。 ### 7.网络操作 `int downloadfile(string url,string path);` 根据 URL 从网络上下载文件到指定路径。 ### 8.脚本操作 `void runcmd(string cmd);` 运行 cmd 命令。 `string runvbs(string prog);` 运行 vbs 命令,运行命令前会先在脚本里定义一个变量 `ret`,vbs 命令运行完成后函数会以字符串的方式返回这个变量,命令可以通过设置这个与主程序传递信息。 `string vbsinput(string info,string title="");` 用 vbs 脚本实现的输入框。第一个参数指定输入框文字提示内容;第二个参数指定输入框标题,可以不写,默认为空。返回输入的字符串,点击“取消”会返回空字符串。 `int vbsmsgbox(string info,string title,int mstyle);` 用 vbs 脚本实现的消息框。参数分别指定消息内容、标题、样式,返回对按钮的选择情况。 ### 9.控制台操作 $\color{red}{\bold{\text{仅限项目中使用。}}}$ `void openconsole(void);` 创建控制台。 `void consoleout(string str);` 在控制台中输出字符串。 `void cputs(const char *s);` 相当于 `puts`。 `char cputc(char c);` 相当于 `putchar`。 `int cprintf(const char *fmt,...);` 相当于 `printf`。 注意:关于速度,这些函数都是用 `consoleout` 实现的,理论上 `consoleout` 最快。 ### 10.音乐操作 注意:如果涉及到音乐文件,只支持 `.wav` 文件,其他格式请转换成 `WAV` 后使用。 目前我发现比较好用的是 [这个网站](https://convertio.co/zh/mp3-wav/)。 `void beep(int freq,int tim);` 发出频率为 $\operatorname{freq}\ \operatorname{Hz}$,时长为 $\operatorname{tim}\ \operatorname{ms}$ 的声音。 `void playmusic(string path);` 异步播放音乐,调用后立即返回,音乐与之后的程序同时运行。 `void finishmusic(string path);` 同步播放音乐,音乐播完后返回。 `void playmusicuntilend(string path);` 相当于 `finishmusic`。 `void playmusicloop(string path);` 异步循环播放音乐,调用后立即返回,之后音乐循环播放。 `void stopallmusic();` 停止所有音乐。 ### 11.版本信息 `int verval(int idx);` 获取版本信息第 $\operatorname{idx}$ 位,位数从 $1$ 开始。 `string version();` 获取简短的版本号字符串。 `string longversion();` 获取完整的版本号字符串。 `dver.h` 第一行注释 (v2.1 及以后)表示版本号。 ### 12.杂项 `UNUSED(var)` 表示变量 `var` 没有使用。(防止编译器报警告) (完) 放一个汉诺塔模拟器: ```cpp #include <dgui.h> #include <algorithm> #define N 67 #define NC 10 #define NCMX 17 #define INF 0x7fffffff using std::sort; int n=8; int twr[5][N],cnt[5]; int sel; int interv=200; DCOLOR nodec[NCMX]={ getcolor("red"), getcolor("orange"), getcolor("yellow"), getcolor("lime"), getcolor("green"), getcolor("blue"), getcolor("cyan"), getcolor("purple"), getcolor("pink"), getcolor("grey") }; DCOLOR framec=getcolor("default"); void tpush(int pos,int id){ twr[pos][++cnt[pos]]=id; } int ttop(int pos){ return twr[pos][cnt[pos]]; } void tpop(int pos){ --cnt[pos]; } void init(){ cnt[1]=cnt[2]=cnt[3]=0; for(int i=1;i<=3;++i){ twr[i][0]=INF; } for(int i=n;i>=1;--i){ tpush(1,i); } } int getnw(int id){ return 30+(id-1)*10; } DCOLOR getnc(int id){ return nodec[(id-1)%NC]; } void upd(){ setfillcolor(framec); clear(); rectangle(30,60,100,50); textout(45,63,"还 原"); rectangle(30,130,100,50); textout(45,133,"自 动"); rectangle(30,200,100,50); textout(45,203,"设 置"); /*80 10 160 10 160 10 80*/ rectangle(180,400,510,10); rectangle(260,100,10,300); rectangle(430,100,10,300); rectangle(600,100,10,300); for(int i=1;i<=3;++i){ for(int j=1;j<=cnt[i];++j){ setfillcolor(getnc(twr[i][j])); int w=getnw(twr[i][j]); if(i==sel&&j==cnt[i]){ rectangle(180+85+(i-1)*170-(w>>1),50,w,20); } else{ rectangle(180+85+(i-1)*170-(w>>1),400-j*20,w,20); } } } } void movenode(int src,int dst){ tpush(dst,ttop(src)); tpop(src); } void clickpos(int pos){ if(sel){ if(sel==pos){ sel=0; } else{ if(ttop(sel)<ttop(pos)){ movenode(sel,pos); sel=0; } } } else{ if(cnt[pos]){ sel=pos; } } upd(); } void setting(){ string s; while(1){ s=vbsinput("请输入层数:","汉诺塔"); if(isnumstr(s)){ n=strtoint(s); break; } else{ vbsmsgbox("请输入数字!","汉诺塔",0); } } init(); upd(); } void cmove(int src,int dst){ clickpos(src); sleep(interv); clickpos(dst); sleep(interv); } void solve(int src,int dst,int mcnt){ if(mcnt==0){ return; } if(mcnt==1){ cmove(src,dst); return; } int mid=6-src-dst; solve(src,mid,mcnt-1); cmove(src,dst); solve(mid,dst,mcnt-1); } void autosolve(){ init(); upd(); sleep(interv); solve(1,3,n); } void onmouse(EPARA p){ UNUSED(p); static DRECT r1=DRECT(30,60,130,110), r2=DRECT(30,130,130,180), r3=DRECT(30,200,130,250); DPOINT pos=mousepos(); int x=pos.x,y=pos.y; if(inrect(pos,r1)){ init(); upd(); } if(inrect(pos,r2)){ autosolve(); } if(inrect(pos,r3)){ setting(); } if(x<180||x>690||y>410){ return; } if(x==690){ x=689; } clickpos((x-180)/170+1); } void onkey(EPARA p){ int vk=transepara<int>(p); switch(vk){ case '1':{ clickpos(1); break; } case '2':{ clickpos(2); break; } case '3':{ clickpos(3); break; } case 'I':{ init(); upd(); break; } case 'A':{ autosolve(); break; } case 'S':{ setting(); break; } } } int main(){ hideconsole(); setup(750,550,"汉诺塔"); init(); setting(); upd(); bind("MouseDown-L",onmouse); bind("KeyDown",onkey); keepwindow(); return 0; } ```
Loading...
点赞
6
收藏
0