1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the documentation of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:FDL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in a
|
---|
14 | ** written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Free Documentation License
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Free
|
---|
18 | ** Documentation License version 1.3 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file included in the packaging of this
|
---|
20 | ** file.
|
---|
21 | **
|
---|
22 | ** If you have questions regarding the use of this file, please contact
|
---|
23 | ** Nokia at [email protected].
|
---|
24 | ** $QT_END_LICENSE$
|
---|
25 | **
|
---|
26 | ****************************************************************************/
|
---|
27 |
|
---|
28 | /*!
|
---|
29 | \page modelview.html
|
---|
30 |
|
---|
31 | \startpage {index.html}{Qt Reference Documentation}
|
---|
32 |
|
---|
33 | \title Model/View Tutorial
|
---|
34 | \brief An introduction to ModelView programming
|
---|
35 |
|
---|
36 | Every UI developer should know about ModelView programming and the goal of
|
---|
37 | this tutorial is to provide you with an easily understandable introduction
|
---|
38 | to this topic.
|
---|
39 |
|
---|
40 | Table, list and tree widgets are components frequently used in GUIs. There
|
---|
41 | are 2 different ways how these widgets can access their data. The
|
---|
42 | traditional way involves widgets which include internal containers for
|
---|
43 | storing data. This approach is very intuitive, however, in many non-trivial
|
---|
44 | applications, it leads to data synchronization issues.
|
---|
45 | The second approach is model/view programming, in
|
---|
46 | which widgets do not maintain internal data containers. They access external
|
---|
47 | data through a standardized interface and therefore avoid data duplication.
|
---|
48 | This may seem complicated at first, but once you take a closer look, it is
|
---|
49 | not only easy to grasp, but the many benefits of model/view programming also
|
---|
50 | become clearer.
|
---|
51 |
|
---|
52 | \image treeview.png
|
---|
53 |
|
---|
54 | In the process, we will learn about some basic technologies provided by Qt,
|
---|
55 | such as:
|
---|
56 |
|
---|
57 | \list
|
---|
58 | \o The difference between standard and model/view widgets
|
---|
59 | \o Adapters betweeen forms and models
|
---|
60 | \o Developing a simple model/view application
|
---|
61 | \o Predefined models
|
---|
62 | \o Intermediate topics such as:
|
---|
63 | \list
|
---|
64 | \o Tree views
|
---|
65 | \o Selection
|
---|
66 | \o Delegates
|
---|
67 | \o Debugging with model test
|
---|
68 | \endlist
|
---|
69 | \endlist
|
---|
70 |
|
---|
71 | You will also learn whether your new application can be written easier with
|
---|
72 | model/view programming or if classic widgets will work just as well.
|
---|
73 |
|
---|
74 | This tutorial includes example code for you to edit and integrate into your
|
---|
75 | project. The tutorial's source code is located in Qt's
|
---|
76 | \c examples/tutorials/modelview directory.
|
---|
77 |
|
---|
78 | For more detailed information you may also want to look at the
|
---|
79 | \l{model-view-programming.html}{reference documentation}
|
---|
80 |
|
---|
81 | If you are completely new to Qt, please read \l{How to Learn Qt} if you
|
---|
82 | have not already done so.
|
---|
83 |
|
---|
84 |
|
---|
85 | \section1 1. Introduction
|
---|
86 |
|
---|
87 | Model/View is a technology used to separate data from views in widgets that
|
---|
88 | handle data sets. Standard widgets are not designed for separating data
|
---|
89 | from views and this is why Qt 4 has two different types of widgets. Both
|
---|
90 | types of widgets look the same, but they interact with data differently.
|
---|
91 |
|
---|
92 | \table
|
---|
93 | \row
|
---|
94 | \o Standard widgets use data that is part of the widget.
|
---|
95 | \o \image standardwidget.png
|
---|
96 | \row
|
---|
97 | \o View classes operate on external data (the model)
|
---|
98 | \o \image modelview.png
|
---|
99 | \endtable
|
---|
100 |
|
---|
101 | \section2 1.1 Standard Widgets
|
---|
102 |
|
---|
103 | Let's have a closer look at a standard table widget. A table widget is a 2D
|
---|
104 | array of the data elements that the user can change. The table widget can be
|
---|
105 | integrated into a program flow by reading and writing the data elements that
|
---|
106 | the table widget provides.
|
---|
107 |
|
---|
108 | This method is very intuitive and useful in many applications, but displaying
|
---|
109 | and editing a database table with a standard table widget can be problematic.
|
---|
110 | Two copies of the data have to be coordinated: one outside the
|
---|
111 | widget; one inside the widget. The developer is responsible for
|
---|
112 | synchronizing both versions. Besides this, the tight coupling of presentation and data
|
---|
113 | makes it harder to write unit tests.
|
---|
114 |
|
---|
115 | \section2 1.2 Model/View to the Rescue
|
---|
116 |
|
---|
117 | Model/view stepped up to provide a solution that uses a more versatile
|
---|
118 | architecture. Model/view eliminates the data consistency problems that may
|
---|
119 | occur with standard widgets. Model/view also makes it easier to use more
|
---|
120 | than one view of the same data because one model can be passed on to many
|
---|
121 | views. The most important difference is that model/view widgets do not store
|
---|
122 | data behind the table cells. In fact, they operate directly from your data.
|
---|
123 | Since view classes do not know your data's structure, you need to provide a
|
---|
124 | wrapper to make your data conform to the QAbstractItemModel interface. A
|
---|
125 | view uses this interface to read from and write to your data. Any instance
|
---|
126 | of a class that implements QAbstractItemModel is said to be a model. Once
|
---|
127 | the view receives a pointer to a model, it will read and display its content
|
---|
128 | and be its editor.
|
---|
129 |
|
---|
130 | \section2 1.3 Overview of the Model/View Widgets
|
---|
131 |
|
---|
132 | Here is an overview of the model/view widgets and their corresponding
|
---|
133 | standard widgets.
|
---|
134 |
|
---|
135 | \table
|
---|
136 | \header
|
---|
137 | \o Widget
|
---|
138 | \o Standard Widget\br
|
---|
139 | (an item based convenience class)
|
---|
140 | \o Model/View View Class\br
|
---|
141 | (for use with external data)
|
---|
142 | \row
|
---|
143 | \o \inlineimage listview.png
|
---|
144 | \o \l QListWidget
|
---|
145 | \o \l QListView
|
---|
146 | \row
|
---|
147 | \o \inlineimage tableview.png
|
---|
148 | \o \l QTableWidget
|
---|
149 | \o \l QTableView
|
---|
150 | \row
|
---|
151 | \o \inlineimage treeview.png
|
---|
152 | \o \l QTreeWidget
|
---|
153 | \o \l QTreeView
|
---|
154 | \row
|
---|
155 | \o \inlineimage columnview.png
|
---|
156 | \o
|
---|
157 | \o \l QColumnView shows a tree as a hierarchy of lists
|
---|
158 | \row
|
---|
159 | \o \inlineimage combobox.png
|
---|
160 | \o {2, 1} \l QComboBox can work as both a view class and also
|
---|
161 | as a traditional widget
|
---|
162 | \endtable
|
---|
163 |
|
---|
164 | \section2 1.4 Using Adapters between Forms and Models
|
---|
165 |
|
---|
166 | Having adapters between forms and models can come in handy.
|
---|
167 |
|
---|
168 | We can edit data stored in tables directly from within the table itself, but
|
---|
169 | it's much more comfortable to edit data in text fields. There is no direct
|
---|
170 | model/view counterpart that separates data and views for widgets that
|
---|
171 | operate on one value (QLineEdit, QCheckBox ...) instead of a dataset, so we
|
---|
172 | need an adapter in order to connect the form to the source of data.
|
---|
173 |
|
---|
174 | \l QDataWidgetMapper is a great solution because it maps form widgets to a
|
---|
175 | table row and makes it very easy to build forms for database tables.
|
---|
176 |
|
---|
177 | \image widgetmapper.png
|
---|
178 |
|
---|
179 | Another example of an adapter is \l QCompleter. Qt has \l QCompleter for
|
---|
180 | providing auto-completions in Qt widgets such as \l QComboBox and, as shown
|
---|
181 | below, \l QLineEdit. \l QCompleter uses a model as its data source.
|
---|
182 |
|
---|
183 | \image qcompleter.png
|
---|
184 |
|
---|
185 |
|
---|
186 | \section1 2. A Simple Model/View Application
|
---|
187 | If you want to develop a model/view application, where should you start?
|
---|
188 | We recommend starting with a simple example and extending it step-by-step.
|
---|
189 | This makes understanding the architecture a lot easier. Trying to understand
|
---|
190 | the model/view architecture in detail before invoking the IDE has proven
|
---|
191 | to be less convenient for many developers. It is substantially easier to
|
---|
192 | start with a simple model/view application that has demo data. Give it a
|
---|
193 | try! Simply replace the data in the examples below with your own.
|
---|
194 |
|
---|
195 | Below are 7 very simple and independent applications that show different
|
---|
196 | sides of model/view programming. The source code can be found inside the
|
---|
197 | \c{examples/tutorials/modelview} directory.
|
---|
198 |
|
---|
199 | \section2 2.1 A Read Only Table
|
---|
200 |
|
---|
201 | We start with an application that uses a QTableView to show data. We will
|
---|
202 | add editing capabilities later.
|
---|
203 |
|
---|
204 | (file source: examples/tutorials/modelview/1_readonly/main.cpp)
|
---|
205 | \snippet examples/tutorials/modelview/1_readonly/main.cpp Quoting ModelView Tutorial
|
---|
206 |
|
---|
207 | We have the usual \l {modelview-part2-main-cpp.html}{main()} function:
|
---|
208 |
|
---|
209 | Here is the interesting part: We create an instance of MyModel and use
|
---|
210 | \l{QTableView::setModel()}{tableView.setModel(&myModel);} to pass a
|
---|
211 | pointer of it to to \l{QTableView}{tableView}. \l{QTableView}{tableView}
|
---|
212 | will invoke the methods of the pointer it has received to find out two
|
---|
213 | things:
|
---|
214 |
|
---|
215 | \list
|
---|
216 | \o How many rows and columns should be displayed.
|
---|
217 | \o What content should be printed into each cell.
|
---|
218 | \endlist
|
---|
219 |
|
---|
220 | The model needs some code to respond to this.
|
---|
221 |
|
---|
222 | We have a table data set, so let's start with QAbstractTableModel since it
|
---|
223 | is easier to use than the more general QAbstractItemModel.
|
---|
224 |
|
---|
225 | (file source: examples/tutorials/modelview/1_readonly/mymodel.h)
|
---|
226 | \snippet examples/tutorials/modelview/1_readonly/mymodel.h Quoting ModelView Tutorial
|
---|
227 |
|
---|
228 | QAbstractTableModel requires the implementation of three abstract methods.
|
---|
229 |
|
---|
230 | (file source: examples/tutorials/modelview/1_readonly/mymodel.cpp)
|
---|
231 | \snippet examples/tutorials/modelview/1_readonly/mymodel.cpp Quoting ModelView Tutorial
|
---|
232 |
|
---|
233 | The number of rows and columns is provided by
|
---|
234 | \l{QAbstractItemModel::rowCount()}{MyModel::rowCount()} and
|
---|
235 | \l{QAbstractItemModel::columnCount()}{MyModel::columnCount()}. When the view
|
---|
236 | has to know what the cell's text is, it calls the method
|
---|
237 | \l{QAbstractItemModel::data()}{MyModel::data()}. Row and column information
|
---|
238 | is specified with parameter \c index and the role is set to
|
---|
239 | \l{Qt::ItemDataRole}{Qt::DisplayRole}. Other roles are covered in the next
|
---|
240 | section. In our example, the data that should be displayed is generated. In
|
---|
241 | a real application, \c MyModel would have a member called \c MyData, which
|
---|
242 | serves as the target for all reading and writing operations.
|
---|
243 |
|
---|
244 | This small example demonstrates the passive nature of a model. The model
|
---|
245 | does not know when it will be used or which data is needed. It simply
|
---|
246 | provides data each time the view requests it.
|
---|
247 |
|
---|
248 | What happens when the model's data needs to be changed? How does the view
|
---|
249 | realize that data has changed and needs to be read again? The model has to
|
---|
250 | emit a signal that indicates what range of cells has changed. This will be
|
---|
251 | demonstrated in section 2.3.
|
---|
252 |
|
---|
253 | \section2 2.2 Extending the Read Only Example with Roles
|
---|
254 |
|
---|
255 | In addition to controlling what text the view displays, the model also
|
---|
256 | controls the text's appearance. When we slightly change the model, we get
|
---|
257 | the following result: \image readonlytable_role.png
|
---|
258 |
|
---|
259 | In fact, nothing except for the \l{QAbstractItemModel::}{data()} method
|
---|
260 | needs to be changed to set fonts, background colour, alignment and a
|
---|
261 | checkbox.
|
---|
262 | Below is the \l{QAbstractItemModel::data()}{data()} method that produces the
|
---|
263 | result shown above. The difference is that this time we use parameter int
|
---|
264 | role to return different pieces of information depending on its value.
|
---|
265 |
|
---|
266 | (file source: examples/tutorials/modelview/2_formatting/mymodel.cpp)
|
---|
267 | \snippet examples/tutorials/modelview/2_formatting/mymodel.cpp Quoting ModelView Tutorial
|
---|
268 |
|
---|
269 | Each formatting property will be requested from the model with a separate
|
---|
270 | call to the \l{QAbstractItemModel::data()}{data()} method. The \c role
|
---|
271 | parameter is used to let the model know which property is being requested:
|
---|
272 |
|
---|
273 | \table
|
---|
274 | \header
|
---|
275 | \o \l{Qt::ItemDataRole}{enum Qt::ItemDataRole}
|
---|
276 | \o Meaning
|
---|
277 | \o Type
|
---|
278 | \row
|
---|
279 | \o \l{Qt::ItemDataRole}{}Qt::DisplayRole
|
---|
280 | \o text
|
---|
281 | \o QString
|
---|
282 | \row
|
---|
283 | \o \l{Qt::ItemDataRole}{Qt::FontRole}
|
---|
284 | \o font
|
---|
285 | \o QFont
|
---|
286 | \row
|
---|
287 | \o \l{Qt::ItemDataRole}{BackgroundRole}
|
---|
288 | \o brush for the background of the cell
|
---|
289 | \o QBrush
|
---|
290 | \row
|
---|
291 | \o \l{Qt::ItemDataRole}{Qt::TextAlignmentRole}
|
---|
292 | \o text alignment
|
---|
293 | \o \l{Qt::AlignmentFlag}{enum Qt::AlignmentFlag}
|
---|
294 | \row
|
---|
295 | \o {1, 3} \l{Qt::ItemDataRole}{Qt::CheckStateRole}
|
---|
296 | \o {1, 3} suppresses checkboxes with \l{QVariant}{QVariant()},
|
---|
297 |
|
---|
298 | sets checkboxes with \l{Qt::CheckState}{Qt::Checked}
|
---|
299 |
|
---|
300 | or \l{Qt::CheckState}{Qt::Unchecked}
|
---|
301 | \o {1, 3} \l{Qt::ItemDataRole}{enum Qt::ItemDataRole}
|
---|
302 | \endtable
|
---|
303 |
|
---|
304 | Refer to the Qt namespace documentation to learn more about the
|
---|
305 | \l{Qt::ItemDataRole}{Qt::ItemDataRole} enum's capabilities.
|
---|
306 |
|
---|
307 | Now we need to determine how using a separated model impacts the
|
---|
308 | application's performance, so let's trace how often the view calls the
|
---|
309 | \l{QAbstractItemModel::}{data()} method. In order to track how often the
|
---|
310 | view calls the model, we have put a debug statement in the
|
---|
311 | \l{QAbstractItemModel::}{data()} method, which logs onto the error output
|
---|
312 | stream. In our small example, \l{QAbstractItemModel::}{data()} will be
|
---|
313 | called 42 times.
|
---|
314 | Each time you hover the cursor over the field,
|
---|
315 | \l{QAbstractItemModel::}{data()} will be called again \mdash 7 times for
|
---|
316 | each cell. That's why it is important to make sure that your data is
|
---|
317 | available when \l{QAbstractItemModel::}{data()} is invoked and expensive
|
---|
318 | lookup operations are cached.
|
---|
319 |
|
---|
320 | \section2 2.3 A Clock inside a Table Cell
|
---|
321 |
|
---|
322 | \image clock.png
|
---|
323 |
|
---|
324 | We still have a read only table, but this time the content changes every
|
---|
325 | second because we are showing the current time.
|
---|
326 |
|
---|
327 | (file source: examples/tutorials/modelview/3_changingmodel/mymodel.cpp)
|
---|
328 | \snippet examples/tutorials/modelview/3_changingmodel/mymodel.cpp quoting mymodel_QVariant
|
---|
329 |
|
---|
330 | Something is missing to make the clock tick. We need to tell the view every
|
---|
331 | second that the time has changed and that it needs to be read again. We do
|
---|
332 | this with a timer. In the constructor, we set its interval to 1 second and
|
---|
333 | connect its timeout signal.
|
---|
334 |
|
---|
335 | (file source: examples/tutorials/modelview/3_changingmodel/mymodel.cpp)
|
---|
336 | \snippet examples/tutorials/modelview/3_changingmodel/mymodel.cpp quoting mymodel_a
|
---|
337 |
|
---|
338 | Here is the corresponding slot:
|
---|
339 |
|
---|
340 | (file source: examples/tutorials/modelview/3_changingmodel/mymodel.cpp)
|
---|
341 | \snippet examples/tutorials/modelview/3_changingmodel/mymodel.cpp quoting mymodel_b
|
---|
342 |
|
---|
343 | We ask the view to read the data in the top left cell again by emitting the
|
---|
344 | \l{QAbstractItemModel::}{dataChanged()} signal. Note that we did not
|
---|
345 | explicitly connect the \l{QAbstractItemModel::}{dataChanged()} signal to the
|
---|
346 | view. This happened automatically when we called \l{QTableView::}{setModel()}.
|
---|
347 |
|
---|
348 | \section2 2.4 Setting up Headers for Columns and Rows
|
---|
349 |
|
---|
350 | Headers can be hidden via a view method: \c{tableView->verticalHeader()->hide();}
|
---|
351 | \image header.png
|
---|
352 |
|
---|
353 | The header content, however, is set via the model, so we reimplement the
|
---|
354 | \l{QAbstractItemModel::headerData()}{headerData()} method:
|
---|
355 |
|
---|
356 | (file source: examples/tutorials/modelview/4_headers/mymodel.cpp)
|
---|
357 | \snippet examples/tutorials/modelview/4_headers/mymodel.cpp quoting mymodel_c
|
---|
358 |
|
---|
359 | Note that method \l{QAbstractItemModel::headerData()}{headerData()} also has
|
---|
360 | a parameter role which has the same meaning as in
|
---|
361 | \l{QAbstractItemModel::data()}{MyModel::data()}.
|
---|
362 |
|
---|
363 | \section2 2.5 The Minimal Editing Example
|
---|
364 |
|
---|
365 | In this example, we are going to build an application that automatically
|
---|
366 | populates a window title with content by repeating values entered into table
|
---|
367 | cells. To be able to access the window title easily we put the QTableView in
|
---|
368 | a QMainWindow.
|
---|
369 |
|
---|
370 | The model decides whether editing capabilities are available. We only have
|
---|
371 | to modify the model in order for the available editing capabilities to be
|
---|
372 | enabled. This is done by reimplementing the following virtual methods:
|
---|
373 | \l{QAbstractItemModel::}{setData()} and \l{QAbstractItemModel::}{flags()}.
|
---|
374 |
|
---|
375 | (file source: examples/tutorials/modelview/5_edit/mymodel.h)
|
---|
376 | \snippet examples/tutorials/modelview/5_edit/mymodel.h Quoting ModelView Tutorial
|
---|
377 |
|
---|
378 | We use \c the two-dimensional array QString \c m_gridData to store our data.
|
---|
379 | This makes \c m_gridData the core of \c MyModel. The rest of \c MyModel acts
|
---|
380 | like a wrapper and adapts \c m_gridData to the QAbstractItemModel
|
---|
381 | interface. We have also introduced the \c editCompleted() signal, which
|
---|
382 | makes it possible to transfer the modified text to the window title.
|
---|
383 |
|
---|
384 | (file source: examples/tutorials/modelview/5_edit/mymodel.cpp)
|
---|
385 | \snippet examples/tutorials/modelview/5_edit/mymodel.cpp quoting mymodel_e
|
---|
386 |
|
---|
387 | \l{QAbstractItemModel::setData()}{setData()} will be called each time the
|
---|
388 | user edits a cell. The \c index parameter tells us which field has been
|
---|
389 | edited and \c value provides the result of the editing process. The role
|
---|
390 | will always be set to \l Qt::EditRole because our cells only contain text.
|
---|
391 | If a checkbox were present and user permissions are set to allow the
|
---|
392 | checkbox to be selected, calls would also be made with the role set to
|
---|
393 | \l Qt::CheckStateRole.
|
---|
394 |
|
---|
395 | (file source: examples/tutorials/modelview/5_edit/mymodel.cpp)
|
---|
396 | \snippet examples/tutorials/modelview/5_edit/mymodel.cpp quoting mymodel_f
|
---|
397 |
|
---|
398 | Various properties of a cell can be adjusted with
|
---|
399 | \l{QAbstractItemModel::flags()}{flags()}.
|
---|
400 |
|
---|
401 | Returning \l{Qt::ItemFlag}{Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled}
|
---|
402 | is enough to show an editor that a cell can be selected.
|
---|
403 |
|
---|
404 | If editing one cell modifies more data than the data in that particular
|
---|
405 | cell, the model must emit a \l{QAbstractItemModel::}{dataChanged()} signal
|
---|
406 | in order for the data that has been changed to be read.
|
---|
407 |
|
---|
408 |
|
---|
409 | \section1 3. Intermediate Topics
|
---|
410 |
|
---|
411 | \section2 3.1 TreeView
|
---|
412 |
|
---|
413 | You can convert the example above into an application with a tree view.
|
---|
414 | Simply replace QTableView with QTreeView, which results in a read/write
|
---|
415 | tree. No changes have to be made to the model. The tree won't have any
|
---|
416 | hierarchies because there aren't any hierarchies in the model itself.
|
---|
417 |
|
---|
418 | \image dummy_tree.png
|
---|
419 |
|
---|
420 | QListView, QTableView and QTreeView all use a model abstraction, which is a
|
---|
421 | merged list, table and tree. This makes it possible to use several different
|
---|
422 | types of view classes from the same model.
|
---|
423 |
|
---|
424 | \image list_table_tree.png
|
---|
425 |
|
---|
426 | This is how our example model looks so far:
|
---|
427 |
|
---|
428 | \image example_model.png
|
---|
429 |
|
---|
430 | We want to present a real tree. We have wrapped our data in the examples
|
---|
431 | above in order to make a model. This time we use QStandardItemModel, which
|
---|
432 | is a container for hierarchical data that also implements
|
---|
433 | QAbstractItemModel. To show a tree, QStandardItemModel must be populated
|
---|
434 | with \l{QStandardItem}s, which are able to hold all the standard properties
|
---|
435 | of items like text, fonts, checkboxes or brushes.
|
---|
436 |
|
---|
437 | \image tree_2_with_algorithm.png
|
---|
438 |
|
---|
439 | (file source: examples/tutorials/modelview/6_treeview/mainwindow.cpp)
|
---|
440 | \snippet examples/tutorials/modelview/6_treeview/mainwindow.cpp Quoting ModelView Tutorial
|
---|
441 |
|
---|
442 | We simply instantiate a QStandardItemModel and add a couple of
|
---|
443 | \l{QStandardItem}{QStandardItems} to the constructor. We can then make a
|
---|
444 | hierarchical data structure because a QStandardItem can hold other
|
---|
445 | \l{QStandardItem}{QStandardItems}. Nodes are collapsed and expanded within
|
---|
446 | the view.
|
---|
447 |
|
---|
448 | \section2 3.2 Working with Selections
|
---|
449 |
|
---|
450 | We want to access a selected item's content in order to output it into the
|
---|
451 | window title together with the hierarchy level.
|
---|
452 |
|
---|
453 | \image selection2.png
|
---|
454 |
|
---|
455 | So let's create a couple of items:
|
---|
456 |
|
---|
457 | (file source: examples/tutorials/modelview/7_selections/mainwindow.cpp)
|
---|
458 | \snippet examples/tutorials/modelview/7_selections/mainwindow.cpp quoting modelview_a
|
---|
459 |
|
---|
460 | Views manage selections within a separate selection model, which can be
|
---|
461 | retrieved with the \l{QAbstractItemView::}{selectionModel()} method. We
|
---|
462 | retrieve the selection Model in order to connect a slot to its
|
---|
463 | \l{QAbstractItemView::}{selectionChanged()} signal.
|
---|
464 |
|
---|
465 | (file source: examples/tutorials/modelview/7_selections/mainwindow.cpp)
|
---|
466 | \snippet examples/tutorials/modelview/7_selections/mainwindow.cpp quoting modelview_b
|
---|
467 |
|
---|
468 | We get the model index that corresponds to the selection by calling
|
---|
469 | \l{QItemSelectionModel::currentIndex()}{treeView->selectionModel()->currentIndex()}
|
---|
470 | and we get the the field's string by using the model index. Then we just
|
---|
471 | calculate the item's \c hierarchyLevel. Top level items do not have parents
|
---|
472 | and the \l{QAbstractItemModel::}{parent()} method will return a default
|
---|
473 | constructed \l{QModelIndex}{QModelIndex()}. This is why we use the
|
---|
474 | \l{QAbstractItemModel::}{parent()} method to iterate to the top level while
|
---|
475 | counting the steps performed during iteration.
|
---|
476 |
|
---|
477 | The selection model (as shown above) can be retrieved, but it can also be
|
---|
478 | set with \l{QAbstractItemView}{QAbstractItemView::setSelectionModel}. This
|
---|
479 | is how it's possible to have 3 view classes with synchronised selections
|
---|
480 | because only one instance of a selection model is used. To share a selection
|
---|
481 | model between 3 views use \l{QAbstractItemView::}{selectionModel()} and
|
---|
482 | assign the result to the second and third view class with
|
---|
483 | \l{QAbstractItemView::}{setSelectionModel()}.
|
---|
484 |
|
---|
485 | \section2 3.3 Predefined Models
|
---|
486 |
|
---|
487 | The typical way to use model/view is to wrap specific data to make it usable
|
---|
488 | with view classes. Qt, however, also provides predefined models for common
|
---|
489 | underlying data structures. If one of the available data structures is
|
---|
490 | suitable for your application, a predefined model can be a good choice.
|
---|
491 |
|
---|
492 | \table
|
---|
493 | \row
|
---|
494 | \o QStringListModel
|
---|
495 | \o Stores a list of strings
|
---|
496 | \row
|
---|
497 | \o QStandardItemModel
|
---|
498 | \o Stores arbitrary hierarchical items
|
---|
499 | \row
|
---|
500 | \o QFileSystemModel\br
|
---|
501 | QDirModel
|
---|
502 | \o Encapsulate the local file system
|
---|
503 | \row
|
---|
504 | \o QSqlQueryModel
|
---|
505 | \o Encapsulate an SQL result set
|
---|
506 | \row
|
---|
507 | \o QSqlTableModel
|
---|
508 | \o Encapsulates an SQL table
|
---|
509 | \row
|
---|
510 | \o QSqlRelationalTableModel
|
---|
511 | \o Encapsulates an SQL table with foreign keys
|
---|
512 | \row
|
---|
513 | \o QSortFilterProxyModel
|
---|
514 | \o Sorts and/or filters another model
|
---|
515 |
|
---|
516 | \endtable
|
---|
517 |
|
---|
518 | \section2 3.4 Delegates
|
---|
519 |
|
---|
520 | In all examples so far, data is presented as text or a checkbox in a cell
|
---|
521 | and is edited as text or a checkbox. The component that provides these
|
---|
522 | presentation and editing services is called a \e delegate. We are only just
|
---|
523 | beginning to work with the delegate because the view uses a default
|
---|
524 | delegate. But imagine that we want to have a different editor (e.g., a
|
---|
525 | slider or a drop down list) Or imagine that we want to present data as
|
---|
526 | graphics.
|
---|
527 | Let's take a look at an example called \l{Star Delegate Example}{Star
|
---|
528 | Delegate}, in which stars are used to show a rating:
|
---|
529 |
|
---|
530 | \image stardelegate.png
|
---|
531 |
|
---|
532 | The view has a \l{QAbstractItemView::}{setItemDelegate()} method that
|
---|
533 | replaces the default delegate and installs a custom delegate.
|
---|
534 | A new delegate can be written by creating a class that inherits from
|
---|
535 | QStyledItemDelegate. In order to write a delegate that displays stars and
|
---|
536 | has no input capabilities, we only need to override 2 methods.
|
---|
537 |
|
---|
538 | \code
|
---|
539 | class StarDelegate : public QStyledItemDelegate
|
---|
540 | {
|
---|
541 | Q_OBJECT
|
---|
542 | public:
|
---|
543 | StarDelegate(QWidget *parent = 0);
|
---|
544 | void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
---|
545 | const QModelIndex &index) const;
|
---|
546 | QSize sizeHint(const QStyleOptionViewItem &option,
|
---|
547 | const QModelIndex &index) const;
|
---|
548 | };
|
---|
549 | \endcode
|
---|
550 |
|
---|
551 | \l{QStyledItemDelegate::}{paint()} draws stars depending on the content of
|
---|
552 | the underlying data. The data can be looked up by calling
|
---|
553 | \l{QModelIndex::data()}{index.data()}. The delegate's
|
---|
554 | \l{QAbstractItemDelegate::}{sizeHint()} method is used to obtain each
|
---|
555 | star's dimensions, so the the cell will provide enough height and width to
|
---|
556 | accommodate the stars.
|
---|
557 |
|
---|
558 | Writing custom delegates is the right choice if you want to show your data
|
---|
559 | with a custom graphical representation inside the grid of the view class. If
|
---|
560 | you want to leave the grid, you would not use a custom delegate but a custom
|
---|
561 | view class.
|
---|
562 |
|
---|
563 | Other references to delegates in Qt Documentation:
|
---|
564 |
|
---|
565 | \list
|
---|
566 | \o \l{Spin Box Delegate Example}
|
---|
567 | \o \l{QAbstractItemDelegate}{QAbstractItemDelegate Class Reference}
|
---|
568 | \o \l{QSqlRelationalDelegate}{QSqlRelationalDelegate Class Reference}
|
---|
569 | \o \l{QStyledItemDelegate}{QStyledItemDelegate Class Reference}
|
---|
570 | \o \l{QItemDelegate}{QItemDelegate Class Reference}
|
---|
571 | \endlist
|
---|
572 |
|
---|
573 |
|
---|
574 | \section2 3.5 Debugging with ModelTest
|
---|
575 |
|
---|
576 | The passive nature of models provides new challenges for programmers.
|
---|
577 | Inconsistencies in the model can cause the application to crash. Since the
|
---|
578 | model is hit by numerous calls from the view, it is hard to find out which
|
---|
579 | call has crashed the application and which operation has introduced the
|
---|
580 | problem.
|
---|
581 |
|
---|
582 | Qt Labs provides software called
|
---|
583 | \l{http://labs.qt.nokia.com/page/Projects/Itemview/Modeltest}{ModelTest},
|
---|
584 | which checks models while your programming is running. Every time the model
|
---|
585 | is changed, ModelTest scans the model and reports errors with an assert.
|
---|
586 | This is especially important for tree models, since their hierarchical
|
---|
587 | nature leaves many possibilities for subtle inconsistencies.
|
---|
588 |
|
---|
589 | Unlike view classes, ModelTest uses out of range indexes to test the model.
|
---|
590 | This means your application may crash with ModelTest even if it runs
|
---|
591 | perfectly without it. So you also need to handle all of the indexes that are
|
---|
592 | out of range when using ModelTest.
|
---|
593 |
|
---|
594 |
|
---|
595 | \section1 4. Good Sources of Additional Information
|
---|
596 |
|
---|
597 | \section2 4.1 Books
|
---|
598 |
|
---|
599 | Model/View programming is covered quite extensively in the documentation of
|
---|
600 | Qt but also in several good books.
|
---|
601 |
|
---|
602 | \list 1
|
---|
603 | \o \bold{C++ GUI Programming with Qt 4} / Jasmin Blanchette, Mark Summerfield,
|
---|
604 | \e{Prentice Hall, 2nd edition}, ISBN 0-13-235416-0. Also available in
|
---|
605 | German: \bold{C++ GUI Programmierung mit Qt 4: Die offizielle EinfÃŒhrung},
|
---|
606 | \e{Addison-Wesley}, ISBN 3-827327-29-6
|
---|
607 | \o \bold{The Book of Qt4, The Art of Building Qt Applications} / Daniel Molkentin,
|
---|
608 | \e{Open Source Press}, ISBN 1-59327-147-6.
|
---|
609 | Translated from \bold{Qt 4, EinfÃŒhrung in die Applikationsentwicklung},
|
---|
610 | \e{Open Source Press}, ISBN 3-937514-12-0.
|
---|
611 | \o \bold{Foundations of Qt Development} / Johan Thelin, \e{Apress}, ISBN 1-59059-831-8.
|
---|
612 | \o \bold{Advanced Qt Programming} / Mark Summerfield, \e{Prentice Hall}, ISBN 0-321-63590-6.
|
---|
613 | This book covers Model/View programming on more than 150 pages.
|
---|
614 | \endlist
|
---|
615 |
|
---|
616 | More information about these books is available on the
|
---|
617 | \l{Books about Qt Programming}{Qt Web site}.
|
---|
618 |
|
---|
619 | The following list provides an overview of example programs contained in the first three
|
---|
620 | books listed above. Some of them make very good templates for developing similar
|
---|
621 | applications.
|
---|
622 |
|
---|
623 | \table
|
---|
624 | \header
|
---|
625 | \o Example name
|
---|
626 | \o View class used
|
---|
627 | \o Model used
|
---|
628 | \o Aspects covered
|
---|
629 | \o
|
---|
630 | \row
|
---|
631 | \o Team Leaders
|
---|
632 | \o QListview
|
---|
633 | \o QStringListModel
|
---|
634 | \o
|
---|
635 | \o Book 1, Chapter 10, Figure 10.6
|
---|
636 | \row
|
---|
637 | \o Directory Viewer
|
---|
638 | \o QTreeView
|
---|
639 | \o QDirModel
|
---|
640 | \o
|
---|
641 | \o Book 1, Chapter 10, Figure 10.7
|
---|
642 | \row
|
---|
643 | \o Color Names
|
---|
644 | \o QListView
|
---|
645 | \o QSortFilterProxyModel
|
---|
646 | applied to QStringListModel
|
---|
647 | \o
|
---|
648 | \o Book 1, Chapter 10, Figure 10.8
|
---|
649 | \row
|
---|
650 | \o Currencies
|
---|
651 | \o QTableView
|
---|
652 | \o custom model based on
|
---|
653 | QAbstractTableModel
|
---|
654 | \o Read only
|
---|
655 | \o Book 1, Chapter 10, Figure 10.10
|
---|
656 | \row
|
---|
657 | \o Cities
|
---|
658 | \o QTableView
|
---|
659 | \o Custom model based on
|
---|
660 | QAbstractTableModel
|
---|
661 | \o Read / write
|
---|
662 | \o Book 1, Chapter 10, Figure 10.12
|
---|
663 | \row
|
---|
664 | \o Boolean Parser
|
---|
665 | \o QTreeView
|
---|
666 | \o Custom model based on
|
---|
667 | QAbstractItemModel
|
---|
668 | \o Read only
|
---|
669 | \o Book 1, Chapter 10, Figure 10.14
|
---|
670 | \row
|
---|
671 | \o Track Editor
|
---|
672 | \o {2, 1} QTableWidget
|
---|
673 | \o Custom delegate providing a custom editor
|
---|
674 | \o Book 1, Chapter 10, Figure 10.15
|
---|
675 |
|
---|
676 | \row
|
---|
677 | \o Four directory views
|
---|
678 | \o QListView
|
---|
679 | QTableView
|
---|
680 | QTreeView
|
---|
681 | \o QDirModel
|
---|
682 | \o Demonstrates the use of multiple views
|
---|
683 | \o Book2, Chapter 8.2
|
---|
684 | \row
|
---|
685 | \o Address Book
|
---|
686 | \o QListView
|
---|
687 | QTableView
|
---|
688 | QTreeView
|
---|
689 | \o Custom model based on
|
---|
690 | QAbstractTableModel
|
---|
691 | \o Read / write
|
---|
692 | \o Book2, Chapter 8.4
|
---|
693 | \row
|
---|
694 | \o Address Book with sorting
|
---|
695 | \o
|
---|
696 | \o QProxyModel
|
---|
697 | \o Introducing sort and filter capabilities
|
---|
698 | \o Book2, Chapter 8.5
|
---|
699 | \row
|
---|
700 | \o Address Book
|
---|
701 | with checkboxes
|
---|
702 | \o
|
---|
703 | \o
|
---|
704 | \o Introducing checkboxes in model/view
|
---|
705 | \o Book2, Chapter 8.6
|
---|
706 | \row
|
---|
707 | \o Address Book with transposed grid
|
---|
708 | \o
|
---|
709 | \o Custom proxy Model based on QAbstractProxyModel
|
---|
710 | \o Introducing a custom model
|
---|
711 | \o Book2, Chapter 8.7
|
---|
712 | \row
|
---|
713 | \o Address Book with drag and drop
|
---|
714 | \o
|
---|
715 | \o
|
---|
716 | \o Introducing drag and drop support
|
---|
717 | \o Book2, Chapter 8.8
|
---|
718 | \row
|
---|
719 | \o Address Book with custom editor
|
---|
720 | \o
|
---|
721 | \o
|
---|
722 | \o Introducing custom delegates
|
---|
723 | \o Book2, Chapter 8.9
|
---|
724 | \row
|
---|
725 | \o Views
|
---|
726 | \o QListView
|
---|
727 | QTableView
|
---|
728 | QTreeView
|
---|
729 | \o QStandardItemModel
|
---|
730 | \o Read only
|
---|
731 | \o Book 3, Chapter 5, figure 5-3
|
---|
732 | \row
|
---|
733 | \o Bardelegate
|
---|
734 | \o QTableView
|
---|
735 | \o
|
---|
736 | \o Custom delegate for presentation based on QAbstractItemDelegate
|
---|
737 | \o Book 3, Chapter 5, figure 5-5
|
---|
738 | \row
|
---|
739 | \o Editdelegate
|
---|
740 | \o QTableView
|
---|
741 | \o
|
---|
742 | \o Custom delegate for editing based on QAbstractItemDelegate
|
---|
743 | \o Book 3, Chapter 5, figure 5-6
|
---|
744 | \row
|
---|
745 | \o Singleitemview
|
---|
746 | \o Custom view based on QAbstractItemView
|
---|
747 | \o
|
---|
748 | \o Custom view
|
---|
749 | \o Book 3,
|
---|
750 | Chapter 5,
|
---|
751 | figure 5-7
|
---|
752 | \row
|
---|
753 | \o listmodel
|
---|
754 | \o QTableView
|
---|
755 | \o Custom Model based on QAbstractTableModel
|
---|
756 | \o Read only
|
---|
757 | \o Book 3, Chapter 5, Figure 5-8
|
---|
758 | \row
|
---|
759 | \o treemodel
|
---|
760 | \o QTreeView
|
---|
761 | \o Custom Model based on QAbstractItemModel
|
---|
762 | \o Read only
|
---|
763 | \o Book 3, Chapter 5, Figure 5-10
|
---|
764 | \row
|
---|
765 | \o edit integers
|
---|
766 | \o QListView
|
---|
767 | \o Custom Model based on QAbstractListModel
|
---|
768 | \o Read / write
|
---|
769 | \o Book 3, Chapter 5, Listing 5-37, Figure 5-11
|
---|
770 | \row
|
---|
771 | \o sorting
|
---|
772 | \o QTableView
|
---|
773 | \o QSortFilterProxyModel applied to QStringListModel
|
---|
774 | \o Demonstrates sorting
|
---|
775 | \o Book 3, Chapter 5, Figure 5-12
|
---|
776 | \endtable
|
---|
777 |
|
---|
778 |
|
---|
779 | \section2 4.2 Qt Documentation
|
---|
780 |
|
---|
781 | Qt 4.7 comes with 17 examples and 2 Demonstrations for model/view.
|
---|
782 | The examples can be found on the \l{Item Views Examples} page.
|
---|
783 |
|
---|
784 | \table
|
---|
785 | \header
|
---|
786 | \o Example name
|
---|
787 | \o View class used
|
---|
788 | \o Model used
|
---|
789 | \o Aspects covered
|
---|
790 | \row
|
---|
791 | \o Address Book
|
---|
792 | \o QTableView
|
---|
793 | \o QAbstractTableModel
|
---|
794 | QSortFilterProxyModel
|
---|
795 | \o Usage of QSortFilterProxyModel to generate different
|
---|
796 | subsets from one data pool
|
---|
797 | \row
|
---|
798 | \o Basic Sort/Filter Model
|
---|
799 | \o QTreeView
|
---|
800 | \o QStandardItemModel
|
---|
801 | QSortFilterProxyModel
|
---|
802 | \o
|
---|
803 | \row
|
---|
804 | \o Chart
|
---|
805 | \o Custom view
|
---|
806 | \o QStandardItemModel
|
---|
807 | \o Designing custom views that cooperate with selection models
|
---|
808 | \row
|
---|
809 | \o Color Editor Factory
|
---|
810 | \o {2, 1} QTableWidget
|
---|
811 | \o Enhancing the standard delegate with a new custom editor to choose colours
|
---|
812 | \row
|
---|
813 | \o Combo Widget Mapper
|
---|
814 | \o QDataWidgetMapper to map QLineEdit, QTextEdit and QComboBox
|
---|
815 | \o QStandardItemModel
|
---|
816 | \o Shows how a QComboBox can serve as a view class
|
---|
817 | \row
|
---|
818 | \o Custom Sort/Filter Model
|
---|
819 | \o QTreeView
|
---|
820 | \o QStandardItemModel
|
---|
821 | QSortFilterProxyModel
|
---|
822 | \o Subclass QSortFilterProxyModel for advanced sorting and filtering
|
---|
823 | \row
|
---|
824 | \o Dir View
|
---|
825 | \o QTreeView
|
---|
826 | \o QDirModel
|
---|
827 | \o Very small example to demonstrate how to assign a model to a view
|
---|
828 | \row
|
---|
829 | \o Editable Tree Model
|
---|
830 | \o QTreeView
|
---|
831 | \o Custom tree model
|
---|
832 | \o Comprehensive example for working with trees, demonstrates
|
---|
833 | editing cells and tree structure with an underlying custom
|
---|
834 | model
|
---|
835 | \row
|
---|
836 | \o Fetch More
|
---|
837 | \o QListView
|
---|
838 | \o Custom list model
|
---|
839 | \o Dynamically changing model
|
---|
840 | \row
|
---|
841 | \o Frozen Column
|
---|
842 | \o QTableView
|
---|
843 | \o QStandardItemModel
|
---|
844 | \o
|
---|
845 | \row
|
---|
846 | \o Pixelator
|
---|
847 | \o QTableView
|
---|
848 | \o Custom table model
|
---|
849 | \o Implementation of a custom delegate
|
---|
850 | \row
|
---|
851 | \o Puzzle
|
---|
852 | \o QListView
|
---|
853 | \o Custom list model
|
---|
854 | \o Model/view with drag and drop
|
---|
855 | \row
|
---|
856 | \o Simple DOM Model
|
---|
857 | \o QTreeView
|
---|
858 | \o Custom tree model
|
---|
859 | \o Read only example for a custom tree model
|
---|
860 | \row
|
---|
861 | \o Simple Tree Model
|
---|
862 | \o QTreeView
|
---|
863 | \o Custom tree model
|
---|
864 | \o Read only example for a custom tree model
|
---|
865 | \row
|
---|
866 | \o Simple Widget Mapper
|
---|
867 | \o QDataWidgetMapper to map QLineEdit, QTextEdit and QSpinBox
|
---|
868 | \o QStandardItemModel
|
---|
869 | \o Basic QDataWidgetMapper usage
|
---|
870 | \row
|
---|
871 | \o Spin Box Delegate
|
---|
872 | \o QTableView
|
---|
873 | \o QStandardItemModel
|
---|
874 | \o Custom delegate that uses a spin box as a cell editor
|
---|
875 | \row
|
---|
876 | \o Star Delegate
|
---|
877 | \o {2, 1} QTableWidget
|
---|
878 | \o Comprehensive custom delegate example.
|
---|
879 | \endtable
|
---|
880 |
|
---|
881 | \l{Qt Demonstrations}{Demonstrations} are similar to examples except that no
|
---|
882 | walkthrough is provided for the code. Demonstrations are typically more
|
---|
883 | feature rich than examples.
|
---|
884 |
|
---|
885 | \list
|
---|
886 | \o The \bold Interview demonstration shows the same model and
|
---|
887 | selection being shared between three different views.
|
---|
888 | \o The \bold Spreadsheet demonstration illustrates the use of a
|
---|
889 | table view as a spreadsheet, using custom delegates to render
|
---|
890 | each item according to the type of data it contains.
|
---|
891 | \endlist
|
---|
892 |
|
---|
893 | A \l{Model/View Programming}{reference document} for model/view technology
|
---|
894 | is also available.
|
---|
895 | */
|
---|
896 |
|
---|
897 | /*!
|
---|
898 | \page modelview-part2-main-cpp.html
|
---|
899 | \title main.cpp
|
---|
900 | \quotefile tutorials/modelview/1_readonly/main.cpp
|
---|
901 | */
|
---|