窗口的基本设置
窗口的打开与关闭
- 使用 initgraph() 打开窗口,closegraph() 关闭窗口
- initgraph(width, height, mode), 后面那个 mode 参数传入0就行
下面是一个窗口的打开的关闭的示例:
#include <graphics.h>
int main()
{
initgraph(640, 480, 0);
getch();
closegraph();
return 0;
}
你的窗口打开会有动画?
像下面这样
如果你不想要,那么请你使用
initgraph(width, height, 0) 最后那个参数传入0
改变窗口的大小
- 同样是调用 initgraph() , 传入窗口的尺寸就可以改变窗口的大小
- 需要注意的是 initgraph() 第三个参数是 窗口初始化模式,只在第一次创建窗口时有效,之后调用就只有改变窗口尺寸的作用, 而且窗口左上角位置是不变的
要注意哦,每次调用 initgraph() 虽然改变了窗口尺寸,但是窗口也会被背景色清空,绘画的内容也被清空,所以调用后注意要重画
示例:按下按键改变窗口大小(如果按键按下窗口没反应,请用鼠标点击一下窗口,不然焦点不在EGE窗口上)
#include <graphics.h>
int main()
{
initgraph(400, 400, 0);
getch();
initgraph(300, 100);
getch();
initgraph(600, 600);
getch();
closegraph();
return 0;
}
设置窗口位置(只在第一次有效)
在第一次调用 initgraph() 前调用一句 setinitmode() 即可, 就可以设置窗口左上角所在的位置
- setinitmode(mode, x, y), 其中 mode 是窗口初始化模式(
后面会有说明 ),x, y 是窗口左上角出现在屏幕的坐标
示例:
#include <graphics.h>
int main()
{
setinitmode(0, -8, 0);
initgraph(600, 600, 0);
getch();
closegraph();
return 0;
}
移动窗口
EGE中并没有移动窗口的函数,但是可以利用窗口句柄,调用WinAPI来移动窗口,使用的是 MoveWindow() 函数
WINUSERAPI
BOOL
WINAPI
MoveWindow(
_In_ HWND hWnd,
_In_ int X,
_In_ int Y,
_In_ int nWidth,
_In_ int nHeight,
_In_ BOOL bRepaint);
hWnd 参数是窗口句柄,可以通过 ege 中的 getHwnd() 获取EGE窗口的句柄
bRepaint 是否重绘。移动后窗口应该重绘,但如果是EGE手动重绘,之后有调用delay_fps(),可以设置为false 因为EGE会自动重绘。也可以是设置 bRepaint 为 true 来立即重绘。
另外还有窗口宽高参数,当 bRepaint 为true时,这两个参数是无效的。所以如果想用 bRepaint 缩放窗口,就要设置 bRepaint为false
所以移动窗口如下:
比如要移动窗口到屏幕 (10, 30) 的位置。
MoveWindow(getHWnd(), 10, 30, getwidth(), getwidth(), true);
注意事项
- 移动窗口后,应该刷新一次窗口,可以是bRepaint赋值为true. 也可以是EGE自动刷新,或者是EGE设置为手动渲染时的手动刷新。(如果不知道什么意思,可以看后面的内容)
- 如果移动频繁,最好用手动渲染模式,否则容易闪烁。
窗口移动示例():
#include <graphics.h>
int main()
{
int scrWidth = 400, scrHeight = 400;
//设置手动渲染模式,并且设置窗口位置
int x = 50, y = 50;
setinitmode(INIT_RENDERMANUAL, x, y);
//创建窗口
initgraph(scrWidth, scrHeight);
//设置颜色
setbkcolor(WHITE);
setcolor(BLACK);
setfillcolor(BLUE);
//获取EGE窗口句柄
HWND egeHWnd = getHWnd();
int dx = 0, dy = 0;
for (; is_run(); delay_fps(60)) {
//回到原点清屏重绘
if (dx + dy == 0) {
cleardevice();
bar(100, 100, 300, 300);
}
//饶边走
if (dy == 0)
dx += 2;
else if (dy == 400)
dx -= 2;
if (dx == 400)
dy += 2;
else if (dx == 0)
dy -= 2;
//画路径
circle(100 + dx / 2, 100 + dy / 2, 10);
//移动窗口
MoveWindow(egeHWnd, x + dx, y + dy, scrWidth, scrHeight, false);
}
closegraph();
return 0;
}
设置窗口背景颜色
- 调用 setbkcolor() 即可
大多数窗口背景色是白色的
#include <graphics.h>
int main()
{
initgraph(600, 600, 0);
setbkcolor(WHITE); //改变窗口背景颜色为白色
getch();
closegraph();
return 0;
}
窗口清屏
调用 cleardevice(), 那么整个窗口就会被背景色填充
- 好不容易画出的东西为什么要用清屏清掉?
我们知道屏幕是由很多像素点组成的,每一个像素点的颜色用一个无符号整型来表示。每一次绘画,其实就是在改变这些像素点的颜色,如果你不修改它,那么它就不变。所以如果你上一次绘画,修改了一些像素点颜色。而这次绘画,又改变了一些像素点的颜色。如果两个改变的像素点不一样,就会出现同时看到两次绘画的结果。而如果前面那些画的,我不想要了,就可以把那些被修改过的改回来。可是如果我并不知道之前改了哪些像素,那只能清屏了。
- 清屏后我画的东西都不见了怎么办?
重新画
- 每次都画它不慢吗? 如果我每次都要画很多
一般情况下绘制速度是满足要求的,重绘一次需要的时间不多。
但是如果整个绘图十分的复杂,绘制速度就达不到要求,此时可以设置缓存,不变的部分可以缓存到一起,根据实际情况判断是否需要重绘缓存。这样就减少了绘制量。
透明窗口
EGE没有设置窗口透明的API,但是可以用winAPI做,只要获取EGE窗口的句柄,就可以设置了,下面把EGE窗口透明写成一个函数。
void setWindowTransparent(bool enable, int alpha = 0xFF) {
HWND egeHwnd = getHWnd();
LONG nRet = ::GetWindowLong(egeHwnd, GWL_EXSTYLE);
nRet |= WS_EX_LAYERED;
::SetWindowLong(egeHwnd, GWL_EXSTYLE, nRet);
if (!enable)
alpha = 0xFF;
SetLayeredWindowAttributes(egeHwnd, 0, alpha, LWA_ALPHA);
}
如果想要把窗口弄成透明,可以传入透明度, 范围0 ~ 0xFF, 0为全透明,0xFF为不透明。
setWindowTransparent(true, 0xc0);
setWindowTransparent(false);
控制台的显示控制
VS2017
VS2017是默认关闭控制台的,如果想要调出控制台,需要在所有 #include <graphics.h> 前面加个 #define SHOW_CONSOLE 的宏定义,。
记住,是所有哦, 如果有多个.cpp源文件,每个源文件都包含有 <graphics.h> ,那么每个都要加上
VS2019
操作和VS2017一样,但如果VS2019总是跳出控制台,需要设置一下在项目属性中设置一下子系统, 如果原先是控制台,那么设置成未设置
CodeBlocks
CodeBlocks是 默认打开控制台 的,如果想要关闭,可以在项目属性设置里,设置成 GUI应用(图形用户界面应用),然后 Rebuild 一下
关闭方法:
工具栏 Project --> Properties --> 选项卡 Build targets, 设置成GUI application
DevC++
点击工具栏 项目(Project)–>项目属性(Project Option…),然后将应用类型设置为 Win32 图形界面程序(Win32 GUI) , 然后 重新编译运行(Rebuild all) 即可。
更多的窗口设置介绍
EGE官网绘图环境相关函数文档 http:///manual/api/env/index.htm
(1) 初始化窗口
窗口初始化是调用了 initgraph( ) 函数,调用函数后创建一个窗口。
第一次调用 initgraph() 为窗口初始化,后面的调用只能说是改变窗口大小
函数声明为
void initgraph(int Width, int Height, int Flag = INIT_DEFAULT);
参数说明:
- Width: 窗口宽, Height:窗口高
窗口的宽和高的大小是有限制的,不会超过你屏幕的分辨率。屏幕的分辨率一般为1920 x 1080。
而且与你的缩放有关,下面可以看到我的笔记本默认是125%放大显示的,那么实际就没有1920x1080那么大了
如果设置width = -1 , height = -1, 那么窗口将会全屏显示
- Flag参数: 窗口初始化模式, 如果你不设置这个参数,那么默认就是 INIT_DEFAULT,即如果是Debug模式,则是普通窗口, Release模式则是带开场动画的窗口
- 看一下ege.h头文件中 初始化模式 的枚举定义
可以看到,有多种初始化模式,分别对应一个值,这些值用二进制 表示都只占一位。而我们最常用的就是 0
用二进制的位来表示,是为了让这些模式可以通过 位或 来组合
enum initmode_flag {
INIT_NOBORDER = 0x1, 无边框窗口
INIT_CHILD = 0x2, 子窗口,需要使用其它函数配合
INIT_TOPMOST = 0x4, 顶层窗口,不会被其它窗口遮住
INIT_RENDERMANUAL = 0x8, 手动渲染
INIT_NOFORCEEXIT = 0x10, 退出时不强制结束程序
INIT_WITHLOGO = 0x100, 带EGE开始动画LOGO
默认模式的定义
#if defined(_DEBUG) || defined(DEBUG)
INIT_DEFAULT = 0x0, Debug模式下为普通窗口
#else
INIT_DEFAULT = INIT_WITHLOGO, Release模式下为带开场动画窗口
#endif
动画窗口为几种模式的组合
INIT_ANIMATION = INIT_DEFAULT | INIT_RENDERMANUAL | INIT_NOFORCEEXIT,
};
flag参数, 为二进制值,可以通过位或操作进行模式组合,参考 INIT_ANIMATION
- INIT_NOBORDER, 为无边框窗口
- INIT_CHILD, 为子窗口(需要使用attachHWND指定要依附的父窗口,此函数不另说明)
- INIT_TOPMOST , 使窗口总在最前
- INIT_RENDERMANUAL, 手动更新标志,即调用delay_fps/delay_ms等会等待操作的函数时会更新窗口,否则保持窗口内容,这是为了减少绘制,减少界面闪烁
- INIT_WITHLOGO, 使initgraph的时候显示开场动画logo
- INIT_NOFORCEEXIT , 使关闭窗口的时候不强制退出程序,但窗口会消失,需要配合is_run函数
- INIT_DEFAULT , 默认参数,不调用本函数时即使用此参数
- INIT_ANIMATION , 是 INIT_DEFAULT, INIT_RENDERMANUAL和 INIT_NOFORCEEXIT 三个的组合,用于动画编写
- 如果你不想要开场动画,设置不带开场动画的窗口可以调用 initgraph(640, 480, 0)。
现在来看看各种窗口效果,下面是测试程序 (请修改 initgraph() 的第三个参数)
#include <graphics.h>
int main()
{
initgraph(640, 480, INIT_NOBORDER);
setbkcolor(0xFFFF00);
getch();
closegraph();
return 0;
}
(2) 设置初始化模式
函数为 setinitmode() , 设置初始化模式,只能在第一次调用 initgraph() 前调用,不然窗口已经初始化完毕,设置对窗口无效。
setinitmode() 有两个功能:
函数声明:
void setinitmode(int mode, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT);
参数:
- mode: 和 initgraph() 第三个参数一致,请查看 initgraph() 参数说明。
- x, y:即窗口左上角的位置坐标, 不设置则使用默认窗口位置。
(3) 设置渲染模式
setrendermode(), 用于设置渲染模式,需要在初始化窗口 initgraph() 之后调用
void setrendermode(rendermode_e mode);
参数 mode,
值有两个可选:
- RENDER_AUTO (默认值)
自动渲染模式,即调用绘图类的函数后,由库确定何时刷新(定时或者积累足够次数) ,把绘画的内容显示到窗口上。
优点:绘画后显示
缺点:少量绘制后便会刷新一次窗口,当绘制复杂时,多次刷新比较费时,造成绘制慢。因为不确定何时刷新,可能在没有绘制完一帧时刷新窗口,容易出现窗口闪烁现象。
- RENDER_MANUAL
自动模式用于简单绘图,手动模式用于制作动画或者游戏
手动渲染模式,即需要自己调用 delay_fps, delay_ms, getch() 等带有等待特性并具有刷新功能的函数来刷新窗口,加快绘制速度,减少闪烁。
优点:减少刷新次数,加快绘制。并且只在调用某些延时类函数时刷新,避免显示不完整的一帧,减少闪烁。
缺点:不调用延时函数时不会刷新窗口,如果整个循环没有调用带刷新功能延时类函数,将看不到绘制内容。
绘制时推荐一直使用手动渲染模式,这将提高绘制效率,并且绘制内容复杂时减少闪烁情况。如果有必要刷新窗口,查看显示内容的,可以插入delay_ms(0) 来手动刷新
EGE延时函数
如果你的程序有清屏之类窗口颜色变化极大的,那就肯定选 RENDER_MANUAL, 一般情况下选 RENDER_MANUAL 也没错
设置渲染模式也可以在窗口初始化时设置:
initgraph(640, 480, INIT_RENDERMANUAL);
(4) 设置窗口标题
在调用initgraph() 之后使用
void setcaption(LPCSTR caption);
void setcaption(LPCWSTR caption);
参数:caption, 指定要设置的标题字符串,可用宽字符或MBCS字符串,需要使用gbk编码。
使用示例:
setcaption(“EGE窗口标题”);
所以一般的设置是这样的(窗口标题不设置也行)
#include <graphics.h>
int main()
{
initgraph(640, 480, INIT_RENDERMANUAL); //初始化窗口
setcaption("EGE窗口标题"); //设置窗口标题
//颜色初始设置
setbkcolor(WHITE);
setcolor(BLACK);
setfillcolor(BLUE);
//文字设置
setbkmode(TRANSPARENT);
setfont(16, 0, "楷体");
/*绘图交互部分*/
/*绘图交互部分*/
getch();
//绘图结束,关闭窗口
closegraph();
return 0;
}
(5) 清除屏幕
cleardevice()
调用后用背景色清空画面, 背景色可用 setbkcolor() 设置,背景色默认是黑色,即 EGERGB(0, 0, 0)
(6) 检测窗口环境是否关闭
bool is_run();
is_run(),若用户点击了右上角关闭窗口按钮或者 Alt+F4 之类关闭窗口操作,则返回 false,否则返回 true, 只在设置窗口初始化模式为非强制退出模式时有效。
使用 closegraph() 关闭窗口,其实只是隐藏窗口不显示,窗口环境还在,并没有被关闭。在窗口右上方点击X号时,这是窗口环境才是被关闭了。所以调用closegraph() 关闭窗口后, is_run() 返回的是 true。
关于is_run()的说明
is_run() 只在窗口初始化模式设置为非强制退出(INIT_NOFORCEEXIT) 时返回结果有效,否则一直返回 true。
所以在没有设置非强制退出(INIT_NOFORCEEXIT) 时,下面这个和死循环没区别
//is_run()一直返回 true
for (; is_run(); delay_fps(60)) {
}
下面的语句不会执行
非强制退出模式
设置非强制退出模式: 在窗口初始化模式添加 INIT_NOFORCEEXIT
initgraph(640, 480, INIT_NOFORCEEXIT);
这个窗口初始化模式可以组合,比如可以与手动渲染模式组合成 INIT_RENDERMANUAL | INIT_NOFORCEEXIT
initgraph(640, 480, INIT_RENDERMANUAL | INIT_NOFORCEEXIT);
当窗口初始化模式设置为非强制退出(INIT_NOFORCEEXIT) 后,可以通过 is_run() 返回值来判断是否要关闭窗口结束程序。
当用户关闭窗口时,非强制退出模式下程序会一直往下执行,直至程序运行结束,并且 getch(), getkey(), getmouse() 之类的函数不再阻塞程序(返回值为0) 。所以在非强制退出模式下,用户关闭窗口时,关不关闭,何时关闭完全由程序控制。
如果没有设置为非强制退出模式, 当用户关闭窗口时,程序会直接中断,强制结束。
非强制退出模式,可用于在用户关闭窗口时,对数据保存,显示关闭动画等后续处理,避免直接结束程序而导致没有保存数据。
下面是一个设置与不设置非强制退出模式的区别示例
不设置非强制退出,关闭窗口时直接退出程序
#include <graphics.h>
int main()
{
initgraph(640, 480, 0); //设置为普通窗口模式
setbkcolor(WHITE);
settextjustify(CENTER_TEXT, CENTER_TEXT); //文字与输出坐标中心对齐
setcolor(BLUE);
setfont(32, 0, "宋体");
outtextxy(320, 240, "点击右上角关闭按钮");
//不设置非强制退出, is_run()会一直返回true
//关闭窗口时直接中断程序退出
for (; is_run(); delay_fps(60)) {
}
//下面不会执行
cleardevice(); //清屏
setfont(128, 0, "宋体");
setcolor(RED);
outtextxy(320, 240, "拜拜~");
delay_ms(1000); //延时1秒
cleardevice();
setfont(64, 0, "宋体");
outtextxy(320, 240, "爱你的每一天");
delay_ms(1000); //延时1秒
closegraph(); //隐藏窗口
return 0;
}
设置非强制退出,关闭窗口时会继续执行,由程序控制何时退出程序
#include <graphics.h>
int main()
{
initgraph(640, 480, INIT_NOFORCEEXIT); //设置为非强制退出模式
setbkcolor(WHITE);
settextjustify(CENTER_TEXT, CENTER_TEXT); //文字与输出坐标中心对齐
setcolor(BLUE);
setfont(32, 0, "宋体");
outtextxy(320, 240, "点击右上角关闭按钮");
//不设置非强制退出, is_run()一直返回true
for (; is_run(); delay_fps(60)) {
}
//下面会继续执行
cleardevice(); //清屏
setfont(128, 0, "宋体");
setcolor(RED);
outtextxy(320, 240, "拜拜~");
delay_ms(1000); //延时1秒
//无法阻塞,返回值为0
getch();
cleardevice();
setfont(64, 0, "宋体");
outtextxy(320, 240, "爱你的每一天");
delay_ms(1000); //延时1秒
closegraph(); //隐藏窗口
return 0;
}
(7) 获取窗口尺寸
int width = getwidth(); //获取窗口的宽度
int heigth = getheight(); //获取窗口的高度
或者
int width = getmaxx();
int heigth = getmaxy();
(8) getHWnd()获取EGE窗口句柄
HWND getHWnd();
(9) getHInstance() 获取实例句柄
(10) attachHWND() 依附窗口
int attachHWND(HWND hWnd);
- 配合 setinitmode()中的flag参数使用, 当flag为 INIT_CHILD, 表示EGE作为子窗口依附在别的窗口上。此时需要设置调用 attachHWND(),设置依附的窗口。
(11)其它窗口设置函数
更多窗口设置请查看 EGE官网绘图环境相关函数文档:
http:///manual/api/env/index.htm
怎么让EGE窗口全屏
经过实验, 调用 initgraph(-1, -1), 并不能让EGE窗口全屏,左边还留着一点,可能是窗口最左上角的位置其实是 (8, 0), 旁边窗口旁边其实有个透明的边框。所以可以在初始化窗口前,加个 setinitmode(0, -8, 0)
又有个问题,EGE的窗口上面有个白色的边框(标题栏),如果真的想完全全屏,可以使用无边框窗口,这样就隐去了窗口的白边。没了边框之后,窗口位置就可以设成 (0, 0) 。当然,没了上边的白边后,窗口就无法拖动了,甚至连关闭按钮都没有
方法:
- 可以自己检测用户按键,软件一般是设置按下ESC后退出全屏, 设置成按下任意键也行。
- 需要快捷键,这个是需要自己知道,给别人用可不行,万一别人不会, win + D 键显示桌面, Alt + Tab 切换窗口, Alt + F4 强制关闭程序
带标题窗口(白边)
setinitmode(0, -8, 0);
initgraph(-1, -1);
示例:
#include <graphics.h>
int main() {
setinitmode(0, -8, 0);
initgraph(-1, -1);
setbkcolor(EGERGB(0xff, 0, 0xff));
getch();
closegraph();
return 0;
}
完全全屏(无边框窗口)
setinitmode(INIT_NOBORDER, 0, 0);
initgraph(-1, -1);
如果你还想使用其它窗口模式,可以使用 位或, 如
setinitmode(INIT_NOBORDER | INIT_RENDERMANUAL, 0, 0);
示例程序一:
简单的打开关闭
#include <graphics.h>
int main() {
setinitmode(INIT_NOBORDER | INIT_RENDERMANUAL, 0, 0);
initgraph(-1, -1);
setcolor(BLACK);
setbkcolor(EGERGB(0xff, 0, 0xff));
setfont(24, 0, "楷体");
xyprintf(400, 400, "按下任意键结束");
getch();
closegraph();
return 0;
}
示例程序二:
缺点是无法设置窗口位置,也无法拖动窗口,EGE没有这样的函数来设置,只能自己通过WinAPI来实现
#include <graphics.h>
int main() {
setinitmode(INIT_NOBORDER | INIT_RENDERMANUAL, 0, 0);
initgraph(-1, -1);
setcolor(BLACK);
setbkcolor(EGERGB(0xff, 0, 0xff));
setfont(24, 0, "楷体");
bool flag_fullScreen = true;
xyprintf(400, 400, "按下ESC键退出全屏");
xyprintf(400, 440, "按下回车键关闭程序");
bool exit = false;
for (; is_run() && !exit; delay_fps(30)) {
key_msg keyMsg = { 0 };
while (kbmsg()) {
keyMsg = getkey();
if (keyMsg.msg == key_msg_up) {
switch (keyMsg.key) {
case key_esc:
flag_fullScreen = !flag_fullScreen;
if (flag_fullScreen) {
initgraph(-1, -1);
setbkcolor(EGERGB(0xff, 0, 0xff));
xyprintf(400, 400, "按下ESC键退出全屏");
xyprintf(400, 440, "按下回车键关闭程序");
}
else {
initgraph(640, 480);
setbkcolor(EGERGB(0xff, 0, 0xff));
xyprintf(180, 160, "按下ESC键进入全屏");
xyprintf(180, 200, "按下回车键关闭程序");
}
break;
case key_enter:
exit = true;
break;
}
}
}
}
closegraph();
return 0;
}
|