QMLの基礎 - ダイアログ
概要
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.SelectExistingFolder (デフォルト) | 既存の単一のフォルダを選択するために使用する。selectedFolder プロパティを使用して選択されたフォルダを取得する。
|
FolderDialog.SelectMultipleFolders | 複数の既存フォルダを選択するために使用する。selectedFolders プロパティを使用して選択されたフォルダの配列を取得する。
|
FolderDialog.SelectNewFolder | 新しいフォルダを作成して選択するために使用する。 既存のフォルダを選択することもできるが、新しいフォルダを作成するオプションも提供される。 選択されたフォルダ (新規または既存) は、selectedFolderプロパティで取得できる。 |
FolderDialog.SelectAnyFolder | 既存のフォルダを選択する、または、新しいフォルダを作成して選択する。 SelectNewFolderモードと似ているが、新しいフォルダの作成がより強調される。 選択されたフォルダは、 selectedFolder プロパティで取得できる。
|
※注意 複数選択モードは、大量のディレクトリが選択された場合にパフォーマンスに影響を与える可能性がある。 そのため、必要に応じて、選択数の制限を設けることを検討する。 また、fileModeプロパティの動作は、使用しているOSのネイティブファイルダイアログの機能に依存する場合がある。 全てのOSで同じ動作を期待できない可能性があることに注意する。 |
下表に、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を使用することにより、プラットフォーム固有のウィジェット機能にアクセスできるようになる。
- これは、特にネイティブのファイル選択ダイアログを使用する場合に重要である。