我使用的程序之一具有两种可以运行的模式:GUI(图形用户界面)模式或CLI(命令行界面)模式。我们通过命令行参数确定要使用的模式(即,如果传递了“ --cli”,它将使用CLI模式)。
实例化的QApplication的类型取决于所使用的模式:QApplication应该用于GUI模式,而QCoreApplication应该用于CLI模式,因为Qt的GUI部分不应该用于CLI模式(因为CLI模式不使用或不需要它们。
我可以通过类似于以下代码的方式做到这一点:
std::unique_ptr<QCoreApplication> app =
(cliMode) ? std::make_unique<QCoreApplication>(argc, argv)
: std::make_unique<QApplication>(argc, argv);
// Do some other stuff...
return app->exec();
由于我已经在使用Qt,因此使用QCommandLineParser解析参数是有意义的。解析完参数后,我想对它们进行分析,以确定我们应该以GUI模式还是CLI模式运行。但是,这样做变得越来越困难。
我注意到的第一个问题是在Linux上的以下问题(在较旧版本的Qt5中没有发生,但在较新版本中确实发生了)
$ ./myQtApplication --help
QCoreApplication::arguments: Please instantiate the QApplication object first
Segmentation fault (core dumped)
好的:所以如果没有实例化QApplication对象,我将无法再运行--help
命令。我通过手动解析参数以查看--help
是否为参数来临时解决此问题。如果是这样,请继续实例化QCoreApplication,解析参数,然后退出。
但是随后我开始在Mac OS X上收到一个神秘的错误。当我直接在OS X上运行该可执行文件时,它可以毫无问题地运行。但是,如果我尝试双击.app
文件或在终端机$ open myQtApplication.app
中键入,则会收到此神秘错误:
LSOpenURLsWithRole() failed with error -10810 for the file ./myQtApplication.app
由于这是一个相当隐蔽的错误,我花了很长时间才弄清楚该错误是由实例化QApplication对象之前使用QCommandLineParser引起的。
要解决此问题,我现在正在执行以下操作:
main()
函数开头的参数,以确定是否传递了--cli
。这不是一种很干净的方法,因为我现在有两个参数解析器:一个用于确定是否传递了--cli
,其余的用于其他参数。
是否有更好的或“适当的”方法来做到这一点?
我猜主要问题是:我可以使用QCommandLineParser确定实例化QCoreApplication对象还是QApplication对象?
答案 0 :(得分:4)
当然,您可以使用解析器-只要已经存在QCoreApplication
。如果没有--cli
选项,则将切换到QApplication
。回想一下,您可以完全控制应用程序对象的生存期。
这在Windows和OS X的Qt 4.8和5.11下均有效:
// https://github.com/KubaO/stackoverflown/tree/master/questions/app-cli-gui-switch-52649458
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QtWidgets>
#endif
struct Options {
bool cli;
};
static Options parseOptionsQt4() {
Options opts = {};
for (auto arg : QCoreApplication::arguments().mid(1)) {
if (arg == "--cli")
opts.cli = true;
else
qFatal("Unknown option %s", arg.toLocal8Bit().constData());
}
return opts;
}
static Options parseOptions() {
if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0)) return parseOptionsQt4();
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
Options opts = {};
QCommandLineParser parser;
QCommandLineOption cliOption("cli", "Start in command line mode.");
parser.addOption(cliOption);
parser.process(*qApp);
opts.cli = parser.isSet(cliOption);
return opts;
#endif
}
int main(int argc, char *argv[]) {
QScopedPointer<QCoreApplication> app(new QCoreApplication(argc, argv));
auto options = parseOptions();
if (options.cli) {
qDebug() << "cli";
} else {
qDebug() << "gui";
app.reset();
app.reset(new QApplication(argc, argv));
}
if (qobject_cast<QApplication *>(qApp))
QMessageBox::information(nullptr, "Hello", "Hello, World!");
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
return app->exec();
}