2012-05-19 229 views
2

我正在使用一些图形引擎来处理gtk窗口(Opencv/highgui)的C和C++应用程序。这个应用程序做一些小输出到标准输出/ cout。从应用程序打开控制台

在Windows上,从桌面启动这种应用程序会自动打开一个控制台,向用户显示标准输出上写有“printf()”或“std :: cout”的内容。

在Linux上,如果我从以前打开的控制台启动它,没有问题。但是,如果我通过桌面启动它(双击),那么linux不会打开关联的控制台,并且写在stdout/cout上的数据将丢失。 似乎这是Linux(?)上的正常行为。

我想从我的应用程序自动打开一个控制台,当在Linux平台上编译。

这看起来像是一个骗局this one,重点是,它不起作用!我现在下面的代码:

#ifndef __WIN32 
    filebuf* console = new filebuf(); 
    console->open("/dev/tty", ios::out); 
    if(!console->is_open()) 
     cerr << "Can't open console" << endl; 
    else 
     cout.ios::rdbuf(console); 
#endif 

我不断收到“无法打开控制台”(CERR使用freopen函数()在一个文件重定向)。我试图更换控制台名称:

console->open("/dev/console", ios::out); 

但这并没有改变。

我在正确的方向吗?接下来我可以尝试什么?我应该尝试打开专门的终端应用程序(xterm)吗?但是,那么,我怎样才能将该控制台与我的应用“连接”?

+1

嗯..我知道在某些桌面环境(至少GNOME)中,您可以在桌面上创建启动程序(Windows中的“快捷方式”),并指定从其启动的应用程序将与关联的终端一起运行。如果你想尝试,创建一个新的启动器,然后检查它的属性 - 你会在那里找到选项。不知道这是不是你想要的。 – Jonatan

+0

@kebs如果您在图形环境(如gnome终端)下的终端中运行应用程序,您将能够看到输出到终端并打开应用程序。 – ShinTakezou

+0

@fullhack:是的,我知道,但这不是一种选择。 – kebs

回答

5

解决方案1个

非常简单的解决方案,你可能不喜欢:有运行在使用gnome-terminal -x <your_program> <your_args>终端应用程序的脚本。双击脚本将打开终端。

解决方案2

有点更复杂的解决方案中添加 '--noconsole' 参数传送给应用程序。如果参数存在,就运行你的应用程序。如果“--noconsole”不存在:

if(fork() == 0) { 
    execlp("gnome-terminal", "gnome-terminal", "-x", argv[0], "--noconsole", NULL); 
} else { 
    exit(0); 
} 

这将创建它的运行使用--noconsole arugment在gnome-terminal申请一个子进程。说得通?有点哈克,但嘿,它的作品。

解决方案3

这一个是最棘手的解决办法,但在某些方面更优雅。我们的想法是将stdout重定向到一个文件并创建一个运行于tail -f <file_name> --pid=<parent_pid>的终端。这会打印父进程的输出,并在父进程结束时终止。

#include <stdlib.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <string.h> 

// Create terminal and redirect output to it, returns 0 on success, 
// -1 otherwise. 
int make_terminal() { 
    char pidarg[256]; // the '--pid=' argument of tail 
    pid_t child;  // the pid of the child proc 
    pid_t parent;  // the pid of the parent proc 
    FILE* fp;   // file to which output is redirected 
    int fn;   // file no of fp 

    // Open file for redirection 
    fp = fopen("/tmp/asdf.log","w"); 
    fn = fileno(fp); 

    // Get pid of current process and create string with argument for tail 
    parent = getpid(); 
    sprintf(pidarg, "--pid=%d", parent); 

    // Create child process 
    child = fork(); 
    if(child == 0) { 
     // CHILD PROCESS 

     // Replace child process with a gnome-terminal running: 
     //  tail -f /tmp/asdf.log --pid=<parent_pid> 
     // This prints the lines outputed in asdf.log and exits when 
     // the parent process dies. 
     execlp("gnome-terminal", "gnome-terminal", "-x", "tail","-f","/tmp/asdf.log", pidarg, NULL); 

     // if there's an error, print out the message and exit 
     perror("execlp()"); 
     exit(-1); 
    } else { 
     // PARENT PROCESS 
     close(1);  // close stdout 
     int ok = dup2(fn, 1); // replace stdout with the file 

     if(ok != 1) { 
      perror("dup2()"); 
      return -1; 
     } 

     // Make stdout flush on newline, doesn't happen by default 
     // since stdout is actually a file at this point. 
     setvbuf(stdout, NULL, _IONBF, BUFSIZ); 
    } 

    return 0; 
} 

int main(int argc, char *argv[]) { 
    // Attempt to create terminal. 
    if(make_terminal() != 0) { 
     fprintf(stderr, "Could not create terminal!\n"); 
     return -1; 
    } 

    // Stuff is now printed to terminal, let's print a message every 
    // second for 10 seconds. 
    int i = 0; 
    while(i < 10) { 
     printf("iteration %d\n", ++ i); 
     sleep(1); 
    } 

    return 0; 
} 
+0

嘿,谢谢你这个漫长的回答,有趣的是,我会尝试一下并回复评论。 – kebs

+0

解决方案1与建议的@fulhack(为其他桌面创建一个.desktop快捷方式,适用于gnome或同等版本)没有多大区别。您的解决方案可能更便携,除了我不确定'gnome-terminal'在所有平台上都可用。解决方案2很好,我只是试了一下,所有东西都包含在应用程序中,但同样需要'gnome-terminal'。也许有一些通用终端保证可以在_all_ linux平台上使用?解决方案3将在明天进行尝试。 – kebs

+0

好的,第三个解决方案也好,实际上和sol没什么不同。 2.我倾向于选择后者,我认为xterm比gnome终端更普遍(例如在KDE系统上)。感谢您抽出时间获得真正完整的答案;-) – kebs

3

你的例子全部“打开”一个控制台 - 就是说打开一个文件。这对gui没有任何作用。如果你想这样做,你将不得不打开一个gtk窗口并将输出指向它。

+1

好吧,所以我假设你建议启动一个终端,这是我的第二个想法。但是,我怎么能“连接”这个终端到我的应用程序的标准输出? – kebs

相关问题