Completer の例
Completer の例では、モデルによって提供されるデータに基づいて、入力ウィジェットに文字列補完機能を提供する方法を示します。
この例では、カスタム項目モデルFileSystemModel
とQCompleter オブジェクトを使用します。QCompleter は、項目モデルに基づいて補完機能を提供するクラスです。モデルのタイプ、補完モード、および大文字と小文字の区別は、コンボボックスを使って選択できます。
リソースファイル
Completer の例では、countries.txtとwords.txt を保存するためにリソースファイルが必要です。リソース・ファイルには以下のコードが含まれています:
<!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/"> <file>resources/countries.txt</file> <file>resources/wordlist.txt</file> </qresource> </RCC>
FileSystemModel クラスの定義
FileSystemModel
クラスはQFileSystemModel のサブクラスで、ローカルファイルシステムのデータモデルを提供します。
class FileSystemModel : public QFileSystemModel { public: FileSystemModel(QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; };
このクラスは、QFileSystemModel のdata()
関数がフォルダのみを返し、ドライブ・ラベルを返さないのとは異なり、data()
が表示ロールのファイル・パス全体を返せるようにするためだけに作成されているため、コンストラクタとdata()
関数しか持っていません。これについてはFileSystemModel
の実装で詳しく説明します。
FileSystemModel クラスの実装
FileSystemModel
クラスのコンストラクタは、parent をQFileSystemModel に渡すために使用されます。
FileSystemModel::FileSystemModel(QObject *parent) : QFileSystemModel(parent) { }
前述のように、data()
関数は、表示ロールのファイル・パス全体を返すように再実装されます。例えば、QFileSystemModel を使用すると、ビューに "Program Files "が表示されます。しかし、FileSystemModel
を使用すると、"C:˶Program Files" と表示されます。
QVariant FileSystemModel::data(const QModelIndex &index, int role) const { if (role == Qt::DisplayRole && index.column() == 0) { QString path = QDir::toNativeSeparators(filePath(index)); if (path.endsWith(QDir::separator())) path.chop(1); return path; } return QFileSystemModel::data(index, role); }
QCompleter が一致を検索するために使用するQt::EditRole は変更されません。
MainWindow クラスの定義
MainWindow
クラスはQMainWindow のサブクラスで、about()
、changeCase()
、changeMode()
、changeModel()
、changeMaxVisible()
の 5 つのプライベート・スロットを実装しています。
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); private slots: void about(); void changeCase(int); void changeMode(int); void changeModel(); void changeMaxVisible(int);
MainWindow
クラス内には、createMenu()
とmodelFromFile()
の2つのプライベート関数があります。また、必要なプライベート・ウィジェットとして、3つのQComboBox オブジェクト、QCheckBox 、QCompleter 、QLabel 、QLineEdit を宣言します。
private: void createMenu(); QAbstractItemModel *modelFromFile(const QString &fileName); QComboBox *caseCombo = nullptr; QComboBox *modeCombo = nullptr; QComboBox *modelCombo = nullptr; QSpinBox *maxVisibleSpinBox = nullptr; QCheckBox *wrapCheckBox = nullptr; QCompleter *completer = nullptr; QLabel *contentsLabel = nullptr; QLineEdit *lineEdit = nullptr; };
MainWindowクラスの実装
MainWindow
のコンストラクタは、親ウィジェットを持つMainWindow
を構築し、プライベート・メンバを初期化します。その後、createMenu()
関数が呼び出されます。
modelComb
、modeCombo
、caseCombo
の3つのQComboBox オブジェクトを設定します。デフォルトでは、modelCombo
はQFileSystemModel に、modeCombo
は "Filtered Popup" に、caseCombo
は "Case Insensitive" に設定されています。
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { createMenu(); QWidget *centralWidget = new QWidget; QLabel *modelLabel = new QLabel; modelLabel->setText(tr("Model")); modelCombo = new QComboBox; modelCombo->addItem(tr("QFileSystemModel")); modelCombo->addItem(tr("QFileSystemModel that shows full path")); modelCombo->addItem(tr("Country list")); modelCombo->addItem(tr("Word list")); modelCombo->setCurrentIndex(0); QLabel *modeLabel = new QLabel; modeLabel->setText(tr("Completion Mode")); modeCombo = new QComboBox; modeCombo->addItem(tr("Inline")); modeCombo->addItem(tr("Filtered Popup")); modeCombo->addItem(tr("Unfiltered Popup")); modeCombo->setCurrentIndex(1); QLabel *caseLabel = new QLabel; caseLabel->setText(tr("Case Sensitivity")); caseCombo = new QComboBox; caseCombo->addItem(tr("Case Insensitive")); caseCombo->addItem(tr("Case Sensitive")); caseCombo->setCurrentIndex(0);
maxVisibleSpinBox
が作成され、コンプリーターの可視アイテムの数を決定します。
次にwrapCheckBox
が設定される。このcheckBox
は、completer
のsetWrapAround() プロパティが有効か無効かを決定します。
QLabel *maxVisibleLabel = new QLabel; maxVisibleLabel->setText(tr("Max Visible Items")); maxVisibleSpinBox = new QSpinBox; maxVisibleSpinBox->setRange(3,25); maxVisibleSpinBox->setValue(10); wrapCheckBox = new QCheckBox; wrapCheckBox->setText(tr("Wrap around completions")); wrapCheckBox->setChecked(true);
次に、contentsLabel
をインスタンス化し、そのサイズ・ポリシーをfixed に設定します。コンボ・ボックスのactivated() シグナルは、それぞれのスロットに接続されます。
contentsLabel = new QLabel; contentsLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(modelCombo, &QComboBox::activated, this, &MainWindow::changeModel); connect(modeCombo, &QComboBox::activated, this, &MainWindow::changeMode); connect(caseCombo, &QComboBox::activated, this, &MainWindow::changeCase); connect(maxVisibleSpinBox, &QSpinBox::valueChanged, this, &MainWindow::changeMaxVisible);
lineEdit
を設定し、QGridLayout を使用してすべてのウィジェットを配置します。changeModel()
関数を呼び出して、completer
を初期化します。
lineEdit = new QLineEdit; QGridLayout *layout = new QGridLayout; layout->addWidget(modelLabel, 0, 0); layout->addWidget(modelCombo, 0, 1); layout->addWidget(modeLabel, 1, 0); layout->addWidget(modeCombo, 1, 1); layout->addWidget(caseLabel, 2, 0); layout->addWidget(caseCombo, 2, 1); layout->addWidget(maxVisibleLabel, 3, 0); layout->addWidget(maxVisibleSpinBox, 3, 1); layout->addWidget(wrapCheckBox, 4, 0); layout->addWidget(contentsLabel, 5, 0, 1, 2); layout->addWidget(lineEdit, 6, 0, 1, 2); centralWidget->setLayout(layout); setCentralWidget(centralWidget); changeModel(); setWindowTitle(tr("Completer")); lineEdit->setFocus(); }
createMenu()
関数は、fileMenu
とhelpMenu
を埋めるために必要なQAction オブジェクトをインスタンス化するために使用されます。アクションのtriggered() シグナルは、それぞれのスロットに接続される。
void MainWindow::createMenu() { QAction *exitAction = new QAction(tr("Exit"), this); QAction *aboutAct = new QAction(tr("About"), this); QAction *aboutQtAct = new QAction(tr("About Qt"), this); connect(exitAction, &QAction::triggered, qApp, &QApplication::quit); connect(aboutAct, &QAction::triggered, this, &MainWindow::about); connect(aboutQtAct, &QAction::triggered, qApp, &QApplication::aboutQt); QMenu *fileMenu = menuBar()->addMenu(tr("File")); fileMenu->addAction(exitAction); QMenu *helpMenu = menuBar()->addMenu(tr("About")); helpMenu->addAction(aboutAct); helpMenu->addAction(aboutQtAct); }
modelFromFile()
関数はファイルのfileName を受け取り、その内容に応じて処理する。
まず、file
を検証し、QFile::ReadOnly モードでオープンできることを確認します。これが失敗した場合、関数は空のQStringListModel を返します。
QAbstractItemModel *MainWindow::modelFromFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly)) return new QStringListModel(completer);
次にマウスカーソルをQt::WaitCursor で上書きしてから、QStringList オブジェクトwords
をfile
の内容で埋めます。これが完了したら、マウスカーソルを復元します。
#ifndef QT_NO_CURSOR QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); #endif QStringList words; while (!file.atEnd()) { QByteArray line = file.readLine(); if (!line.isEmpty()) words << QString::fromUtf8(line.trimmed()); } #ifndef QT_NO_CURSOR QGuiApplication::restoreOverrideCursor(); #endif
前述したように、リソースファイルには、countries.txtと words.txtの2つのファイルが含まれている。読み込まれたfile
がwords.txt の場合、words
をQStringList とし、completer
を親とするQStringListModel を返します。
if (!fileName.contains(QLatin1String("countries.txt"))) return new QStringListModel(words, completer);
file
がcountries.txt の場合、words.count()
行、2 列、completer
を親とするQStandardItemModel が必要です。
QStandardItemModel *m = new QStandardItemModel(words.count(), 2, completer);
countries.txtの標準的な行は以下の通り:
ノルウェー NO
したがって、QStandardItemModel オブジェクト、m
に入力するには、国名とその記号を分割しなければならない。これが完了したら、m
を返します。
for (int i = 0; i < words.count(); ++i) { QModelIndex countryIdx = m->index(i, 0); QModelIndex symbolIdx = m->index(i, 1); QString country = words.at(i).mid(0, words[i].length() - 2).trimmed(); QString symbol = words.at(i).right(2); m->setData(countryIdx, country); m->setData(symbolIdx, symbol); } return m; }
changeMode()
関数は、index
の値に応じてcompleter
のモードを設定する。
void MainWindow::changeMode(int index) { QCompleter::CompletionMode mode; if (index == 0) mode = QCompleter::InlineCompletion; else if (index == 1) mode = QCompleter::PopupCompletion; else mode = QCompleter::UnfilteredPopupCompletion; completer->setCompletionMode(mode); }
changeModel()
関数は、ユーザーが選択したモデルに基づいて使用する項目モデルを変更する。
modelCombo
のインデックスに基づいてアイテム・モデルを変更するために、switch
文が使用されます。case
が 0 の場合、ソートされていないQFileSystemModel が使用され、ドライブ・ラベルを除いたファイル・パスが提供されます。
void MainWindow::changeModel() { delete completer; completer = new QCompleter(this); completer->setMaxVisibleItems(maxVisibleSpinBox->value()); switch (modelCombo->currentIndex()) { default: case 0: { // Unsorted QFileSystemModel QFileSystemModel *fsModel = new QFileSystemModel(completer); fsModel->setRootPath(QString()); completer->setModel(fsModel); contentsLabel->setText(tr("Enter file path")); } break;
completer
を親としてモデルを作成することで、モデルを新しいモデルに置き換えることができます。completer
は、新しいモデルが割り当てられた瞬間に古いモデルが削除されるようにします。
case
が 1 の場合、先に定義したDirModel
を使用し、ファイルのフルパスを作成します。
case 1: { // FileSystemModel that shows full paths FileSystemModel *fsModel = new FileSystemModel(completer); completer->setModel(fsModel); fsModel->setRootPath(QString()); contentsLabel->setText(tr("Enter file path")); } break;
case
が 2 の場合、国名を完全なものにしようとする。これにはQTreeView オブジェクト、treeView
が必要である。国名はcountries.txtから抽出され、補完を表示するポップアップをtreeView
に設定します。
case 2: { // Country List completer->setModel(modelFromFile(":/resources/countries.txt")); QTreeView *treeView = new QTreeView; completer->setPopup(treeView); treeView->setRootIsDecorated(false); treeView->header()->hide(); treeView->header()->setStretchLastSection(false); treeView->header()->setSectionResizeMode(0, QHeaderView::Stretch); treeView->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents); contentsLabel->setText(tr("Enter name of your country")); } break;
下のスクリーンショットは、国名リストモデルの Completer を示している。
case
が 3 の場合、単語の補完を試みます。これは、words.txt から抽出したデータを含むQStringListModel を使用して行われます。モデルはcase insensitively でソートされます。
下のスクリーンショットは、単語リスト・モデルを使った Completer を示しています。
モデル・タイプが選択されると、changeMode()
関数とchangeCase()
関数が呼び出され、それに応じてラップ・オプションが設定されます。wrapCheckBox
のclicked() 信号は、completer
のsetWrapAround() スロットに接続されている。
case 3: { // Word list completer->setModel(modelFromFile(":/resources/wordlist.txt")); completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel); contentsLabel->setText(tr("Enter a word")); } break; } changeMode(modeCombo->currentIndex()); changeCase(caseCombo->currentIndex()); completer->setWrapAround(wrapCheckBox->isChecked()); lineEdit->setCompleter(completer); connect(wrapCheckBox, &QAbstractButton::clicked, completer, &QCompleter::setWrapAround); }
changeMaxVisible()
は、completer内の可視アイテムの最大数を更新する。
void MainWindow::changeMaxVisible(int max) { completer->setMaxVisibleItems(max); }
about()
関数は、この例に関する簡単な説明を提供する。
void MainWindow::about() { QMessageBox::about(this, tr("About"), tr("This example demonstrates the " "different features of the QCompleter class.")); }
main()
関数
main()
関数は、QApplication とMainWindow
をインスタンス化し、show() 関数を呼び出します。
int main(int argc, char *argv[]) { QApplication app(argc, argv); MainWindow window; window.show(); return app.exec(); }
©2024 The Qt Company Ltd. 本書に含まれるドキュメントの著作権は、それぞれの所有者に帰属します。 ここで提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。