Can I use QCommandLineParser to determine GUI mode or CLI mode?

╄→尐↘猪︶ㄣ 提交于 2021-02-10 16:55:30

问题


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:

  1. Manually parse the arguments at the beginning of the main() function to determine whether or not --cli was passed.
  2. Instantiate a QApplication object based on the results of #1.
  3. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!