Могу ли я использовать QCommandLineParser для определения режима GUI или режима CLI? - PullRequest
0 голосов
/ 04 октября 2018

Одна из программ, с которыми я работаю, имеет два режима, в которых она может работать: режим GUI (графический интерфейс пользователя) или режим CLI (интерфейс командной строки).Мы определяем, какой режим использовать с помощью аргумента командной строки (т. Е. Если передано «--cli», он будет использовать режим CLI).

Тип создаваемого экземпляра QApplication зависит от того, какой режим используется:QApplication должен использоваться для режима GUI, а QCoreApplication должен использоваться для режима CLI, потому что части GUI Qt не должны создаваться для режима 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 для анализа моих аргументов.После разбора аргументов я хочу проанализировать их, чтобы определить, должны ли мы работать в режиме графического интерфейса или в режиме CLI.Тем не менее, это становится все труднее сделать.

Первая проблема, которую я заметил, была следующая в Linux (это не происходило в более старых версиях Qt5, но это происходит в более новых версиях):

$ ./myQtApplication --help
QCoreApplication::arguments: Please instantiate the QApplication object first
Segmentation fault (core dumped)

Хорошо: я больше не могу запускать команду --help без создания экземпляра объекта QApplication.Я временно исправил это, вручную проанализировав аргументы, чтобы увидеть, является ли --help аргументом.Если это так, продолжайте и создайте экземпляр QCoreApplication, проанализируйте аргументы и затем закройте.

Но затем я начал получать загадочную ошибку в Mac OS X. Когда я запускал исполняемый файл непосредственно в OS X, онбудет работать без проблем.Но если бы я попытался дважды щелкнуть файл .app или ввести в терминале $ open myQtApplication.app, я получил бы такую ​​загадочную ошибку:

LSOpenURLsWithRole() failed with error -10810 for the file ./myQtApplication.app

Поскольку это довольно загадочная ошибка, мне потребовалосьДолгое время выяснялось, что эта ошибка была вызвана использованием QCommandLineParser до создания экземпляра объекта QApplication.

Чтобы исправить это, я сейчас делаю следующее:

  1. Вручную проанализируйте аргументы в начале функции main(), чтобы определить, была ли передана --cli.
  2. Создание объекта QApplication на основе результатов # 1.
  3. Запустите QCommandLineParserобработать остальные аргументы.

Это не очень чистый способ сделать это, потому что теперь у меня есть два парсера аргументов: один для определения, был ли передан --cli, а остальные длядругие аргументы.

Есть ли гораздо лучший или "правильный" способ сделать это?

Полагаю, главный вопрос: могу ли я использовать QCommandLineParser, чтобы определить, создавать ли экземпляр объекта QCoreApplication или объект QApplication?

1 Ответ

0 голосов
/ 04 октября 2018

Конечно, вы можете использовать парсер - пока QCoreApplication уже присутствует.Если опция --cli отсутствует, вы переключитесь на QApplication.Напомним, что вы имеете полный контроль над временем жизни объекта приложения.

Это работает в Qt 4.8 и 5.11 как в Windows, так и в 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();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...