Ever faced a situation where you have to “stuff” the same dataset into multiple widgets—and suddenly your app starts bloating in memory while synchronization becomes a headache? This is especially noticeable with file systems and any “heavy” sources: duplication grows, bugs multiply, and changes to data storage logic trigger a cascade of fixes.
This chapter will reveal why Qt’s “interview” approach (model/view) isn’t just a textbook pattern, but a practical tool professional developers use to save performance and architecture. Here you’ll discover a non-obvious secret: how to separate data from display so you can change storage with minimal pain—while getting clean, test-friendly code.
We’ll cover 4 key components (model, view, selection, delegate), working with QModelIndex and roles (DisplayRole/ToolTipRole/DecorationRole), plus sorting/filtering via QSortFilterProxyModel. Plus—practical examples: sharing selection among 3 views, custom delegate with highlighting, and a mini file system browser on QFileSystemModel.
If model-view still seems like “complex magic”—skipping this chapter means continuing to pay with time and memory on every other project.
This chapter includes ready-to-use code examples.
Chapter Self-Check
Why is the “interview” technique more efficient than the item-oriented approach when working with databases and large volumes of information?Answer
Correct answer: Data isn’t duplicated when using multiple views—all views work with one data model through an interface. This saves memory and automatically solves synchronization problems.
Which two methods must be implemented when creating your own model based on QAbstractListModel?Answer
Correct answer: Methods rowCount() (returns row count) and data() (returns data for given index and role). Without them, the model can’t provide data to views.
What’s a proxy model and why is it needed?Answer
Correct answer: It’s a model between the source model and view, allowing sorting and filtering without changing the original model. QSortFilterProxyModel class is a ready-made implementation for these tasks.
Why is it necessary to emit the dataChanged() signal when changing data via setData() method?Answer
Correct answer: The signal notifies all connected views that data has changed and they should update their content. Without this signal, changes won’t appear in the interface.
What three parts make up a model index (QModelIndex)?Answer
Correct answer: Row, column, and internal identifier. This allows addressing cells in hierarchical tables where the internal identifier points to the parent element.
Why do you need to call beginInsertRows() and endInsertRows() when inserting rows into a model?Answer
Correct answer: These methods notify all connected views and other objects about the start and completion of model changes, allowing them to correctly update their state and avoid display errors.
What role does a delegate play in model-view architecture, and which method needs to be overloaded to change item appearance?Answer
Correct answer: The delegate handles drawing each item and its editing. To change appearance, overload the paint() method, which receives QPainter and display parameters.
How do you make model items editable by users?Answer
Correct answer: Implement the setData() method to save changes and override the flags() method so it returns the Qt::ItemIsEditable flag for valid indexes.
Why does the rowCount() method for a list model need to return 0 if parent.isValid() equals true?Answer
Correct answer: A list model (QAbstractListModel) is one-dimensional by definition and shouldn’t have child elements. A valid parent index indicates an attempt to get child elements that shouldn’t exist.
What advantages does centralized selection management via QItemSelectionModel provide?Answer
Correct answer: Allows sharing the selection mechanism among multiple views of one model—selecting an item in one view automatically reflects in all others. Selection management code is in one place.
What are item roles used for (e.g., Qt::DisplayRole, Qt::EditRole)?Answer
Correct answer: Roles allow each model item to store different data types for different purposes: text for display, value for editing, icon, background color, tooltip, etc.
When should you use QStandardItemModel instead of creating your own model?Answer
Correct answer: When working with small amounts of data and it’s more convenient to store data directly in the model. This is a compromise solution that contradicts the model-view idea but is practical for simple applications.
How can you access the built-in model of an item-oriented widget QListWidget and why might this be needed?Answer
Correct answer: Call the model() method, which returns a pointer to the built-in model. This allows sharing QListWidget data with other views without duplication.
Hands-On Assignments
Easy Level
Task List with Shared Views
Create a task list application using QStringListModel. Display this model simultaneously in QListView and QTableView. Add 5 initial tasks. Ensure that selecting an item in one view automatically selects it in the other.
Hints: Use QStringListModel and the setStringList() method to initialize data. Create a QItemSelectionModel and set it in both views using setSelectionModel(). Don’t forget to set the model in both views via setModel().
Medium Level
Contacts Model with Filtering
Create an application with a contacts model (people’s names). Use QStringListModel with 10-15 names. Add a QLineEdit for filter input and two QListView views: one shows all contacts, the other—only filtered ones. When entering text in QLineEdit, the second view should show only names containing the entered text.
Hints: Use QSortFilterProxyModel for filtering. Create an original QStringListModel and a proxy model linked to it via setSourceModel(). Connect the textChanged() signal from QLineEdit to the setFilterWildcard() or setFilterRegularExpression() slot of the proxy model.
Hard Level
Custom Student Model with Grades
Create your own table model based on QAbstractTableModel for storing student information: name, age, and GPA. The model should support editing all fields. Implement methods data(), setData(), rowCount(), columnCount(), headerData(), and flags(). Add the ability to insert new rows via button. Display the model in QTableView with a custom delegate that highlights rows of students with GPA above 4.5 in green background.
Hints: Store data in QVector> or create a Student structure. In data() method, handle Qt::DisplayRole and Qt::EditRole roles. For editing, return Qt::ItemIsEditable in flags(). Implement insertRows() with beginInsertRows()/endInsertRows() calls. For delegate, inherit from QStyledItemDelegate and overload the paint() method, checking GPA value via index.data().
💬 Join the Discussion!
Figured out model-view architecture? Managed to create your first model based on QAbstractListModel or QAbstractTableModel?
Have questions about when to use proxy models, how to properly work with item roles, or how to implement a custom delegate?
Share your experience: What problems have you solved using model-view? Did you encounter issues when creating custom models? Which patterns proved most useful in your practice?
Your questions and discoveries help other readers better master this powerful Qt technology!