问题
One of the programs that I work with has two modes that it can run in: GUI (Graphical User Interface) mode or CLI (Command-Line Interface) mode. We determine which mode to use via a command line argument (i.e., if "--cli" is passed, it will use CLI mode).
The type of QApplication that is instantiated depends on which mode is used: QApplication should be used for GUI mode, and QCoreApplication should be used for CLI mode, because the GUI parts of Qt should not be instantiated for CLI mode (since CLI mode does not use or need them).
I can do that via code similar to the following:
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();
Since I am already using Qt, it makes sense to use QCommandLineParser to parse my arguments. After parsing the arguments, I want to analyze them to determine whether we should run in GUI mode or CLI mode. However, it has been becoming increasingly difficult to do so.
The first problem I noticed was the following on Linux (this did not happen in older versions of Qt5, but it does happen in the newer versions):
$ ./myQtApplication --help
QCoreApplication::arguments: Please instantiate the QApplication object first
Segmentation fault (core dumped)
Okay: so I can no longer run the --help
command without already having a QApplication object instantiated. I temporarily fixed this by manually parsing the arguments to see whether or not --help
is an argument. If it is, go ahead and instantiated the QCoreApplication, parse the arguments, and then exit.
But then I started getting a cryptic error on Mac OS X. When I would run the executable on OS X directly, it would run without any issues. But if I tried to double-click on the .app
file or type in the terminal $ open myQtApplication.app
, I would get this cryptic error:
LSOpenURLsWithRole() failed with error -10810 for the file ./myQtApplication.app
Since it is a rather cryptic error, it took me a long time to figure out that this error was being caused by the QCommandLineParser being used before having a QApplication object instantiated.
To fix this, I am now doing the following:
- Manually parse the arguments at the beginning of the
main()
function to determine whether or not--cli
was passed. - Instantiate a QApplication object based on the results of #1.
- Run QCommandLineParser to process the rest of the arguments.
This is not a very clean way to do this because I now have two argument parsers: one to determine if --cli
was passed, and the rest for the other arguments.
Is there a much better, or "proper", way to do this?
I guess the main question is: can I use QCommandLineParser to determine whether to instantiate a QCoreApplication object or a QApplication object?
回答1:
Of course you can use the parser - as long as QCoreApplication
already present. If the --cli
option is absent, you will switch to a QApplication
. Recall that you have full control over the lifetime of the application object.
This works under Qt 4.8 and 5.11 on both Windows and OS X:
// 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();
}
来源:https://stackoverflow.com/questions/52649458/can-i-use-qcommandlineparser-to-determine-gui-mode-or-cli-mode