分享

在GUI程序中使用控制台的两种方法

 willor 2013-08-01
经常需要在GUI下面做些计算程序的测试,想很快的看到计算结果并且希望通过控制台输出来,所以找到了以下的文章。
reference:
http://blog.csdn.net/wangfutao01/article/details/6473498
http://blog.csdn.net/nanyu/article/details/6473435
http://blog.csdn.net/nanyu/article/details/6474939
http://lgy-047.blog.163.com/blog/static/613465652009112672118305/
http://blog.csdn.net/lzhlzz/article/details/6585554
http://blog.csdn.net/lzhlzz/article/details/6585559
注: 用关键词 "EmbeddedConsole* EmbeddedConsole::_instance;" 或者"在GUI程序中使用控制台"可以baidu到很多类似的文章。

1 何谓输入输出重定向?

默认情况下输入是由键盘输入的。输出是默认的输出到屏幕上。而输入输出重定向就是改变默认的输入输出方向。。呵呵。

2 freopen()函数

函数名:freopen
声明:FILE *freopen( const char *path, const char *mode, FILE *stream );
所在文件: stdio.h
参数说明:
path:
文件名,用于存储输入输出的自定义文件名。
mode:
文件打开的模式。和fopen中的模式(如r-只读, w-写)相同。
stream:
一个文件,通常使用标准流文件。
返回值:成功,则返回一个path所指定文件的指针;失败,返回NULL。(一般可以不使用它的返回值)

与该函数相对应的函数是

下面我们就用这两个函数来实现一下输入输出重定向

 

int fclose ( FILE * stream );
返回值表示:若stream被成功关闭将返回一个0值,否则返回EOF.
Code:
  1. #include <iostream>   
  2. #include <string>   
  3. using namespace std;   
  4. int main()   
  5. {   
  6.    freopen("out.txt","w",stdout);   
  7.    string str;   
  8.    while (cin >> str)   
  9.    cout << str << endl;   
  10.    fclose(stdout);   
  11.     return 0;   
  12. }  

这个程序实现了输出重定向,即:输出不再是默认的屏幕了,而是输出到了out.txt这个文件中。同样,用此种方法我们也可以实现输入重定向。

呵呵。掌握了这点知识,基本上就可以学南老师的那篇笔记了:

在GUI程序中使用控制台的两种方法-方法一:http://student.csdn.net/space.php?uid=112600&do=blog&id=10713

现在分析老师的笔记内容以帮助自己加深理解:

Code:
  1. struct EmbeddedConsole      
  2. {      
  3. public:          
  4.     static void Need()    //define a function to malloc  a object   
  5.     {      
  6.             
  7.   
  8.         if (!_instance)      
  9.         {      
  10.             _instance = new EmbeddedConsole;      
  11.         }      
  12.             
  13.   
  14.     }      
  15.           
  16.     static void Unneed()   // release a object.   
  17.     {      
  18.         delete _instance;      
  19.         _instance = 0;      
  20.     }      
  21.           
  22. private:      
  23.     EmbeddedConsole()    //construct.   
  24.     {      
  25.         AllocConsole();      
  26.               
  27.         SetConsoleTitle("XXX程序内嵌测试控制台");      
  28.               
  29.         freopen("conin$""r+t", stdin);    // in redirect.   
  30.         freopen("conout$""w+t", stdout);   // out redirect   
  31.         freopen("conout$""w+t", stderr);     // err redirect   
  32.     }      
  33.           
  34.     ~EmbeddedConsole()   //destructor   
  35.     {      
  36.         fclose(stderr);   //release.   
  37.         fclose(stdout);      
  38.         fclose(stdin);      
  39.               
  40.         FreeConsole();      
  41.     }      
  42.           
  43.     static EmbeddedConsole* _instance;    // a static data member.   
  44. };      
  45.       
  46. EmbeddedConsole* EmbeddedConsole::_instance;   // the definition of the static member  

 总观整个类,我们可以发现,南老师把构造函数和析构函数定义为了私有。为的是不容许我们定义一个对象,即:

Code:
  1. EmbeddedConsole obj;  // error . cannot access the private constructor  

我们若想定义一个EmbeddedConsole对象。只能显示的调用static void Need()函数。这也就是为啥南老师把Need函数定义为static的原因。因为我们无法获得一个对象,也就无法调用普通的成员函数(因为普通的成员函数只能通过一个对象来调用。)。同理

static void Unneed()函数也被定义为了static.  既然仅有的两个成员函数都成static了,那么它仅有的数据成员_instance也只能是static了(static成员函数只能访问static数据成员)。这两个函数的作用分别是分配一个对象,释放一个对象。但我们看到老师的Need函数里用到了这样一个判断if (!_instance).意思是如果对象已经别分配了空间。就不再进行分配。对于另一个函数Unneed().老师的实现是:

Code:
  1. static void Unneed()      
  2. {      
  3.     delete _instance;      
  4.     _instance = 0;      
  5. }    

对于这个函数我觉得在delete使用之前应该进行一下判断if (_instance).即如果_instance有值.才进行删除操作。不过这样对每个对象都多了一层判断,在效率上势必会有影响。这两个函数内部调用了私有的构造函数和析构函数。进行对象的分配和释放。

好了,老师的这个类理解了,下面看看老师的实例:

Code:
  1. #define WIN32_LEAN_AND_MEAN   //???不明白何用   
  2.       
  3. #include <windows.h>      
  4. #include <iostream>      
  5. #include <string>      
  6.       
  7. #include "resource.h"      
  8.       
  9. HINSTANCE hInst;   //define a HINSTANCE handle object   
  10.       
  11. //the class just define.   
  12. struct EmbeddedConsole      
  13. {      
  14. public:          
  15.     static void Need()      
  16.     {      
  17.              
  18.   
  19.         if (!_instance)      
  20.         {      
  21.             _instance = new EmbeddedConsole;      
  22.         }      
  23.            
  24.   
  25.     }      
  26.           
  27.     static void Unneed()      
  28.     {      
  29.         delete _instance;      
  30.         _instance = 0;      
  31.     }      
  32.           
  33. private:      
  34.     EmbeddedConsole()      
  35.     {      
  36.         AllocConsole();      
  37.         SetConsoleTitle("XXX程序内嵌测试控制台");      
  38.               
  39.         freopen("conin$""r+t", stdin);      
  40.         freopen("conout$""w+t", stdout);      
  41.         freopen("conout$""w+t", stderr);       
  42.     }      
  43.           
  44.     ~EmbeddedConsole()      
  45.     {      
  46.         fclose(stderr);      
  47.         fclose(stdout);      
  48.         fclose(stdin);      
  49.               
  50.         FreeConsole();      
  51.     }      
  52.           
  53.     static EmbeddedConsole* _instance;       
  54. };      
  55.       
  56. EmbeddedConsole* EmbeddedConsole::_instance;      
  57.       
  58. BOOL CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)   // a callback function.   
  59. {      
  60.     std::string str;      
  61.           
  62.     switch (uMsg)   //deal with the message.   
  63.     {      
  64.         case WM_INITDIALOG:      
  65.             /*    
  66.              * TODO: Add code to initialize the dialog.    
  67.              */      
  68.             return TRUE;      
  69.       
  70.         case WM_CLOSE:      
  71.             EndDialog(hwndDlg, 0);      
  72.             return TRUE;      
  73.       
  74.         case WM_COMMAND:      
  75.             switch (LOWORD(wParam))      
  76.             {      
  77.                     /** TODO: Add more control ID's, when needed.    
  78.                      */      
  79.                 case IDC_BTN_QUIT:   /// a button (quit)   
  80.                     EndDialog(hwndDlg, 0);      
  81.                           
  82.                     EmbeddedConsole::Unneed(); //不要了!      
  83.                     return TRUE;      
  84.       
  85.                 case IDC_BTN_TEST:    /// a button (test)   
  86.                     EmbeddedConsole::Need(); //我要!      
  87.                     std::cout << "please input :";      
  88.                     std::cin >> str;      
  89.                     std::cerr << str << std::endl;      
  90.                     ::MessageBox(hwndDlg, str.c_str(), "Information"      
  91.                         , MB_ICONINFORMATION);      
  92.                     return TRUE;      
  93.             }      
  94.     }      
  95.       
  96.     return FALSE;      
  97. }      
  98.       
  99.       
  100. int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)      
  101. {      
  102.     hInst = hInstance;      
  103.       
  104.     // The user interface is a modal dialog box      
  105.     return DialogBox(hInstance, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DialogProc);      
  106. }    

这个实例就是用来测试刚才定义哪个类。来实现输入输出重定向。在用户点击test按钮的时候:

Code:
  1. case IDC_BTN_TEST:      
  2.     EmbeddedConsole::Need(); //我要!      
  3.     std::cout << "please input :";      
  4.     std::cin >> str;      
  5.     std::cerr << str << std::endl;      
  6.     ::MessageBox(hwndDlg, str.c_str(), "Information"      
  7.         , MB_ICONINFORMATION);      
  8.     return TRUE;     

调用static function Need().来申请一个对象,申请对象的同时也申请了一个控制台。并重定向了stream。

在用户点击quit按钮的时候,操作很简单,关闭对话框,然后释放控制台和关闭流。通过学习南老师的这篇笔记又了解了另一种输入输出重定向。但却偏 离了南老师的愿意,南老师的这个例子是教我们一种GUI程序的调试方法。不过我们确实可以通过它了解一下输入输出重定向。。谢谢南老师。继续关注南老师的 笔记。

下面我们接着看输入输出重定向:

先看一个简单的输入重定向的例子:

Code:
  1. #include <cstdio>    
  2.   
  3. #include <iostream>    
  4.   
  5. using namespace std;   
  6.   
  7. int main()    
  8.   
  9. {    
  10.   
  11. #ifdef ONLINE_JUDGE   
  12.   
  13. #else   
  14.   
  15.     freopen("in.txt","r",stdin);   
  16.   
  17. #endif   
  18.   
  19.     int a,b;   
  20.   
  21.     while(cin>>a>>b)   
  22.   
  23.         cout<<a+b<<endl;   
  24.   
  25.     return 0;   
  26.   
  27. }   

这个例子简单的进行了输入重定向,cin >> a >> b;不再是有键盘输入a,b的值,而是程序自动从文件里进行读取。这里我们还可以了解另外一个知识:宏。

#ifdef ONLINE_JUDGE

#else

#endif

宏的这种使用方法对于调试也是很有用的。即若是我们定义了ONLINE_JUDGE.就不进行输入输出重定向。a,b的值将由我们由键盘给出。否则将从文件中读取a,b的值。我们想改变方式只需简简单单的一个#define ONLINE_JUDGE就OK啦。。呵呵。据说做软件的时候也经常用到这种方法。

willor 注:
我自己修改后的文件:
.h头文件
EmbeddedConsole.h
#pragma once

struct EmbeddedConsole 

    public:     
        static void Need() 
        { 
           
            if (!_instance) 
            { 
                _instance = new EmbeddedConsole; 
            } 
           
        } 
         
        static void Unneed() 
        { 
            delete _instance; 
            _instance = 0; 
        } 
         
    private: 
        EmbeddedConsole() 
        { 
            AllocConsole(); 
             
            SetConsoleTitle("Console in GUI Windows..."); 
             
            freopen("conin$", "r+t", stdin); 
            freopen("conout$", "w+t", stdout); 
            freopen("conout$", "w+t", stderr);  
        } 
         
        ~EmbeddedConsole() 
        { 
            fclose(stderr); 
            fclose(stdout); 
            fclose(stdin); 
             
            FreeConsole(); 
        } 
         
        static EmbeddedConsole* _instance;  
}; 


.cpp文件
EmbeddedConsole.cpp

#include "StdAfx.h"
#include "EmbeddedConsole.h"

EmbeddedConsole* EmbeddedConsole::_instance; 


/***********************************************************
Usage:   
There could be only one EmbeddedConsole for one program in parallel.
You could release one then enable a new one,
but can not enable more than one at one time.

below are the steps to make use this:
1.    #include "EmbeddedConsole.h"

2.    EmbeddedConsole::Need();    //enable the EmbeddedConsole

3. cout your content to screen.

4.    EmbeddedConsole::Unneed(); //release the EmbeddedConsole

*////////////////////////////////////////////////////////////

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

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多