本文介绍了我可以使用 QCommandLineParser 来确定 GUI 模式或 CLI 模式吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的其中一个程序有两种可以运行的模式:GUI(图形用户界面)模式或 CLI(命令行界面)模式.我们通过命令行参数确定使用哪种模式(即,如果传递了--cli",它将使用 CLI 模式).

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).

实例化的 QApplication 类型取决于使用哪种模式:QApplication 应该用于 GUI 模式,QCoreApplication 应该用于 CLI 模式,因为 Qt 的 GUI 部分不应该被实例化用于 CLI 模式(因为 CLI模式不使用或不需要它们).

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();

因为我已经在使用 Qt,所以使用 QCommandLineParser 来解析我的参数是有意义的.解析参数后,我想分析它们以确定我们应该在 GUI 模式还是 CLI 模式下运行.但是,这样做变得越来越困难.

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.

我注意到的第一个问题是 Linux 上的以下问题(这在旧版本的 Qt5 中没有发生,但在新版本中确实发生了):

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)

好的:所以在没有实例化 QApplication 对象的情况下,我无法再运行 --help 命令.我通过手动解析参数以查看 --help 是否为参数来临时修复此问题.如果是,继续实例化 QCoreApplication,解析参数,然后退出.

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.

但后来我开始在 Mac OS X 上遇到一个神秘的错误.当我直接在 OS X 上运行可执行文件时,它会毫无问题地运行.但是如果我试图双击 .app 文件或在终端输入 $ open myQtApplication.app,我会得到这个神秘的错误:

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

由于这是一个相当神秘的错误,我花了很长时间才弄清楚这个错误是由在实例化 QApplication 对象之前使用的 QCommandLineParser 引起的.

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. 手动解析main()函数开头的参数,判断是否传递了--cli.
  2. 根据 #1 的结果实例化 QApplication 对象.
  3. 运行 QCommandLineParser 以处理其余参数.
  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.

这不是一种非常干净的方法,因为我现在有两个参数解析器:一个用于确定是否传递了 --cli,其余用于其他参数.

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?

我想主要问题是:我可以使用 QCommandLineParser 来确定是实例化 QCoreApplication 对象还是 QApplication 对象吗?

I guess the main question is: can I use QCommandLineParser to determine whether to instantiate a QCoreApplication object or a QApplication object?

推荐答案

当然你可以使用解析器 - 只要 QCoreApplication 已经存在.如果 --cli 选项不存在,您将切换到 QApplication.回想一下,您可以完全控制应用程序对象的生命周期.

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.

这适用于 Windows 和 OS X 上的 Qt 4.8 和 5.11:

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();
}

这篇关于我可以使用 QCommandLineParser 来确定 GUI 模式或 CLI 模式吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 21:34