「QMLの基礎 - ダイアログ」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
 
(同じ利用者による、間の11版が非表示)
1行目: 1行目:
== 概要 ==
== 概要 ==
 
QMLにおけるダイアログは、ユーザとのインタラクションを促進する重要なUIコンポーネントである。<br>
<br><br>
Qt5 / Qt6において、ダイアログは主にポップアップウィンドウとして機能し、情報の表示や入力の受け取りに使用される。<br>
 
== ディレクトリ選択ダイアログ ==
==== FolderDialog ====
<code>FolderDialog</code>は、ネイティブプラットフォームのディレクトリ選択ダイアログのためのQML APIを提供する。<br>
<br>
<br>
<u>※注意</u><br>
Qt5 / Qt6のQMLでは、ダイアログの基本的な概念は類似しているが、いくつかの違いがある。<br>
<u><code>Qt.labs Platform</code>モジュールのアイテムは、将来のバージョンでの互換性が保証されていない。</u><br>
* Qt 5
*: 主に、Dialogコンポーネントが使用されていた。
* Qt 6
*: 新しいDialog APIが導入されており、より柔軟性が増した。
<br>
<br>
ディレクトリ選択ダイアログを表示するには、<code>FolderDialog</code>の定義やプロパティを記述して、<code>open</code>メソッドを呼び出す。<br><br>
ダイアログの特徴として、モーダル (親ウインドウの操作をブロック)、または、モードレス (親ウインドウの操作を許可) で表示できる点が挙げられる。<br>
また、カスタマイズ可能なコンテンツエリア、タイトルバー、ボタンエリア等の要素を持つ。<br>
<br>
<br>
<code>currentFolder</code>プロパティは、ダイアログ内で現在選択されているディレクトリのURLが設定される。<br>
Qt6では、DialogコンポーネントやPopupコンポーネント等の基本的なコンポーネントに加えて、<br>
<code>folder</code>プロパティは、ダイアログの選択ボタンにより選択された後にのみ設定される。<br>
MessageDialogコンポーネント、FileDialogコンポーネント、ColorDialogコンポーネント等の特殊化されたダイアログも提供されている。<br>
これらは特定の用途に最適化されており、開発者の作業を簡素化することができる。<br>
<br>
<br>
<code>FolderDialog</code>の使用手順を以下に示す。<br>
ダイアログの表示 / 非表示は、<code>open</code>メソッドや<code>close</code>メソッドを使用して制御する。<br>
<code>Qt Labs Platform</code>モジュールは、ネイティブな実装が利用できないプラットフォーム上のフォールバックとしてQt Widgetsを使用している。<br>
したがって、<code>Qt Labs Platform</code>モジュールのアイテムを使用する場合、<br>
<code>QtWidgets</code>ライブラリをリンクして、<code>QGuiApplication</code>クラスの代わりに<code>QApplication</code>クラスを使用する必要がある。<br>
<br>
<br>
まず、<code>QtWidgets</code>ライブラリをリンクするには、.proファイルに以下の設定を追記する。<br>
また、<code>accepted</code>シグナルや<code>rejected</code>シグナルを使用して、ユーザの操作結果を処理することができる。<br>
# .proファイル
QT += 〜 widgets
<br>
<br>
<code>main</code>関数において、<code>QGuiApplication</code>クラスの代わりに<code>QApplication</code>クラスのインスタンスを生成する。<br>
QMLでのダイアログの実装は、アプリケーションのデザインや要件に応じて柔軟に調整可能である。<br>
<syntaxhighlight lang="c++">
単純な確認メッセージから複雑なフォームまで、様々な用途に対応できる強力なツールとなっている。<br>
// main.cppファイル
<br><br>
 
#include <QApplication>
== ディレクトリ選択ダイアログ ==
//#include <QGUIApplication>
==== FolderDialogコンポーネント ====
#include <QQmlApplicationEngine>
まず、必要なモジュールをインポートして、<code>FolderDialog</code>コンポーネントを使用する。<br>
// ...略
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    //QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app,
                    [url](QObject *obj, const QUrl &objUrl)
                    {
                        if (!obj && url == objUrl)
                        {
                          QCoreApplication::exit(-1);
                        }
                    }, Qt::QueuedConnection);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}
</syntaxhighlight>
<br>
<br>
<code>FileDialog</code><code>StandardPaths</code>も参照すること。<br>
<code>FolderDialog</code>コンポーネントのプロパティを以下に示す。
<br>
* <code>title</code>プロパティ
<code>FileDialog</code>のプロパティを以下に示す。<br>
*: ダイアログのタイトルを設定する。
* acceptLabel
*: <br>
*: 値 : string型 (既定値 : 空の文字列)
* <code>currentFolder</code>プロパティ
*: ダイアログで現在選択されているフォルダを設定する。
*: folderプロパティとは異なり、currentFolderプロパティはダイアログ内でディレクトリを選択している間、最終的な選択がなされる前でも更新される。
*: <br>
*: <code>StandardPaths</code>を使用することにとより、プラットフォーム間で一貫した方法で標準的なディレクトリを参照できる。
*: 例: <code>currentFolder: "file:///home/user/Documents"</code>
*: <br>
*: <u>Qt 6以降で使用可能である。</u>
*: <br>
*: 以下の例では、StandardPathsを使用してドキュメントディレクトリを指定している。
*: <br>
*: <br>
*: ダイアログの選択ボタンに表示されるラベルテキストを設定する。
* <code>folder</code>プロパティ (Qt 6以降では非推奨)
*: 空の文字列を設定すると、プラットフォームの標準のラベルテキスト(Open)が使用される。
*: 最終的に選択されたディレクトリのURLが設定される。
*: currentFolderプロパティとは異なり、folderプロパティはダイアログでディレクトリを選択している間は更新されず、最終的な選択が行われた後にのみ更新される。
*: つまり、[Open]ボタンを押下した場合、または、acceptedシグナルを処理して最終選択をした場合のみである。
*: <br>
*: <br>
*: rejectLabelプロパティも参照すること。
*: <u>Qt 5では、このプロパティを使用する。</u>
*: <u>Qt 6以降では、folderプロパティは非推奨となっており、代わりにcurrentFolderプロパティを使用することが推奨される。</u>
*: <br>
*: <br>
* rejectLabel
* <code>options</code>プロパティ
*: 値 : string (既定値 : 空の文字列)
*: ダイアログの外観に影響を与える様々なオプションを設定する。
*: 既定値では、全てのオプションが無効になっている。
*: <br>
*: <br>
*: ダイアログのキャンセルボタンに表示されるラベルテキストを設定する。
*: このプロパティは、ダイアログを表示する前に設定する必要がある。
*: 空の文字列を設定すると、プラットフォームの標準のラベルテキスト(Cancel)が使用される。
*: ダイアログが表示されている間に設定を変更した場合、ダイアログに影響を与えることは保証されていない。
*: <br>
*: <br>
*: acceptLabelプロパティも参照すること。
*: ディレクトリのみの表示、および、シンボリックリンクを解決しない場合
*: 例: <code>options: FolderDialog.ShowDirsOnly | FolderDialog.DontResolveSymlinks</code>
*: <br>
*: <br>
* currentFolder
* <code>acceptLabel</code>プロパティ
*: : url型 (既定値 : なし)
*: ダイアログの選択ボタンに表示されるラベルテキストを設定する。
*: 空の文字列を設定すると、プラットフォームの標準のラベルテキスト (: Open) が使用される。
*: <br>
*: <br>
*: ダイアログで現在選択されているフォルダを設定する。
* <code>rejectLabel</code>プロパティ
*: folderプロパティとは異なり、currentFolderプロパティは、ダイアログ内でディレクトリを選択している間、最終的な選択がなされる前でも更新される。
*: ダイアログのキャンセルボタンに表示されるラベルテキストを設定する。
*: 空の文字列を設定すると、プラットフォームの標準のラベルテキスト (例: Cancel) が使用される。
*: <br>
*: <br>
*: folderプロパティも参照すること。
* <code>visible</code>プロパティ
*: ダイアログの表示 / 非表示を制御する。
*: 例: <code>visible: false</code>
*: <br>
*: <br>
* folder
* <code>modality</code>プロパティ
*: : url型 (既定値 : なし)
*: ダイアログのモーダル性を設定する。
*: 例: <code>modality: Qt.WindowModal</code>
*: <br>
*: <br>
*: 最終的に選択されたディレクトリのURLが設定される。
* <code>selectedFolder</code>プロパティ (Qt 6以降)
*: currentFolderプロパティとは異なり、folderプロパティはダイアログでディレクトリを選択している間は更新されず、最終的な選択が行われた後にのみ更新される。
*: 選択されたディレクトリのURLを保持する。 (単一ディレクトリ選択時)
*: つまり、Openボタンを押下した場合、または、acceptedシグナルを処理して最終選択をした場合のみである。
*: <br>
*: <br>
*: currentFolderプロパティおよびacceptedメソッドも参照すること。
* <code>selectedFolders</code>プロパティ (Qt 6.5以降)
*: 選択されたディレクトリのURL配列 (複数ディレクトリ選択時)
*: <br>
*: <br>
* options
*: Qt 6.5以降では、<code>fileMode</code>プロパティを使用することにより、複数選択を可能にすることができる。
*: 値 : enumlation型 (既定値 : なし)
*: <br>
*: <br>
*: ダイアログの外観に影響を与える様々なオプションを設定する。
* <code>fileMode</code>プロパティ
*: 既定値では、全てのオプションが無効になっている。
*: FolderDialogの動作モードを制御する。
*: optionsプロパティは、ダイアログを表示する前に設定する必要がある。
*: このプロパティは、FolderDialog.FileMode型の列挙値を取る。
*: ダイアログが表示されている間に設定を変更した場合、ダイアログに影響を与えることは保証されていない。
*: <br>
*: <br>
*: 使用可能なoptionsプロパティの値を、以下に示す。
*: 例: 複数選択モードを有効化する場合
*: <code>fileMode = FolderDialog.SelectMultipleFolders</code>
<br>
下表に、<code>fileMode</code>プロパティで指定できるFolderDialog.FileModeの列挙値を示す。<br>
<center>
<center>
{| class="wikitable" | style="background-color:#fefefe;"
{| class="wikitable" | style="background-color:#fefefe;"
|+ FolderDialog.FileModeの列挙値
|-
|-
! style="background-color:#66CCFF;" | 定数
! style="background-color:#66CCFF;" |
! style="background-color:#66CCFF;" | 説明
! style="background-color:#66CCFF;" | 説明
|-
| FolderDialog.SelectExistingFolder (デフォルト) || 既存の単一のフォルダを選択するために使用する。<br><code>selectedFolder</code>プロパティを使用して選択されたフォルダを取得する。
|-
| FolderDialog.SelectMultipleFolders || 複数の既存フォルダを選択するために使用する。<br><code>selectedFolders</code>プロパティを使用して選択されたフォルダの配列を取得する。
|-
| FolderDialog.SelectNewFolder || 新しいフォルダを作成して選択するために使用する。<br>既存のフォルダを選択することもできるが、新しいフォルダを作成するオプションも提供される。<br>選択されたフォルダ (新規または既存) は、selectedFolderプロパティで取得できる。
|-
| FolderDialog.SelectAnyFolder || 既存のフォルダを選択する、または、新しいフォルダを作成して選択する。<br>SelectNewFolderモードと似ているが、新しいフォルダの作成がより強調される。<br>選択されたフォルダは、<code>selectedFolder</code>プロパティで取得できる。
|-
| colspan="2" | <u>※注意</u><br><u>複数選択モードは、大量のディレクトリが選択された場合にパフォーマンスに影響を与える可能性がある。</u><br><u>そのため、必要に応じて、選択数の制限を設けることを検討する。</u><br><u>また、fileModeプロパティの動作は、使用しているOSのネイティブファイルダイアログの機能に依存する場合がある。</u><br><u>全てのOSで同じ動作を期待できない可能性があることに注意する。</u>
|}
</center>
<br>
下表に、<code>options</code>プロパティで指定できるFolderDialog.Optionsの列挙値を示す。<br>
<center>
{| class="wikitable" | style="background-color:#fefefe;"
|+ FolderDialog.Optionsの列挙値
|-
! style="background-color:#66CCFF;" | 値
! style="background-color:#66CCFF;" | 説明
|-
|-
| FolderDialog.ShowDirsOnly || ディレクトリのみを表示する。<br>既定値では、フォルダとディレクトリの両方を表示する。
| FolderDialog.ShowDirsOnly || ディレクトリのみを表示する。<br>既定値では、フォルダとディレクトリの両方を表示する。
119行目: 128行目:
</center>
</center>
<br>
<br>
== ファイル選択ダイアログ ==
<code>FolderDialog</code>コンポーネントのシグナルハンドラ (スロット) を以下に示す。<br>
==== QWidgetのファイル選択ダイアログ ====
* <code>onAccepted</code>ハンドラ
*: ディレクトリが選択された場合の処理を定義する。
*: <br>
* <code>onRejected</code>ハンドラ
*: キャンセルされた場合の処理を定義する。
*: <br>
* <code>onFolderChanged</code>ハンドラ
*: 選択されたディレクトリが変更された場合の処理を定義する。
<br>
<syntaxhighlight lang="qml">
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs
// ...略
FolderDialog {
    id: folderDialog
    title: "フォルダを選択してください"
    currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0]
    options: FolderDialog.ShowDirsOnly | FolderDialog.DontResolveSymlinks
    acceptLabel: "選択"
    rejectLabel: "キャンセル"
    modality: Qt.WindowModal
    onAccepted: {
      console.log("選択されたフォルダ: " + folderDialog.selectedFolder)
      selectedFolderText.text = "選択されたフォルダ: " + folderDialog.selectedFolder
    }
    onRejected: {
      console.log("フォルダ選択がキャンセルされました")
    }
    onFolderChanged: {
      console.log("現在のフォルダが変更されました: " + folderDialog.currentFolder)
    }
    onVisibleChanged: {
      if (visible) {
          console.log("フォルダダイアログが開かれました")
      }
      else {
          console.log("フォルダダイアログが閉じられました")
      }
    }
}
Column {
    spacing: 20
    anchors.centerIn: parent
    // ダイアログを表示するためのトリガ (例: ボタン)
    Button {
      text: "フォルダを選択"
      onClicked: folderDialog.open()
    }
    Text {
      id: selectedFolderText
      text: "選択されたフォルダ: なし"
    }
}
Component.onCompleted: {
    // ディレクトリ選択ダイアログの初期設定およびカスタマイズをここで行うこともできる
    folderDialog.currentFolder = StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
}
</syntaxhighlight>
<br>
 
==== QWidgetのディレクトリ選択ダイアログ ====
QMLからQWidgetのファイル選択ダイアログを使用することもできる。<br>
QMLからQWidgetのファイル選択ダイアログを使用することもできる。<br>
<br>
<br>
129行目: 210行目:
<br>
<br>
* QGuiApplication
* QGuiApplication
*: ウインドウやGUI (OpenGLやQtQuick等のウィジェットに関連しないもの) の処理に関連するものである。
*: グラフィカルアプリケーション向けの基本クラスである。
*: QMLやOpenGL等のGUIを使用するが、ウィジェットを使用しないアプリケーションに適している。
* QApplication
* QApplication
*: ウィジェットの処理に関連する機能であり、QGuiApplicationを拡張するものである。
*: QGuiApplicationを継承し、ウィジェット機能を追加したクラスである。
*: QWidgetベースのアプリケーションやQWidgetを使用するコンポーネント (QFileDialog等) を含むアプリケーションに必要である。
<br>
* Qtプロジェクトファイル (.pro)
<syntaxhighlight lang="make">
# Qtプロジェクトファイル (.pro)
QT += widgets
</syntaxhighlight>
<br>
* CMakeLists.txtファイル
<syntaxhighlight lang="cmake">
# CMakeLists.txtファイル
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
target_link_libraries(<ターゲット名> PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
)
</syntaxhighlight>
<br>
<code>main</code>関数において、<code>QGuiApplication</code>クラスの代わりに<code>QApplication</code>クラスのインスタンスを生成する。<br>
<syntaxhighlight lang="c++">
// FolderSelectDialog.hファイル
#ifndef FOLDERDIALOG_H
#define FOLDERDIALOG_H
#include <QFileDialog>
#include <QQuickWindow>
#include <QObject>
class FolderSelectDialog : public QObject
{
    Q_OBJECT
public:
    explicit FolderDialog(QObject *parent = nullptr) : QObject(parent)
    {};
    Q_INVOKABLE QString getExistingDirectory()
    {
      QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
      QString dir = QFileDialog::getExistingDirectory(window, tr("フォルダを選択"),
                                                      "/home",
                                                      QFileDialog::ShowDirsOnly
                                                      | QFileDialog::DontResolveSymlinks);
      return dir;
    }
};
#endif // FOLDERDIALOG_H
</syntaxhighlight>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // main.cppファイル
  // main.cppファイル
137行目: 273行目:
  #include <QApplication>
  #include <QApplication>
  #include <QQmlApplicationEngine>
  #include <QQmlApplicationEngine>
#include <QQmlContext>
#include "FolderSelectDialog.h"
   
   
  int main(int argc, char *argv[])
  int main(int argc, char *argv[])
  {
  {
     set_qt_environment();
     QApplication app(argc, argv);
    QQmlApplicationEngine engine;
   
    FolderSelectDialog folderDialog;
    engine.rootContext()->setContextProperty("folderDialog", &folderDialog);
   
   
     QGuiApplication app(argc, argv);
     engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
   
   
     QQmlApplicationEngine engine;
     return app.exec();
     const QUrl url(u"qrc:/qt/qml/Main/main.qml"_qs);
}
     QObject::connect(
</syntaxhighlight>
       &engine,
<br>
       &QQmlApplicationEngine::objectCreated,
<syntaxhighlight lang="qml">
       &app,
import QtQuick
       [url](QObject *obj, const QUrl &objUrl) {
import QtQuick.Window
          if (!obj && url == objUrl)
import QtQuick.Controls
            QCoreApplication::exit(-1);
       },
ApplicationWindow {
       Qt::QueuedConnection);
     width: 640
    height: 480
    visible: true
    title: qsTr("Folder Selection Example")
    Column {
      spacing: 20
      anchors.centerIn: parent
      Button {
          text: "フォルダを選択"
          onClicked: {
            var selectedFolder = folderDialog.getExistingDirectory();
            if (selectedFolder) {
                selectedFolderText.text = "選択されたフォルダ: " + selectedFolder;
            }
          }
      }
      Text {
          id: selectedFolderText
          text: "選択されたフォルダ: なし"
          width: parent.width
          wrapMode: Text.WordWrap
      }
    }
}
</syntaxhighlight>
<br>
 
== ファイル選択ダイアログ ==
==== FileDialogコンポーネント ====
まず、必要なモジュールをインポートして、<code>FileDialog</code>コンポーネントを使用して、ファイル選択ダイアログを作成する。<br>
これは、一般的に、アプリケーションのメインウィンドウや特定のコンポーネント内で記述する。<br>
<br>
<code>FileDialog</code>コンポーネントのプロパティを以下に示す。<br>
* <code>title</code>プロパティ
*: ダイアログのタイトルを設定する。
* <code>nameFilters</code>プロパティ
*: 表示するファイルタイプを制限することができる。
* <code>selectedFiles</code>プロパティ
*: 選択されたファイルのパスが配列として格納される。
*: 一般的に、単一ファイル選択の場合は、<u>selectedFiles[0]</u>を使用する。
* <code>fileMode</code>プロパティ
*: ファイル選択モードを指定する。
*: 単一ファイル選択または複数ファイル選択等を指定することができる。
*: <br>
*: 指定できる値を以下に示す。
** <code>FileDialog.OpenFile</code>
**: 単一ファイルを選択する。 (デフォルト)
** <code>FileDialog.OpenFiles</code>
**: 複数ファイルを選択する。
** <code>FileDialog.SaveFile</code>
**: ファイルを保存する。
* <code>options</code>プロパティ
*: ダイアログの動作オプションを設定する。
*: 指定できる値を以下に示す。
** <code>FileDialog.ReadOnly</code>
**: 読み取り専用モード
** <code>FileDialog.DontResolveSymlinks</code>
**: シンボリックリンクを解決しない。
* <code>currentFolder</code>プロパティ
*: 初期表示するディレクトリを指定する。
* <code>selectedFile</code>プロパティ
*: 選択されたファイルのURLを保持する。 (単一ファイル選択時)
* <code>selectedFiles</code>プロパティ
*: 選択されたファイルのURL配列 (複数ファイル選択時)
* <code>acceptLabel</code>プロパティ
*: [開く]ボタンおよび[保存]ボタンのラベルをカスタマイズする。
* <code>rejectLabel</code>プロパティ
*: [キャンセル]ボタンのラベルをカスタマイズする。
<br>
<code>FileDialog</code>コンポーネントのシグナルハンドラ (スロット) を以下に示す。<br>
* <code>onAccepted</code>ハンドラ
*: ファイルが選択された場合の処理を定義する。
* <code>onRejected</code>ハンドラ
*: ダイアログがキャンセルされた場合の処理を定義する。
* <code>selectionChanged</code>ハンドラ
*: ファイル選択が変更された時に発行される。
<br>
ファイル選択ダイアログを表示する場合は、<code>open</code>メソッドを実行してダイアログを表示する。<br>
<br>
<syntaxhighlight lang="qml">
import QtQuick
import QtQuick.Controls
import QtQuick.Dialogs
// ...略
FileDialog {
    id: fileDialog
    title: "ファイルを選択してください"
    nameFilters: ["テキストファイル (*.txt)", "Image files (*.jpg *.png)", "すべてのファイル (*)"]
    fileMode: FileDialog.OpenFile
     options: FileDialog.ReadOnly
    // ファイルを選択した場合
    onAccepted: {
        console.log("選択されたファイル:", fileDialog.selectedFiles)
        selectedFileText.text = "選択されたファイル: " + fileDialog.selectedFiles[0]
    }
    // ファイル選択が変更された場合
    onSelectionChanged: {
       console.log("現在選択中: ", fileDialog.currentFile)
    }
    // キャンセルした場合
    onRejected: {
       console.log("ファイル選択がキャンセルされました")
    }
}
 
Column {
    anchors.centerIn: parent
    spacing: 20
    // ダイアログを表示するためのトリガ (例: ボタン)
    Button {
      text: "ファイルを開く"
      onClicked: fileDialog.open()
    }
    Text {
       id: selectedFileText
       text: "ファイルが選択されていません"
    }
}
</syntaxhighlight>
<br>
<u>※注意</u><br>
<u>Qt 6以降では、<code>QtQuick.Dialogs</code>モジュールを使用する。</u><br>
<u>Qt 5では、<code>Qt.labs.platform</code>モジュールを使用する。</u><br>
<br>
<u>ファイル選択ダイアログの動作は、使用しているプラットフォーム (Windows、MacOS、Linux) により異なる場合がある。</u><br>
<br>
 
==== QWidgetのファイル選択ダイアログ ====
QMLからQWidgetのファイル選択ダイアログを使用することもできる。<br>
<br>
ただし、純粋なQMLアプリケーションではなくなることに注意する。<br>
<br>
QWidgetを使用するには、<code>QGuiApplication</code>から<code>QApplication</code>に変更する必要がある。<br>
つまり、QWidgetインスタンスの作成に必要な機能を提供する<code>QApplication</code>を使用する。<br>
<br>
* QGuiApplication
*: グラフィカルアプリケーション向けの基本クラスである。
*: QMLやOpenGL等のGUIを使用するが、ウィジェットを使用しないアプリケーションに適している。
* QApplication
*: QGuiApplicationを継承し、ウィジェット機能を追加したクラスである。
*: QWidgetベースのアプリケーションやQWidgetを使用するコンポーネント (QFileDialog等) を含むアプリケーションに必要である。
<br>
* Qtプロジェクトファイル (.pro)
<syntaxhighlight lang="make">
# Qtプロジェクトファイル (.pro)
QT += widgets
</syntaxhighlight>
<br>
* CMakeLists.txtファイル
<syntaxhighlight lang="cmake">
# CMakeLists.txtファイル
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
target_link_libraries(<ターゲット名> PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
)
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// FileSelectDialog.hファイル
#ifndef FILESELECTDIALOG_H
#define FILESELECTDIALOG_H
#include <QFileDialog>
#include <QQuickWindow>
#include <QObject>
class FileSelectDialog : public QObject
{
    Q_OBJECT
private:
    QString lastUsedDirectory;
public:
    explicit FileSelectDialog(QObject *parent = nullptr) : QObject(parent), lastUsedDirectory(QDir::homePath())
    {}
    Q_INVOKABLE QString getOpenFileName(const QString &filter = QString())
    {
      QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
      QString fileName = QFileDialog::getOpenFileName(window, tr("ファイルを開く"), lastUsedDirectory, filter);
      if (!fileName.isEmpty()) {
          lastUsedDirectory = QFileInfo(fileName).path();
      }
      return fileName;
    }
    Q_INVOKABLE QStringList getOpenFileNames(const QString &filter = QString())
    {
      QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
      QStringList fileNames = QFileDialog::getOpenFileNames(window, tr("複数のファイルを開く"), lastUsedDirectory, filter);
      if (!fileNames.isEmpty()) {
          lastUsedDirectory = QFileInfo(fileNames.first()).path();
       }
       return fileNames;
    }
   
   
     engine.addImportPath(QCoreApplication::applicationDirPath() + "/qml");
     Q_INVOKABLE QString getSaveFileName(const QString &filter = QString())
    engine.addImportPath(":/");
    {
      QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
      QString fileName = QFileDialog::getSaveFileName(window, tr("ファイルを保存"), lastUsedDirectory, filter);
   
   
    engine.load(url);
      if (!fileName.isEmpty()) {
          lastUsedDirectory = QFileInfo(fileName).path();
      }
   
   
    if (engine.rootObjects().isEmpty()) {
       return fileName;
       return -1;
     }
     }
};
#endif // FILESELECTDIALOG_H
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "FileSelectDialog.h"
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
   
    FileSelectDialog fileDialog;
    engine.rootContext()->setContextProperty("fileDialog", &fileDialog);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
   
   
     return app.exec();
     return app.exec();
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br>
<u>※注意</u><br>
* パフォーマンスへの影響
*: QApplicationは、QGuiApplicationよりも多くのリソースを使用する。
*: ただし、QFileDialogを使用する場合、この追加リソースの使用は避けられない。
*: <br>
* アプリケーションの種類
*: QApplicationを使用することにより、アプリケーションはQWidgetアプリケーションになる。
*: ただし、主要なUIはQMLで構築されているため、実際の使用感はほとんど変わらない。
*: <br>
* プラットフォーム依存性
*: QApplicationを使用することにより、プラットフォーム固有のウィジェット機能にアクセスできるようになる。
*: これは、特にネイティブのファイル選択ダイアログを使用する場合に重要である。
<br><br>
<br><br>


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]

2024年9月3日 (火) 00:27時点における最新版

概要

QMLにおけるダイアログは、ユーザとのインタラクションを促進する重要なUIコンポーネントである。
Qt5 / Qt6において、ダイアログは主にポップアップウィンドウとして機能し、情報の表示や入力の受け取りに使用される。

Qt5 / Qt6のQMLでは、ダイアログの基本的な概念は類似しているが、いくつかの違いがある。

  • Qt 5
    主に、Dialogコンポーネントが使用されていた。
  • Qt 6
    新しいDialog APIが導入されており、より柔軟性が増した。


ダイアログの特徴として、モーダル (親ウインドウの操作をブロック)、または、モードレス (親ウインドウの操作を許可) で表示できる点が挙げられる。
また、カスタマイズ可能なコンテンツエリア、タイトルバー、ボタンエリア等の要素を持つ。

Qt6では、DialogコンポーネントやPopupコンポーネント等の基本的なコンポーネントに加えて、
MessageDialogコンポーネント、FileDialogコンポーネント、ColorDialogコンポーネント等の特殊化されたダイアログも提供されている。
これらは特定の用途に最適化されており、開発者の作業を簡素化することができる。

ダイアログの表示 / 非表示は、openメソッドやcloseメソッドを使用して制御する。

また、acceptedシグナルやrejectedシグナルを使用して、ユーザの操作結果を処理することができる。

QMLでのダイアログの実装は、アプリケーションのデザインや要件に応じて柔軟に調整可能である。
単純な確認メッセージから複雑なフォームまで、様々な用途に対応できる強力なツールとなっている。


ディレクトリ選択ダイアログ

FolderDialogコンポーネント

まず、必要なモジュールをインポートして、FolderDialogコンポーネントを使用する。

FolderDialogコンポーネントのプロパティを以下に示す。

  • titleプロパティ
    ダイアログのタイトルを設定する。

  • currentFolderプロパティ
    ダイアログで現在選択されているフォルダを設定する。
    folderプロパティとは異なり、currentFolderプロパティはダイアログ内でディレクトリを選択している間、最終的な選択がなされる前でも更新される。

    StandardPathsを使用することにとより、プラットフォーム間で一貫した方法で標準的なディレクトリを参照できる。
    例: currentFolder: "file:///home/user/Documents"

    Qt 6以降で使用可能である。

    以下の例では、StandardPathsを使用してドキュメントディレクトリを指定している。

  • folderプロパティ (Qt 6以降では非推奨)
    最終的に選択されたディレクトリのURLが設定される。
    currentFolderプロパティとは異なり、folderプロパティはダイアログでディレクトリを選択している間は更新されず、最終的な選択が行われた後にのみ更新される。
    つまり、[Open]ボタンを押下した場合、または、acceptedシグナルを処理して最終選択をした場合のみである。

    Qt 5では、このプロパティを使用する。
    Qt 6以降では、folderプロパティは非推奨となっており、代わりにcurrentFolderプロパティを使用することが推奨される。

  • optionsプロパティ
    ダイアログの外観に影響を与える様々なオプションを設定する。
    既定値では、全てのオプションが無効になっている。

    このプロパティは、ダイアログを表示する前に設定する必要がある。
    ダイアログが表示されている間に設定を変更した場合、ダイアログに影響を与えることは保証されていない。

    ディレクトリのみの表示、および、シンボリックリンクを解決しない場合
    例: options: FolderDialog.ShowDirsOnly | FolderDialog.DontResolveSymlinks

  • acceptLabelプロパティ
    ダイアログの選択ボタンに表示されるラベルテキストを設定する。
    空の文字列を設定すると、プラットフォームの標準のラベルテキスト (例: Open) が使用される。

  • rejectLabelプロパティ
    ダイアログのキャンセルボタンに表示されるラベルテキストを設定する。
    空の文字列を設定すると、プラットフォームの標準のラベルテキスト (例: Cancel) が使用される。

  • visibleプロパティ
    ダイアログの表示 / 非表示を制御する。
    例: visible: false

  • modalityプロパティ
    ダイアログのモーダル性を設定する。
    例: modality: Qt.WindowModal

  • selectedFolderプロパティ (Qt 6以降)
    選択されたディレクトリのURLを保持する。 (単一ディレクトリ選択時)

  • selectedFoldersプロパティ (Qt 6.5以降)
    選択されたディレクトリのURL配列 (複数ディレクトリ選択時)

    Qt 6.5以降では、fileModeプロパティを使用することにより、複数選択を可能にすることができる。

  • fileModeプロパティ
    FolderDialogの動作モードを制御する。
    このプロパティは、FolderDialog.FileMode型の列挙値を取る。

    例: 複数選択モードを有効化する場合
    fileMode = FolderDialog.SelectMultipleFolders


下表に、fileModeプロパティで指定できるFolderDialog.FileModeの列挙値を示す。

FolderDialog.FileModeの列挙値
説明
FolderDialog.SelectExistingFolder (デフォルト) 既存の単一のフォルダを選択するために使用する。
selectedFolderプロパティを使用して選択されたフォルダを取得する。
FolderDialog.SelectMultipleFolders 複数の既存フォルダを選択するために使用する。
selectedFoldersプロパティを使用して選択されたフォルダの配列を取得する。
FolderDialog.SelectNewFolder 新しいフォルダを作成して選択するために使用する。
既存のフォルダを選択することもできるが、新しいフォルダを作成するオプションも提供される。
選択されたフォルダ (新規または既存) は、selectedFolderプロパティで取得できる。
FolderDialog.SelectAnyFolder 既存のフォルダを選択する、または、新しいフォルダを作成して選択する。
SelectNewFolderモードと似ているが、新しいフォルダの作成がより強調される。
選択されたフォルダは、selectedFolderプロパティで取得できる。
※注意
複数選択モードは、大量のディレクトリが選択された場合にパフォーマンスに影響を与える可能性がある。
そのため、必要に応じて、選択数の制限を設けることを検討する。
また、fileModeプロパティの動作は、使用しているOSのネイティブファイルダイアログの機能に依存する場合がある。
全てのOSで同じ動作を期待できない可能性があることに注意する。


下表に、optionsプロパティで指定できるFolderDialog.Optionsの列挙値を示す。

FolderDialog.Optionsの列挙値
説明
FolderDialog.ShowDirsOnly ディレクトリのみを表示する。
既定値では、フォルダとディレクトリの両方を表示する。
FolderDialog.DontResolveSymlinks シンボリックリンクを解決しない。
既定値では、シンボリックリンクを解決する。
FolderDialog.ReadOnly ダイアログ内でディレクトリの作成を許可しない。


FolderDialogコンポーネントのシグナルハンドラ (スロット) を以下に示す。

  • onAcceptedハンドラ
    ディレクトリが選択された場合の処理を定義する。

  • onRejectedハンドラ
    キャンセルされた場合の処理を定義する。

  • onFolderChangedハンドラ
    選択されたディレクトリが変更された場合の処理を定義する。


 import QtCore
 import QtQuick
 import QtQuick.Controls
 import QtQuick.Dialogs
 
 // ...略
 
 FolderDialog {
    id: folderDialog
    title: "フォルダを選択してください"
    currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0]
    options: FolderDialog.ShowDirsOnly | FolderDialog.DontResolveSymlinks
    acceptLabel: "選択"
    rejectLabel: "キャンセル"
    modality: Qt.WindowModal
 
    onAccepted: {
       console.log("選択されたフォルダ: " + folderDialog.selectedFolder)
       selectedFolderText.text = "選択されたフォルダ: " + folderDialog.selectedFolder
    }
 
    onRejected: {
       console.log("フォルダ選択がキャンセルされました")
    }
 
    onFolderChanged: {
       console.log("現在のフォルダが変更されました: " + folderDialog.currentFolder)
    }
 
    onVisibleChanged: {
       if (visible) {
          console.log("フォルダダイアログが開かれました")
       }
       else {
          console.log("フォルダダイアログが閉じられました")
       }
    }
 }
 
 Column {
    spacing: 20
    anchors.centerIn: parent
 
    // ダイアログを表示するためのトリガ (例: ボタン)
    Button {
       text: "フォルダを選択"
       onClicked: folderDialog.open()
    }
 
    Text {
       id: selectedFolderText
       text: "選択されたフォルダ: なし"
    }
 }
 
 Component.onCompleted: {
    // ディレクトリ選択ダイアログの初期設定およびカスタマイズをここで行うこともできる
    folderDialog.currentFolder = StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
 }


QWidgetのディレクトリ選択ダイアログ

QMLからQWidgetのファイル選択ダイアログを使用することもできる。

ただし、純粋なQMLアプリケーションではなくなることに注意する。

QWidgetを使用するには、QGuiApplicationからQApplicationに変更する必要がある。
つまり、QWidgetインスタンスの作成に必要な機能を提供するQApplicationを使用する。

  • QGuiApplication
    グラフィカルアプリケーション向けの基本クラスである。
    QMLやOpenGL等のGUIを使用するが、ウィジェットを使用しないアプリケーションに適している。
  • QApplication
    QGuiApplicationを継承し、ウィジェット機能を追加したクラスである。
    QWidgetベースのアプリケーションやQWidgetを使用するコンポーネント (QFileDialog等) を含むアプリケーションに必要である。


  • Qtプロジェクトファイル (.pro)
 # Qtプロジェクトファイル (.pro)
 
 QT += widgets


  • CMakeLists.txtファイル
 # CMakeLists.txtファイル
 
 find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
 find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
 
 target_link_libraries(<ターゲット名> PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
 )


main関数において、QGuiApplicationクラスの代わりにQApplicationクラスのインスタンスを生成する。

 // FolderSelectDialog.hファイル
 
 #ifndef FOLDERDIALOG_H
 #define FOLDERDIALOG_H
 
 #include <QFileDialog>
 #include <QQuickWindow>
 #include <QObject>
 
 class FolderSelectDialog : public QObject
 {
    Q_OBJECT
 
 public:
    explicit FolderDialog(QObject *parent = nullptr) : QObject(parent)
    {};
 
    Q_INVOKABLE QString getExistingDirectory()
    {
       QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
       QString dir = QFileDialog::getExistingDirectory(window, tr("フォルダを選択"),
                                                       "/home",
                                                       QFileDialog::ShowDirsOnly
                                                       | QFileDialog::DontResolveSymlinks);
       return dir;
    }
 };
 
 #endif // FOLDERDIALOG_H


 // main.cppファイル
 
 #include <QApplication>
 #include <QQmlApplicationEngine>
 #include <QQmlContext>
 #include "FolderSelectDialog.h"
 
 int main(int argc, char *argv[])
 {
    QApplication app(argc, argv);
 
    QQmlApplicationEngine engine;
     
    FolderSelectDialog folderDialog;
    engine.rootContext()->setContextProperty("folderDialog", &folderDialog);
 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
 
    return app.exec();
 }


 import QtQuick
 import QtQuick.Window
 import QtQuick.Controls
 
 ApplicationWindow {
    width: 640
    height: 480
    visible: true
    title: qsTr("Folder Selection Example")
 
    Column {
       spacing: 20
       anchors.centerIn: parent
 
       Button {
          text: "フォルダを選択"
          onClicked: {
             var selectedFolder = folderDialog.getExistingDirectory();
             if (selectedFolder) {
                selectedFolderText.text = "選択されたフォルダ: " + selectedFolder;
             }
          }
       }
 
       Text {
          id: selectedFolderText
          text: "選択されたフォルダ: なし"
          width: parent.width
          wrapMode: Text.WordWrap
       }
    }
 }


ファイル選択ダイアログ

FileDialogコンポーネント

まず、必要なモジュールをインポートして、FileDialogコンポーネントを使用して、ファイル選択ダイアログを作成する。
これは、一般的に、アプリケーションのメインウィンドウや特定のコンポーネント内で記述する。

FileDialogコンポーネントのプロパティを以下に示す。

  • titleプロパティ
    ダイアログのタイトルを設定する。
  • nameFiltersプロパティ
    表示するファイルタイプを制限することができる。
  • selectedFilesプロパティ
    選択されたファイルのパスが配列として格納される。
    一般的に、単一ファイル選択の場合は、selectedFiles[0]を使用する。
  • fileModeプロパティ
    ファイル選択モードを指定する。
    単一ファイル選択または複数ファイル選択等を指定することができる。

    指定できる値を以下に示す。
    • FileDialog.OpenFile
      単一ファイルを選択する。 (デフォルト)
    • FileDialog.OpenFiles
      複数ファイルを選択する。
    • FileDialog.SaveFile
      ファイルを保存する。
  • optionsプロパティ
    ダイアログの動作オプションを設定する。
    指定できる値を以下に示す。
    • FileDialog.ReadOnly
      読み取り専用モード
    • FileDialog.DontResolveSymlinks
      シンボリックリンクを解決しない。
  • currentFolderプロパティ
    初期表示するディレクトリを指定する。
  • selectedFileプロパティ
    選択されたファイルのURLを保持する。 (単一ファイル選択時)
  • selectedFilesプロパティ
    選択されたファイルのURL配列 (複数ファイル選択時)
  • acceptLabelプロパティ
    [開く]ボタンおよび[保存]ボタンのラベルをカスタマイズする。
  • rejectLabelプロパティ
    [キャンセル]ボタンのラベルをカスタマイズする。


FileDialogコンポーネントのシグナルハンドラ (スロット) を以下に示す。

  • onAcceptedハンドラ
    ファイルが選択された場合の処理を定義する。
  • onRejectedハンドラ
    ダイアログがキャンセルされた場合の処理を定義する。
  • selectionChangedハンドラ
    ファイル選択が変更された時に発行される。


ファイル選択ダイアログを表示する場合は、openメソッドを実行してダイアログを表示する。

 import QtQuick
 import QtQuick.Controls
 import QtQuick.Dialogs
 
 // ...略
 
 FileDialog {
    id: fileDialog
    title: "ファイルを選択してください"
    nameFilters: ["テキストファイル (*.txt)", "Image files (*.jpg *.png)", "すべてのファイル (*)"]
    fileMode: FileDialog.OpenFile
    options:  FileDialog.ReadOnly
 
    // ファイルを選択した場合
    onAccepted: {
        console.log("選択されたファイル:", fileDialog.selectedFiles)
        selectedFileText.text = "選択されたファイル: " + fileDialog.selectedFiles[0]
    }
 
    // ファイル選択が変更された場合
    onSelectionChanged: {
       console.log("現在選択中: ", fileDialog.currentFile)
    }
 
    // キャンセルした場合
    onRejected: {
       console.log("ファイル選択がキャンセルされました")
    }
 }

 Column {
    anchors.centerIn: parent
    spacing: 20
 
    // ダイアログを表示するためのトリガ (例: ボタン)
    Button {
       text: "ファイルを開く"
       onClicked: fileDialog.open()
    }
 
    Text {
       id: selectedFileText
       text: "ファイルが選択されていません"
    }
 }


※注意
Qt 6以降では、QtQuick.Dialogsモジュールを使用する。
Qt 5では、Qt.labs.platformモジュールを使用する。

ファイル選択ダイアログの動作は、使用しているプラットフォーム (Windows、MacOS、Linux) により異なる場合がある。

QWidgetのファイル選択ダイアログ

QMLからQWidgetのファイル選択ダイアログを使用することもできる。

ただし、純粋なQMLアプリケーションではなくなることに注意する。

QWidgetを使用するには、QGuiApplicationからQApplicationに変更する必要がある。
つまり、QWidgetインスタンスの作成に必要な機能を提供するQApplicationを使用する。

  • QGuiApplication
    グラフィカルアプリケーション向けの基本クラスである。
    QMLやOpenGL等のGUIを使用するが、ウィジェットを使用しないアプリケーションに適している。
  • QApplication
    QGuiApplicationを継承し、ウィジェット機能を追加したクラスである。
    QWidgetベースのアプリケーションやQWidgetを使用するコンポーネント (QFileDialog等) を含むアプリケーションに必要である。


  • Qtプロジェクトファイル (.pro)
 # Qtプロジェクトファイル (.pro)
 
 QT += widgets


  • CMakeLists.txtファイル
 # CMakeLists.txtファイル
 
 find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
 find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
 
 target_link_libraries(<ターゲット名> PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
 )


 // FileSelectDialog.hファイル
 
 #ifndef FILESELECTDIALOG_H
 #define FILESELECTDIALOG_H
 
 #include <QFileDialog>
 #include <QQuickWindow>
 #include <QObject>
 
 class FileSelectDialog : public QObject
 {
    Q_OBJECT
 
 private:
    QString lastUsedDirectory;
 
 public:
    explicit FileSelectDialog(QObject *parent = nullptr) : QObject(parent), lastUsedDirectory(QDir::homePath())
    {}
 
    Q_INVOKABLE QString getOpenFileName(const QString &filter = QString())
    {
       QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
       QString fileName = QFileDialog::getOpenFileName(window, tr("ファイルを開く"), lastUsedDirectory, filter);
 
       if (!fileName.isEmpty()) {
          lastUsedDirectory = QFileInfo(fileName).path();
       }
 
       return fileName;
    }
 
    Q_INVOKABLE QStringList getOpenFileNames(const QString &filter = QString())
    {
       QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
       QStringList fileNames = QFileDialog::getOpenFileNames(window, tr("複数のファイルを開く"), lastUsedDirectory, filter);
 
       if (!fileNames.isEmpty()) {
          lastUsedDirectory = QFileInfo(fileNames.first()).path();
       }
 
       return fileNames;
    }
 
    Q_INVOKABLE QString getSaveFileName(const QString &filter = QString())
    {
       QQuickWindow *window = qobject_cast<QQuickWindow*>(parent());
       QString fileName = QFileDialog::getSaveFileName(window, tr("ファイルを保存"), lastUsedDirectory, filter);
 
       if (!fileName.isEmpty()) {
          lastUsedDirectory = QFileInfo(fileName).path();
       }
 
       return fileName;
    }
 };
 
 #endif // FILESELECTDIALOG_H


 // main.cppファイル
 
 #include <QApplication>
 #include <QQmlApplicationEngine>
 #include <QQmlContext>
 #include "FileSelectDialog.h"
 
 int main(int argc, char *argv[])
 {
    QApplication app(argc, argv);
 
    QQmlApplicationEngine engine;
     
    FileSelectDialog fileDialog;
    engine.rootContext()->setContextProperty("fileDialog", &fileDialog);
 
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
 
    return app.exec();
 }


※注意

  • パフォーマンスへの影響
    QApplicationは、QGuiApplicationよりも多くのリソースを使用する。
    ただし、QFileDialogを使用する場合、この追加リソースの使用は避けられない。

  • アプリケーションの種類
    QApplicationを使用することにより、アプリケーションはQWidgetアプリケーションになる。
    ただし、主要なUIはQMLで構築されているため、実際の使用感はほとんど変わらない。

  • プラットフォーム依存性
    QApplicationを使用することにより、プラットフォーム固有のウィジェット機能にアクセスできるようになる。
    これは、特にネイティブのファイル選択ダイアログを使用する場合に重要である。