2013-12-13 60 views
3

我有一个基于Qt GUI的完整应用程序,但现在我需要在批处理模式(控制台)中使用此应用程序。我尝试了几种方法,但没有一个按预期工作。以下是我现在有:将基于Qt GUI的应用程序转换为控制台或批处理应用程序

QApplication a(argc, argv); 
MyMainWindow *w = new MyMainWindow(); 
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); 
a.exec(); 

以下是我需要:

QApplication a(argc, argv); 

QString project_path = argv[1]; 

MyMainWindow *w = new MyMainWindow(); 
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); 

w->loadPrjFile(project_path); 
w->analyze(); 
w->exportResults(); 

a.exec(); 

所以,基本上我需要的是允许应用程序通过命令行得到project_path(不是文件对话框)并执行用户通常使用GUI所遵循的方法。问题在于这些方法应该阻止,即应该等待前一个结束。

应用程序本身应该阻塞,在shell中执行时,应该等待整个执行完成才能退出。由于它应该作为控制台应用程序工作,所以该界面也应该隐藏起来。

如果你知道如何做到这一点,我真的很感激这样做的代码示例。

+0

简单的方法是使用Qt的各种'waitForXxxx'方法(主要是'QIODevice'子类,记住,他们是在GUI应用馊主意),而不是以往任何时候都调用'EXEC()'。 'QFile'也可以用在像stdin,stdout和stderr这样的FILE指针文件上。或者只是使用标准的C++流等,并根据需要转换为'QString'等。 – hyde

+0

为了澄清我以前的评论,以防万一:这是'waitForXxx'方法,这在GUI应用程序中是一个坏主意,因为它们会阻塞事件循环并导致实际使用中的麻烦,并且可能需要很多工作才能稍后进行修复。 – hyde

回答

4

您遇到的问题是您正在尝试开发控制台应用程序,但仍使用Gui窗口小部件,例如QMainWindow。您需要首先将Gui类与主项目中的所有其他类分开。

我建议你创建一个从QObject派生的类,它处理你需要的处理; loadPrjFile,分析并导出结果。

然后在您的MainWindow中为GUI项目使用这个新类的实例,并直接将其用于控制​​台项目。

class Worker : public QObject 
{ 
    Q_OBJECT 

    public: 
     void loadPrjFile(const QString& path); 
     void analyze(); 
     void exportResults(); 
}; 


class MyMainWindow : QMainWindow 
{ 
    private: 
     Worker m_pWorkerObject; 
}; 

如果你正在开发一个不需要GUI的控制台项目,你可以使用QCoreApplication,而不是QApplication的。

请注意,调用app.exec()会启动Qt处理消息,因此只有在需要消息循环才能处理事件时(这可能不是控制台应用程序的情况),具体取决于应用程序的功能。

+0

你的答案看起来很专业,但我正在寻找一个更直接的解决方案,我也不知道如何做到这一点,因为接口和逻辑在我手边的代码中是混乱的。 –

1

要从具有GUI的应用程序的命令行中读取参数,可以在代码中的任何位置使用全局指针qApp。例如,如果希望能够将GUI应用程序与文件类型相关联,这是特别有用的,因为文件名将由操作系统用于应用程序(至少它在Windows中工作)。

您可以在this thread中看到我给出的同一个问题的详细答案,以及相应文档的链接,由于某些原因,这些链接不在最新版本的Qt中。

第二部分并不那么容易。您可以在调用a.exec()之前使用w-> setVisible(false);否则,您可以使用w-> setVisible(false)隐藏你的主窗口,但是据我所知,你将会修改每一个有对话的方法,如果检测到对命令行参数作出反应,并且禁用对话,或者在没有相关的情况下使用正常对话参数被检测到。

如果您只需要调用主窗口中与用户没有交互的方法,那么它就不会有那么多的工作,并且您可能不会调用一个。exec(当且仅当你的代码中没有任何部分在批处理模式下使用信号和槽),这实际上启动了GUI的主循环,在这种情况下不需要。

像这样的东西可能会奏效:

QApplication a(argc, argv); 
MyMainWindow *w = new MyMainWindow(); 


if(1 < qApp->arguments().count()) //Command line arguments detected 
{ 
    QString project_path = qApp->arguments().at(1); 

    w->loadPrjFile(project_path); 
    w->analyze(); 
    w->exportResults(); 


} 
else //No command line arguments detected 
{ 
    a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); 
    a.exec(); 
} 

如果,另一方面,功能loadPrjFile(),分析();和exportResults()是插槽,而不是像你的代码所建议的那样,是你主窗口的方法,它们不会被顺序调用,你将别无选择,只能使用信号和插槽,这样每个函数都可以通知下一个函数完成它的工作,因此将不得不打电话给a.exec

+0

我没有接受你的回答,因为它在我看来是不完整的。虽然这很有用。主要的问题是您在回答中没有提到的顺序执行和无法取出的a.exec()函数,至少在我的具体情况中。 –

+0

谢谢。我很高兴我能帮上忙。由于你在sample.code中调用你的函数的方式,我认为它们是公共方法而不是插槽,并且没有你的主窗口的标题,我不能透露其他信息。公共方法被顺序调用,除非他们使用事件,否则不需要a.exec,如@Merlin先前所述,但我相应地编辑了我的答案以使其更清晰。关于qApp的使用,您可以将完全相同的行移动到需要文件路径的插槽,无需将其作为参数传递并保留整洁的主函数 –

+0

我还将w-> hide()更改为w- > setVisible(false),如你的文章所建议的。 –

1

这个答案显示了我在一段时间后想出的解决方案。我会把它放在这里,因为它对别人有用。代码看起来是这样的:

QApplication a(argc, argv); 

QString project_file = argv[1]; 

MyMainWindow *w = new MyMainWindow(); 
w->setVisible(false); 
a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); 
w->setBatchMode(true); 

QObject::connect(w,SIGNAL(loadingFinished()),w,SLOT(analyze())); 
QObject::connect(w,SIGNAL(analysisFinished()),w,SLOT(exportResults())); 
QObject::connect(w,SIGNAL(exportingFinished()),w,SLOT(close())); 

w->loadPrjFile(project_file); 

a.exec(); 

主要考虑是:

  • W->调用setVisible(假)来隐藏主窗口也如所指出@Dissident企鹅。

  • w-> setBatchMode(true)用于设置一个类变量,用于抑制整个代码中的所有其他对话框,同样也是@Dissident企鹅指出的。里面的功能我刚刚结束的对话框代码与if语句,如:

    如果{//显示对话框}

  • 会议序贯执行的要求是不容易(_batchMode!)。我必须创建两个信号:loadingFinished()analyzeFinished()exportingFinished()。然后我发出它们在的结尾处加载.prj文件(),analyze()exportResults()函数分别。这样我保证他们是按顺序执行的,而另一个则是等待执行。这是需要的,因为插槽在Qt中是异步执行的。

  • 最后,我不能拿出方法a.exec(),因为如果我这样做,该程序无法正常运行。我认为这是因为我仍在使用GUI,它只是隐藏起来。这样,仍然需要a.exec()

相关问题