Help us understand the problem. What is going on with this article?

QCoreApplication系を見直してみよう

新型コロナの影響でいろいろと大変な一年だったかと思いますが、皆様おかわりないでしょうか。
@task_jp さんの初日のエントリーに気が付くまですっかり忘れていましたが、今年もアドベントカレンダーの季節がやってまいりました。

昨日は、Q_GADGET を活用したデータモデルの実装について ということで、QObjectを支えるメタオブジェクトを軽量に扱えるようにするための仕組みについて解説されています。

本日は、突発的に記事を書くことにしたので、色々悩んで、QCoreApplicationとその継承クラスについて触れてみようかと思います。突発的にざっくり調べて書きつけるので、誤りが含まれる可能性が多分にあります。特にイベント周りは色々複雑なので、後日別記事にまとめつつ、こちらの記事も修正する予定です。

QCoreApplication系クラスとは何か

Qtのドキュメントでは、UIのないアプリケーションにイベントループを提供するクラスと簡潔に説明されています。Qtを利用される多くの方は、GUIで利用されているでしょうから、古くからのWidgetを使われる方はQApplication、最近のQMLを利用される方はQGuiApplicationの方が見慣れていらっしゃるかと思います。

alt

Qtを使い始めると、とりあえずおまじないのように書くようになってしまうこのクラスは、Qtアプリケーションの初期化・終了処理とアプリケーション全体に対する設定、OS側からのイベントも含め処理するメインイベントループの生成を担っています。

QCoreApplication

GUIアプリケーションを主に開発される方には耳慣れないかもしれませんが、QApplicationやQGuiApplicationの親クラスで、GUIを伴わないCUI向けのアプリケーション用の初期化・イベントループ生成クラスになります。QCoreApplicationが提供する機能は以下の通りです。

アプリケーション引数の保持

  QCoreApplication(int &argc, char **argv);
  static QStringList arguments();

UNIX系ではコンストラクタに渡された引数を、Windows系ではargc,argvを改変されていなければ、GetCommandLine() APIで取得したアプリケーション実行時引数をQStringListとして保持しており、arguments()関数で取得できます。

arguments().at(0)はプログラム名が、引数があれば、それ以降に引数が保持されています。

なお、あくまでシンプルなリストが作られるだけですので、複雑なオプションのパースやヘルプの生成をしたいのであれば、QCommandLineParser クラスを使う必要があります。

アプリケーションパスの取得

  static QString applicationDirPath();
  static QString applicationFilePath();

実行ファイル名までhあ含まないディレクトリパスと、実行ファイル名までを含むファイルパスを取得できます。なお、Linuxではパスの取得に/procを参照し、失敗した場合は、argv[0]とアプリケーションのカレントディレクトリから生成するので、カレントディレクトリを変えた場合など、正確な値が取れないケースがあるようです。

ライブラリパスの取得・操作

  static QStringList libraryPaths();
  static void        setLibraryPaths(const QStringList &paths);
  static void        addLibraryPath(const QString &path);
  static void        removeLibraryPath(const QString &path);

QLibraryを使ったライブラリ読み込みに利用されるパスを取得、設定、追加、削除を行います。

アプリケーション情報の設定・取得

  static QString applicationName();
  static QString applicationVersion();
  static QString organizationDomain();
  static QString organizationName();

  static void setApplicationName(const QString &application);
  static void setApplicationVersion(const QString &version);
  static void setOrganizationDomain(const QString &orgDomain);
  static void setOrganizationName(const QString &orgName);

QSettingsやQCommandLineParserなどで使われるアプリケーション情報の取得・設定

  • アプリケーション名(未設定時は実行ファイル名)
  • バージョン(未設定時は以下の通り)

    アーキテクチャ
    Windows(classic) VERSIONINFOリソースのPRODUCTVERSIONパラメーター
    Windows(Universal) アプリケーションパッケージマニフェストのバージョン属性
    macOS、iOS、tvOS、watchOS CFBundleVersionプロパティ
    Android AndroidManifest.xmlのandroid:versionNameプロパティ
  • 組織ドメイン

  • 組織名

なお、この値が実行中に変更された際に通知するためのシグナルが提供されています。

  void  applicationNameChanged();
  void  applicationVersionChanged();
  void  organizationDomainChanged();
  void  organizationNameChanged();

アプリケーション全体の機能制御

static void setAttribute(Qt::ApplicationAttribute attribute, bool on = true);
static bool testAttribute(Qt::ApplicationAttribute attribute);

アプリケーションの挙動を制御します。ざっくりと一覧しておきますので、詳細はドキュメントを確認してください。QGuiApplicationのインスタンスが生成される前に指定しなくてはならない属性や、デフォルトでONのものもあります。

ApplicationAttribute on=trueの場合
Qt::AA_DontShowIconsInMenus メニューへのアイコン表示を抑止する
Qt::AA_DontShowShortcutsInContextMenus コンテキストメニュー上のショートカットの表示を抑止する
Qt::AA_NativeWindows ネイティブウィンドウを使用する
Qt::AA_DontCreateNativeWidgetSiblings ネイティブウィンドウの兄弟を非ネイティブのままとする
Qt::AA_PluginApplication プラグインの作成に使用されることを指定し、不要な初期化を抑制する
Qt::AA_DontUseNativeMenuBar ネイティブメニューバーを使用しない(macOSの上部のメニューバー等)
Qt::AA_MacDontSwapCtrlAndMeta [macOS] commandキーとctrlキーの入れ替えを抑止する
Qt::AA_Use96Dpi OS指定の解像度ではなく、画面の解像度を96DPIであると想定する
Qt::AA_SynthesizeTouchForUnhandledMouseEvents アプリケーションで受け入れられないすべてのマウスイベンをタッチイベントに変換する
Qt::AA_SynthesizeMouseForUnhandledTouchEvents アプリケーションで受け入れられないすべてのタッチイベントを左ボタンのマウスイベントに変換する
Qt::AA_UseHighDpiPixmaps QIconで、高DPIのピックスマップを生成する
Qt::AA_ForceRasterWidgets トップレベルのウィジェットが純粋なラスターサーフェスを使用するようにし、非ネイティブのGLベースの子ウィジェットをサポートしない
Qt::AA_UseDesktopOpenGL OpenGL実装の動的ロードを使用するプラットフォームでデスクトップOpenGLを強制する
Qt::AA_UseOpenGLES OpenGL実装の動的ロードを使用するプラットフォームでOpenGLES2.0以降の使用を強制する
Qt::AA_UseSoftwareOpenGLQt OpenGL実装の動的ロードを使用するプラットフォームでソフトウェアベースのOpenGL実装の使用を強制する
Qt::AA_ShareOpenGLContexts QOpenGLWidgetやQQuickWidgetなどのクラスで使用されるOpenGLコンテキスト間のリソース共有を有効にし、テクスチャ等のリソース共有をする
Qt::AA_SetPalette QGuiApplicationでパレットが明示的に設定されているかどうか(test用?)
Qt::AA_EnableHighDpiScaling サポートされているプラ​​ットフォームでQtの高DPIスケーリングを有効にする
Qt::AA_DisableHighDpiScaling Qtで高DPIスケーリングを無効にする
Qt::AA_UseStyleSheetPropagationInWidgetStyles Widgetのスタイルに対するスタイルシートを継承する
Qt::AA_DontUseNativeDialogs ネイティブダイアログを使用しない
Qt::AA_SynthesizeMouseForUnhandledTabletEvents アプリケーションで受け入れられないすべてのタブレットイベントをマウスイベントに変換する
Qt::AA_CompressHighFrequencyEvents 特定の頻繁なイベントの圧縮を有効にする
Qt::AA_CompressTabletEvents タブレットデバイスからの入力イベントの圧縮を有効にする
Qt::AA_DontCheckOpenGLContextThreadAffinity QOpenGLContext::makeCurrentで生成する際、QObjectのスレッド親和性チェックをしない
Qt::AA_DisableShaderDiskCache シェーダーのディスクキャッシュを無効にする
Qt::AA_DisableWindowContextHelpButton Qt::SheetおよびQt::Dialogで、WindowContextHelpButtonHintを無効にする
Qt::AA_DisableNativeVirtualKeyboard [Windows] ネイティブの仮想キーボードを無効にする

国際化対応

static bool installTranslator(QTranslator *translationFile);
static bool removeTranslator(QTranslator *translationFile);
static QString  translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1)

翻訳ファイルのインストール・削除を行います。このあたりの使い方は、3年前のアドベントカレンダーで、@task_jp 会長が記事にしてくださっていますので、そちらをご確認ください。

translateは、インストールされている翻訳ファイルをクエリして、sourceTextの翻訳テキストを返します。

イベントループの開始と終了

static int exec();
QT_SIGNAL aboutToQuit();

メインイベントループを開始し、exitが呼び出されるまでイベント待機・処理します。終了時の返却値は、exitで指定されたreturnCodeになりますが、プラットフォームによってはexec()から返らずにそのままアプリケーションが終了されるケースがあるので注意が必要です。

イベントループから抜ける際には、aboutToQuit()シグナルを発行します。aboutToQuit()によりアプリケーションの最後に簡単な処理を実施できます。なお、イベントループは終了しようとしているので、ユーザーとの対話などはできないことに注意が必要です。

static void exit(int returnCode = 0);
Q_SIGNAL void quit();

exitは、メインイベントループをreturnCodeで終了するよう指示します。メインイベントループが実行されていない場合は何もしません。

quit()スロットは、exit(0)します。イベントループが実行される前のexitは何もしないため、exitの直接呼出しより、quitスロットへQueuedConnectionしたシグナルを発行する方が安全です。

  static bool   isQuitLockEnabled();
  static void   setQuitLockEnabled(bool enabled);

また、Qtには、イベントループが不要になった際終了させるためのQEventLoopLockerクラスがありますが、メインイベントループもquitlockするか否かの制御が用意されています。デフォルトでは有効になっています。

イベントディスパッチャー

  static QAbstractEventDispatcher *eventDispatcher();
  static void   setEventDispatcher(QAbstractEventDispatcher *eventDispatcher);

Event Dispatcherは、ウィンドウシステムおよびその他のソースからイベントを受信・処理、QCoreApplicationに配信します。
通常プラットフォームごとに適切なディスパッチャーが用意されていますが、QCoreApplicationのインスタンス生成前であれば、独自のディスパッチャーを設定することも可能です。

ネイティブイベントフィルタ

  void installNativeEventFilter(QAbstractNativeEventFilter * filterObj);
  void removeNativeEventFilter(QAbstractNativeEventFilter * filterObject);

OS等のプラットフォーム側のイベントをフィルタするネイティブイベントフィルタのインストール・削除ができます。
プラットフォーム依存となるため移植性に注意が必要ですが、QPAプラットフォームプラグイン(Windowsの場合はディスパッチャー)レベルでネイティブのイベントをフィルタできます。

イベント通知処理関数

virtual bool notify(QObject *receiver, QEvent *event);

イベントループでイベント配信時に呼び出される関数で、オーバーライドすると任意のスレッドのレシーバーに送信される任意のイベントの通知処理を置き換え可能になります。

イベント操作

static void processEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
static void processEvents(QEventLoop::ProcessEventsFlags flags, int ms);

保留中イベントの処理。ms指定された時間か、すべてのイベントが処理できるまで、呼び出し元のスレッドのイベントを処理します。

bool    sendEvent(QObject *receiver, QEvent *event);

receiver当てのeventをnotify関数を経由して即時送信します。eventのインスタンスは削除しません。

static void postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority);
static void removePostedEvents(QObject *receiver, int eventType = 0);
static void sendPostedEvents(QObject *receiver = nullptr, int event_type = 0);

receiver当てのeventを配信用のキューに入れ保留します。このキューは、メインイベントループの処理によりnotify経由で対象に送信した後、eventのインスタンスを破棄(delete)します。また、remove/sendは、receiver向けのキューにあるイベントを削除、即時送信します。

setuid対策(セキュリティ)

  static bool isSetuidAllowed();
  static void setSetuidAllowed(bool allow);

Qt 5.3以降、デフォルトはsetuidを禁止してUIDとRUIDが異なる状態ではアプリケーションの起動を失敗するようになっています。歴史的な経緯でsetuidしなくてはならないアプリケーションでは、明示的に許可する必要があります。

その他

  static QCoreApplication *instance();

インスタンスの取得

  static qint64 applicationPid()

プロセスIDの取得

  static bool startingUp()
  static bool closingDown()

アプリケーションが起動処理中(application object生成前)か、終了処理中か(application objectのdestroyが開始しているか)の問い合わせ。

QGuiApplication

QGuiApplicationは、QCoreApplicationを継承したGUI向けのクラスで、Qt Widgetを使わないもの向けの初期化・イベントループ生成クラスになります。

イベントループ生成のexec()関数はオーバーライドされています。その他、QCoreApplicationの機能に加え、GUI向けに以下の機能が追加されています。

プロパティの取得、設定

  static QString applicationDisplayName();
  static setApplicationDisplayName(const QString& displayName);
  Q_SIGNAL void applicationDisplayNameChanged();

ユーザーに表示される名前の取得、設定ができます。ウィンドウタイトルなのでユーザーに表示されます。
設定されていない場合は、applicationNameが利用されます。シグナルは変更通知となるます。

  static QString desktopFileName();
  static void setDesktopFileName(const QString& name);

freedesktopのデスクトップエントリのベース名の取得、設定ができます。

  static Qt::LayoutDirection layoutDirection();
  static void setLayoutDirection(Qt::LayoutDirection direction);
  static bool isLeftToRight();
  static bool isRightToLeft();
  Q_SIGNAL void layoutDirectionChanged(Qt::LayoutDirection direction);

ウィジェットのレイアウト方向を設定、取得します。

  static QString platformName();

基盤となるプラットフォームプラグインの名前の取得

  static QScreen *  primaryScreen()
  Q_SIGNAL void primaryScreenChanged(QScreen *screen);

アプリケーションのプライマリ(またはデフォルト)画面の取得,変更通知

  static bool quitOnLastWindowClosed();
  static void setQuitOnLastWindowClosed(bool quit);
  Q_SIGNAL void lastWindowClosed();

最終ウィンドウを閉じた際にQuitするかのフラグを取得、設定。
最後とウィンドウを閉じた際は、lastWindowClosed()シグナルを発行する。

  static QIcon  windowIcon();
  static void   setWindowIcon(const QIcon &icon);

ウィンドウアイコンの取得、設定

スタイルの取得、アプリケーションデフォルトフォント・パレットの取得設定

  static QStyleHints *  styleHints();
  static QFont  font();
  static QPalette palette();
  static void setFont(const QFont& font);
  static void setPalette(const QPalette& pal);
  Q_SIGNAL fontChanged(const QFont &font);
  Q_SIGNAL fontDatabaseChanged();
  Q_SIGNAL paletteChanged(const QPalette &palette);

オーバーライドカーソルの取得、設定、変更、リセット

  static QCursor *  overrideCursor();
  static void   setOverrideCursor(const QCursor &cursor);
  static void   changeOverrideCursor(const QCursor &cursor);
  static void   restoreOverrideCursor();

アプリケーションオーバーライドカーソルは、たとえば、操作中に時間がかかる場合のような、アプリケーションが特別な状態にあることをユーザーに示すことを目的としています。

高DPIスケールファクター丸めポリシーの取得、設定

  static Qt::HighDpiScaleFactorRoundingPolicy   highDpiScaleFactorRoundingPolicy();
  static void   setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy);

フォールバックセッション管理の有効・無効の確認、設定、セッション情報の取得

  static bool   isFallbackSessionManagementEnabled();
  static void   setFallbackSessionManagementEnabled(bool enabled);
  Q_SIGNAL void saveStateRequest(QSessionManager &manager);
  bool isSavingSession() const;
  bool isSessionRestored() const;
  QString sessionId() const;
  QString sessionKey() const;

セッションマネージャがユーザーとの対話を許可している場合に、セッションマネージャーが特定の条件に応じてトップレベルウィンドウを閉じることを防ぎ、セッション管理を明示的に実装するために何もしない機能を有効とするかどうかを確認、設定する。

システム標準色、フォントを使用するかの設定、確認

  static bool   desktopSettingsAware();
  static void   setDesktopSettingsAware(bool on);

Window Systemとの同期

  static void   sync();

アプリケーション状態の取得

  static Qt::ApplicationState   applicationState();
  Q_SIGNAL void applicationStateChanged(Qt::ApplicationState state); 

アプリケーションの現在の状態,変更通知シグナル

ApplicationState 概要
Qt::ApplicationSuspended 一時停止状態 
Qt::ApplicationHidden 非表示、バックグラウンド実行
Qt::ApplicationInactive 非前面に表示中
Qt::ApplicationActive 前面に表示中

 ウィンドウの取得

  static QWindowList    allWindows();
  static QWindowList    topLevelWindows();
  static QWindow *  focusWindow();
  static QWindow *  modalWindow();
  static QWindow *  topLevelAt(const QPoint &pos);

スクリーンの取得

  static QScreen *  screenAt(const QPoint &point);
  static QList<QScreen *>   screens();
  Q_SIGNAL void screenAdded(QScreen * screen);
  Q_SIGNAL void screenRemoved(QScreen * screen);

マウス、キーボード修飾キーの取得

  static Qt::MouseButtons   mouseButtons();
  static Qt::KeyboardModifiers  keyboardModifiers();
  static Qt::KeyboardModifiers  queryKeyboardModifiers();

なお、keyboardModifiers()がイベントに応じて更新された値を返すのに対し、queryKeyboardModifiers()は呼び出し時に入力デバイスに保持されている実際のキーを返します。

platform plugin関数ポインタの取得

  static QFunctionPointer   platformFunction(const QByteArray &function);

その他、アプリケーション情報、機能へのアクセス

  qreal devicePixelRatio()const;
  static QClipboard *   clipboard();
  static QObject *  focusObject();
  static QInputMethod * inputMethod();
  static QPlatformNativeInterface * platformNativeInterface();

QApplication

QApplicationは、QGuiApplicationを継承したGUI向けのクラスで、Qt Widgetを使うアプリケーション向けの初期化・イベントループ生成クラスになります。QGuiApplicationに類似したAPIのQWidget版が追加されています。

プロパティの取得、設定

  Q_SLOT bool   autoSipEnabled() const;
  Q_SLOT void   setAutoSipEnabled(const bool enabled);

自動SIP(ソフトウェア入力パネル)の可視性を設定、取得

  static int    cursorFlashTime();
  static void   setCursorFlashTime(int);

テキストカーソル点滅時間(ミリ秒単位)の取得、設定

  static int    doubleClickInterval();
  static void   setDoubleClickInterval(int);

ダブルクリックと2回の連続したマウスクリックを区別する時間制限(ミリ秒)の取得、設定

  static int    keyboardInputInterval();
  static void   setKeyboardInputInterval(int);

キーの押下と2つの連続したキーの押下を区別する制限時間(ミリ秒単位)の取得、設定

  static int    startDragDistance();
  static void   setStartDragDistance(int l);

ユーザーがボタンを押したままカーソルを移動した際、ドラッグと判断される移動距離。defaultは10ピクセル

  static int    startDragTime();
  static void   setStartDragTime(int ms);

ドラッグアンドドロップ操作を開始する前にマウスボタンを押し続ける必要がある時間(ミリ秒単位)の取得、設定

  static int    wheelScrollLines();
  static void   setWheelScrollLines(int);

マウスホイールが回転したときにウィジェットをスクロールするための行数の取得、設定

  QString   styleSheet() const;
  Q_SLOT void   setStyleSheet(const QString &sheet);

アプリケーションスタイルシートの取得、設定

スタイルの取得、設定アプリケーションデフォルトフォント・パレットの取得設定

  static QStyle *   style();
  static void   setStyle(QStyle *style);
  static QStyle *   setStyle(const QString &style);
  static QFont  font(const QWidget *widget);
  static QFont  font(const char *className);
  static QFontMetrics   fontMetrics();
  static void   setFont(const QFont &font, const char *className = nullptr);
  static QPalette   palette(const QWidget *widget);
  static QPalette   palette(const char *className);
  static void   setPalette(const QPalette &palette, const char *className = nullptr);

条件に合うウィジェットの取得、設定、変更通知、操作

  static void   setActiveWindow(QWidget *active);
  static QWidget *  activeModalWidget();
  static QWidget *  activePopupWidget();
  static QWidget *  activeWindow();
  static QWidgetList    allWidgets();
  static QWidget *  focusWidget();
  static QWidget *  topLevelAt(const QPoint &point);
  static QWidget *  topLevelAt(int x, int y)
  static QWidgetList    topLevelWidgets();
  static QWidget *  widgetAt(const QPoint &point);
  static QWidget *  widgetAt(int x, int y);
  Q_SIGNAL  focusChangedQWidget * oldQWidget * now;
  Q_SLOT closeAllWindows();
  Q_SLOT aboutQt();

aboutQt()は、アプリケーションで使用されているQtのバージョン番号が含まれるダイアログを表示する。

その他の機能

  static Qt::NavigationMode navigationMode();
  static void   setNavigationMode(Qt::NavigationMode mode);

フォーカスナビゲーション種類の取得、設定

  static bool   isEffectEnabled(Qt::UIEffect effect);
  static void   setEffectEnabled(Qt::UIEffect effect, bool enable = true);

UIエフェクト効果の有効・無効の検査、設定

  static void   alert(QWidget *widget, int msec = 0);

ウィジェットに対する警告ウィンドウ表示

  static void   beep();

Beep音を鳴らす

QCoreApplicationに関わるマクロ

qApp

qobject_cast QCoreApplication::instance() 相当

qGuiApp

qobject_cast QCoreApplication::instance() 相当

Q_COREAPP_STARTUP_FUNCTION(QtStartUpFunction ptr)

QCoreApplicationのコンストラクタ最後に呼び出される関数ポインタの設定

関連非メンバ関数

  void  qAddPostRoutine(QtCleanUpFunction ptr)
  void  qRemovePostRoutine(QtCleanUpFunction ptr)

QCoreApplicationのデストラクタからコールされる関数ポインタの追加、削除

QCoreApplication系のちょっとしたTips

TBD

まとめ

なんとなくQCoreApplication一族の機能と役割を見直すことができたでしょうか。割とおまじないチックに呼んだあと、あまり使う機会のないクラスではありますが、意外といろいろなAPIが実装されていることがわかるかと思います。ふっと何かでこれどうすれば情報取れるのだっけとか、どこで設定するのだっけみたいなものもあるので、一度ドキュメントを流し読みしておくのも良いものですよ。

ちょっと時間が無くてTBDな項目やTODOのまま残している個所がありますが、0時前までには登録したいので、とりあえず本日はここまでで登録させていただきます。ごめんなさい。

例年のように、相も変わらず適当な書きなぐり記事でしたが、何か少しでも皆さんのお役に立てれば幸いです。

明日3日目は、まだ誰も登録者がいません。今年はコロナの影響で勉強会も中止したままだいぶ時間が過ぎてしまいましたから、気が付いていない方もいらっしゃるのかもしれませんね。何か軽くかけることを思いついた方は、ぜひご登録ください。

hermit4
文系出身のなんちゃってプログラマです。フリーランスで細々と生きてます。 主にC++でお仕事して生きてますが、Lispとwhitespace見たいな目で追うのがつらい言語以外はたいてい好きです。
http://hermit4.info
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away