分享

(五)EGE窗口

 我就是个蒟蒻 2020-08-08

窗口的基本设置

窗口的打开与关闭

  • 使用 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会自动重绘。也可以是设置 bRepainttrue 来立即重绘。
  另外还有窗口宽高参数,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为不透明。

  • 设置成窗口透明样式,透明度为0xc0
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_RENDERMANUALINIT_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延时函数

  • 具有刷新窗口功能:
    强制刷新:
    delay_fps() (延时刷新,常用)
    delay_jfps()
    delay_ms() 延时时间不为0
    Sleep() 延时时间不为0

    绘制后才刷新:
    delay_ms(0) (不延时刷新,常用)
    getch()

  • 不具有刷新窗口功能:
    delay()
    api_sleep()
    ege_sleep()

如果你的程序有清屏之类窗口颜色变化极大的,那就肯定选 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窗口句柄

  • 获取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) 。当然,没了上边的白边后,窗口就无法拖动了,甚至连关闭按钮都没有

方法:

  1. 可以自己检测用户按键,软件一般是设置按下ESC后退出全屏, 设置成按下任意键也行。
  2. 需要快捷键,这个是需要自己知道,给别人用可不行,万一别人不会, 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;
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多