<?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <!-- treemodelcompleter.qdoc --> <head> <title>Qt 4.6: Tree Model Completer Example</title> <link href="classic.css" rel="stylesheet" type="text/css" /> </head> <body> <table border="0" cellpadding="0" cellspacing="0" width="100%"> <tr> <td align="left" valign="top" width="32"><a href="http://qt.nokia.com/"><img src="images/qt-logo.png" align="left" border="0" /></a></td> <td width="1"> </td><td class="postheader" valign="center"><a href="index.html"><font color="#004faf">Home</font></a> · <a href="classes.html"><font color="#004faf">All Classes</font></a> · <a href="functions.html"><font color="#004faf">All Functions</font></a> · <a href="overviews.html"><font color="#004faf">Overviews</font></a></td></tr></table><h1 class="title">Tree Model Completer Example<br /><span class="subtitle"></span> </h1> <p>Files:</p> <ul> <li><a href="tools-treemodelcompleter-mainwindow-cpp.html">tools/treemodelcompleter/mainwindow.cpp</a></li> <li><a href="tools-treemodelcompleter-mainwindow-h.html">tools/treemodelcompleter/mainwindow.h</a></li> <li><a href="tools-treemodelcompleter-treemodelcompleter-cpp.html">tools/treemodelcompleter/treemodelcompleter.cpp</a></li> <li><a href="tools-treemodelcompleter-treemodelcompleter-h.html">tools/treemodelcompleter/treemodelcompleter.h</a></li> <li><a href="tools-treemodelcompleter-main-cpp.html">tools/treemodelcompleter/main.cpp</a></li> <li><a href="tools-treemodelcompleter-treemodelcompleter-pro.html">tools/treemodelcompleter/treemodelcompleter.pro</a></li> <li><a href="tools-treemodelcompleter-treemodelcompleter-qrc.html">tools/treemodelcompleter/treemodelcompleter.qrc</a></li> </ul> <p>The Tree Model Completer example shows how to provide completion facilities for a hierarchical model, using a period as the separator to access Child, GrandChild and GrandGrandChild level objects.</p> <p align="center"><img src="images/treemodelcompleter-example.png" /></p><p>Similar to the <a href="tools-completer.html">Completer Example</a>, we provide <a href="qcombobox.html">QComboBox</a> objects to enable selection for completion mode and case sensitivity, as well as a <a href="qcheckbox.html">QCheckBox</a> for wrap completions.</p> <a name="the-resource-file"></a> <h2>The Resource File</h2> <p>The contents of the TreeModelCompleter is read from <i>treemodel.txt</i>. This file is embedded within the <i>treemodelcompleter.qrc</i> resource file, which contains the following:</p> <pre> <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/"> <file>resources/treemodel.txt</file> </qresource> </RCC></pre> <a name="treemodelcompleter-class-definition"></a> <h2>TreeModelCompleter Class Definition</h2> <p>The <tt>TreeModelCompleter</tt> is a subclass of <a href="qcompleter.html">QCompleter</a> with two constructors - one with <i>parent</i> as an argument and another with <i>parent</i> and <i>model</i> as arguments.</p> <pre> class TreeModelCompleter : public QCompleter { Q_OBJECT Q_PROPERTY(QString separator READ separator WRITE setSeparator) public: TreeModelCompleter(QObject *parent = 0); TreeModelCompleter(QAbstractItemModel *model, QObject *parent = 0); QString separator() const; public slots: void setSeparator(const QString &separator); protected: QStringList splitPath(const QString &path) const; QString pathFromIndex(const QModelIndex &index) const; private: QString sep; };</pre> <p>The class reimplements the protected functions <a href="qcompleter.html#splitPath">splitPath()</a> and <a href="qcompleter.html#pathFromIndex">pathFromIndex()</a> to suit a tree model. For more information on customizing <a href="qcompleter.html">QCompleter</a> to suit tree models, refer to <a href="qcompleter.html#handling-tree-models">Handling Tree Models</a>.</p> <p><tt>TreeModelCompleter</tt> also has a separator property which is declared using the <a href="qobject.html#Q_PROPERTY">Q_PROPERTY</a>() macro. The separator has READ and WRITE attributes and the corresponding functions <tt>separator()</tt> and <tt>setSeparator()</tt>. For more information on <a href="qobject.html#Q_PROPERTY">Q_PROPERTY</a>(), refer to <a href="properties.html">Qt's Property System</a>.</p> <a name="treemodelcompleter-class-implementation"></a> <h2>TreeModelCompleter Class Implementation</h2> <p>The first constructor constructs a <tt>TreeModelCompleter</tt> object with a parent while the second constructor constructs an object with a parent and a <a href="qabstractitemmodel.html">QAbstractItemModel</a>, <i>model</i>.</p> <pre> TreeModelCompleter::TreeModelCompleter(QObject *parent) : QCompleter(parent) { } TreeModelCompleter::TreeModelCompleter(QAbstractItemModel *model, QObject *parent) : QCompleter(model, parent) { }</pre> <p>The <tt>separator()</tt> function is a getter function that returns the separator string.</p> <pre> QString TreeModelCompleter::separator() const { return sep; }</pre> <p>As mentioned earlier, the <tt>splitPath()</tt> function is reimplemented because the default implementation is more suited to <a href="qdirmodel.html">QDirModel</a> or list models. In order for <a href="qcompleter.html">QCompleter</a> to split the path into a list of strings that are matched at each level, we split it using <a href="qstring.html#split">QString::split</a>() with <tt>sep</tt> as its separator.</p> <pre> QStringList TreeModelCompleter::splitPath(const QString &path) const { if (sep.isNull()) { return QCompleter::splitPath(path); } return path.split(sep); }</pre> <p>The <tt>pathFromIndex()</tt> function returns data for the completionRole() for a tree model. This function is reimplemented as its default implementation is more suitable for list models. If there is no separator, we use <a href="qcompleter.html">QCompleter</a>'s default implementation, otherwise we use the <a href="qlist.html#prepend">prepend()</a> function to navigate upwards and accumulate the data. The function then returns a <a href="qstringlist.html">QStringList</a>, <tt>dataList</tt>, using a separator to join objects of different levels.</p> <pre> QString TreeModelCompleter::pathFromIndex(const QModelIndex &index) const { if (sep.isNull()) { return QCompleter::pathFromIndex(index); } <span class="comment">// navigate up and accumulate data</span> QStringList dataList; for (QModelIndex i = index; i.isValid(); i = i.parent()) { dataList.prepend(model()->data(i, completionRole()).toString()); } return dataList.join(sep); }</pre> <a name="mainwindow-class-definition"></a> <h2>MainWindow Class Definition</h2> <p>The <tt>MainWindow</tt> class is a subclass of <a href="qmainwindow.html">QMainWindow</a> and implements five custom slots: <tt>about()</tt>, <tt>changeCase()</tt>, <tt>changeMode()</tt>, <tt>highlight()</tt>, and <tt>updateContentsLabel()</tt>.</p> <pre> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); private slots: void about(); void changeCase(int); void changeMode(int); void highlight(const QModelIndex&); void updateContentsLabel(const QString&);</pre> <p>In addition, the class has two private functions, <tt>createMenu()</tt> and <tt>modelFromFile()</tt>, as well as private instances of <a href="qtreeview.html">QTreeView</a>, <a href="qcombobox.html">QComboBox</a>, <a href="qlabel.html">QLabel</a>, <tt>TreeModelCompleter</tt> and <a href="qlineedit.html">QLineEdit</a>.</p> <pre> private: void createMenu(); QAbstractItemModel *modelFromFile(const QString& fileName); QTreeView *treeView; QComboBox *caseCombo; QComboBox *modeCombo; QLabel *contentsLabel; TreeModelCompleter *completer; QLineEdit *lineEdit; };</pre> <a name="mainwindow-class-implementation"></a> <h2>MainWindow Class Implementation</h2> <p>The <tt>MainWindow</tt>'s constructor creates a <tt>MainWindow</tt> object with a parent and initializes the <tt>completer</tt> and <tt>lineEdit</tt>. The <tt>createMenu()</tt> function is invoked to set up the "File" menu and "Help" menu. The <tt>completer</tt>'s model is set to the <a href="qabstractitemmodel.html">QAbstractItemModel</a> obtained from <tt>modelFromFile()</tt>, and the <a href="qcompleter.html#highlighted">highlighted()</a> signal is connected to <tt>MainWindow</tt>'s <tt>highlight()</tt> slot.</p> <pre> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), completer(0), lineEdit(0) { createMenu(); completer = new TreeModelCompleter(this); completer->setModel(modelFromFile(":/resources/treemodel.txt")); completer->setSeparator(QLatin1String(".")); QObject::connect(completer, SIGNAL(highlighted(QModelIndex)), this, SLOT(highlight(QModelIndex))); QWidget *centralWidget = new QWidget; QLabel *modelLabel = new QLabel; modelLabel->setText(tr("Tree Model<br>(Double click items to edit)")); 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);</pre> <p>The <a href="qlabel.html">QLabel</a> objects <tt>modelLabel</tt>, <tt>modeLabel</tt> and <tt>caseLabel</tt> are instantiated. Also, the <a href="qcombobox.html">QComboBox</a> objects, <tt>modeCombo</tt> and <tt>caseCombo</tt>, are instantiated and populated. By default, the <tt>completer</tt>'s mode is "Filtered Popup" and the case is insensitive.</p> <pre> QLabel *separatorLabel = new QLabel; separatorLabel->setText(tr("Tree Separator")); QLineEdit *separatorLineEdit = new QLineEdit; separatorLineEdit->setText(completer->separator()); connect(separatorLineEdit, SIGNAL(textChanged(QString)), completer, SLOT(setSeparator(QString))); QCheckBox *wrapCheckBox = new QCheckBox; wrapCheckBox->setText(tr("Wrap around completions")); wrapCheckBox->setChecked(completer->wrapAround()); connect(wrapCheckBox, SIGNAL(clicked(bool)), completer, SLOT(setWrapAround(bool))); contentsLabel = new QLabel; contentsLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(separatorLineEdit, SIGNAL(textChanged(QString)), this, SLOT(updateContentsLabel(QString))); treeView = new QTreeView; treeView->setModel(completer->model()); treeView->header()->hide(); treeView->expandAll(); connect(modeCombo, SIGNAL(activated(int)), this, SLOT(changeMode(int))); connect(caseCombo, SIGNAL(activated(int)), this, SLOT(changeCase(int))); lineEdit = new QLineEdit; lineEdit->setCompleter(completer);</pre> <p>We use a <a href="qgridlayout.html">QGridLayout</a> to place all the objects in the <tt>MainWindow</tt>.</p> <pre> QGridLayout *layout = new QGridLayout; layout->addWidget(modelLabel, 0, 0); layout->addWidget(treeView, 0, 1); layout->addWidget(modeLabel, 1, 0); layout->addWidget(modeCombo, 1, 1); layout->addWidget(caseLabel, 2, 0); layout->addWidget(caseCombo, 2, 1); layout->addWidget(separatorLabel, 3, 0); layout->addWidget(separatorLineEdit, 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); changeCase(caseCombo->currentIndex()); changeMode(modeCombo->currentIndex()); setWindowTitle(tr("Tree Model Completer")); lineEdit->setFocus(); }</pre> <p>The <tt>createMenu()</tt> function sets up the <a href="qaction.html">QAction</a> objects required and adds them to the "File" menu and "Help" menu. The <a href="qaction.html#triggered">triggered()</a> signals from these actions are connected to their respective slots.</p> <pre> 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, SIGNAL(triggered()), qApp, SLOT(quit())); connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); QMenu* fileMenu = menuBar()->addMenu(tr("File")); fileMenu->addAction(exitAction); QMenu* helpMenu = menuBar()->addMenu(tr("About")); helpMenu->addAction(aboutAct); helpMenu->addAction(aboutQtAct); }</pre> <p>The <tt>changeMode()</tt> function accepts an <i>index</i> corresponding to the user's choice of completion mode and changes the <tt>completer</tt>'s mode accordingly.</p> <pre> 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); }</pre> <p>The <tt>about()</tt> function provides a brief description on the Tree Model Completer example.</p> <pre> void MainWindow::about() { QMessageBox::about(this, tr("About"), tr("This example demonstrates how " "to use a QCompleter with a custom tree model.")); }</pre> <p>The <tt>changeCase()</tt> function alternates between <a href="qt.html#CaseSensitivity-enum">Case Sensitive</a> and <a href="qt.html#CaseSensitivity-enum">Case Insensitive</a> modes, depending on the value of <i>cs</i>.</p> <pre> void MainWindow::changeCase(int cs) { completer->setCaseSensitivity(cs ? Qt::CaseSensitive : Qt::CaseInsensitive); }</pre> <a name="function"></a> <h2><tt>main()</tt> Function</h2> <p>The <tt>main()</tt> function instantiates <tt>MainWindow</tt> and invokes the <a href="qwidget.html#show">show()</a> function to display it.</p> <pre> int main(int argc, char *argv[]) { Q_INIT_RESOURCE(treemodelcompleter); QApplication app(argc, argv); MainWindow window; window.show(); return app.exec(); }</pre> <p /><address><hr /><div align="center"> <table width="100%" cellspacing="0" border="0"><tr class="address"> <td width="40%" align="left">Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies)</td> <td width="20%" align="center"><a href="trademarks.html">Trademarks</a></td> <td width="40%" align="right"><div align="right">Qt 4.6.3</div></td> </tr></table></div></address></body> </html>