1. 方法-1:内嵌式
顾名思义,我们主动在自己写的GUI程序中,创建一个控制台。
1.1 API
在Windows 的API,提供一大族Console的函数(最无聊的,比如可以设置字符颜色:) ),AllocConsole用来直接为一个进程创建一个控制台。注意,一个进程只能有一个控制台:
Remarks
A process can be associated with only one console, so the AllocConsole function fails if the calling process already has a console. A process can use the FreeConsole function to detach itself from its current console, then it can call AllocConsole to create a new console or AttachConsole to attach to another console.
怎么让“编程”与“英语”齐飞,C++与Windows API一色呢?请参看我的另一篇笔记《学习编程需要什么英语基础?》。
1.2 主要类设计
好,这一段就基本齐全了,连设计模式都有了:既然“A process can be associated with only one console”,那就来一个简单的“单例模式”吧。
EmbeddedConsole 的构造和析构函数都是private的。我们逼着自己通过“Need()”函数来new 出这个类的对象,而不是直接在全局范围内,定义一个它的对象,是因为我们需要严格的控制这个对象的“生死”时机。C++控制台程序是“耍了手段”,替我们尽量安全地往前自动生成cout, cin, cerr 这三个对象(没错,这三个老朋友都是变量),但对于GUI程序,它们要起效,必须有一个真正的控制台——我们通过AllocConsole所做的事情。
构造函数分配一个控制台,然后重定向; 析构函数关闭三个标准控制台文件,然后释放控制台,注意次序。
构造函数中,我还特意调用了一下SetConsoleTitle,用来修改控制台标题,同时也用来体现一名像我这样“专业的”程序员所必须拥有的“骚包”劲儿。
静态成员数:instance 确保我们不会愚蠢地一直尝试去重新分配控制台(AllocConsole函数是有返回值的,这里简单地认定它一定会成功 :)。
第44 行在类之外定义了类的静态成员数据,这是必须的,除非那是一个静态常量成员内置类型数据,请参看《纠正“C++测试题的一些问题”的问题》。
1.3 测试例子
来一个使用例子。请在Code::Blocks(或你用的其它编程IDE),通过"Win32 GUI project”向导,生成一个应用,提问窗口类型时,请选择“Dialog”, 编译运行后,应该出来一个有两个按钮的对话框。点击“test”按钮,应该出一个消息框(MessageBox),这就是我们要改掉的地方,加入以上代码,全部代码如下:
第82行,是用户按下“test”按钮时,要执行的代码。
我们先在83行通过Need()函数,确保控制台生成。然后就是我们熟悉的 cin, cout , cerr 的使用了,当然这里的cerr用得没有什么逻辑。
第76行,那是用户按下"quit"按钮时,要执行的代码。我们只是调用了Unneed()函数,表示我们在程序退出前,释放掉之前创建的控制台。
对了,如果你害怕在发布发行版时,忘了屏掉这个功能,可以通过宏来检测编译版本,如果发现它是release版时,就什么也别做。由于不同的编译器用于判断编译版本,有不同的宏名称,所以我就不写了。
1.4 截图
附带控制台分两部分