Listing your albums with AlbumListWidget
This widget must offer a way to create a new album and display existing ones. Selecting an album must also trigger an event that will be used by other widgets to display the proper data. The AlbumListWidget component is the simplest widget in this project using the Qt View mechanism. Take the time to fully understand AlbumListWidget before jumping to the next widget.
The following screenshot shows the Form Editor view of the file, AlbumListWidget.ui:
The layout is very simple. The components are described as follows:
- The AlbumListWidget component uses a vertical layout to display the Create button above the list
- The frame component contains an attractive button
- The createAlbumButton component handles album creation
- The albumList component displays the album list
You should have recognized most of the types used here. Let us take the time to talk about the really new one: QListView. As we already saw in the previous chapter, Qt provides a Model/View architecture. This system relies on specific interfaces that you must implement to provide generic data access via your model classes. That is what we did in the project gallery-core with the AlbumModel and PictureModel classes.
It is now time to deal with the view part. The view is in charge of the presentation of the data. It will also handle user interactions like selection, drag and drop, or item editing. Fortunately, to achieve these tasks, the view is helped by other Qt classes such as QItemSelectionModel, QModelIndex, or QStyledItemDelegate, which we will soon use in this chapter.
We can now enjoy one of the ready-to-use views offered by Qt:
- QListView: This view displays items from a model as a simple list
- QTableView: This view displays items from a model as a two-dimensional table
- QTreeView: This view displays items from a hierarchy of lists
Here, the choice is rather obvious because we want to display a list of album names. But in a more complex situation, a rule of thumb for choosing the proper view is to look for the model type; here we want to add a view for AlbumModel of type QAbstractListModel so the QListView class seems correct.
As you can see in the preceding screenshot, the createAlbumButton object has an icon. You can add one to a QPushButton class by selecting the widget property: icon | Choose resource. You can now choose a picture from the resource.qrc file.
A Qt resource file is a collection of files for embedding binary files in your application. You can store any types of file but we commonly use it to store pictures, sounds, or translation files. To create a resource file, right-click on the project name and then follow Add New | Qt | Qt Resource File. Qt Creator will create a default file, resource.qrc, and add this line in your file gallery-desktop.pro:
RESOURCES += resource.qrc
The resource file can be mainly displayed in two ways: Resource Editor and Plain Text Editor. You can choose an editor with by right-clicking on the resource file and selecting Open With.
The Resource Editor is a visual editor that helps you to easily add and remove files in your resource file, as shown in the following screenshot:
The Plain Text Editor will display this XML-based file resource.qrc like this:
<RCC> <qresource prefix="/"> <file>icons/album-add.png</file> <file>icons/album-delete.png</file> <file>icons/album-edit.png</file> <file>icons/back-to-gallery.png</file> <file>icons/photo-add.png</file> <file>icons/photo-delete.png</file> <file>icons/photo-next.png</file> <file>icons/photo-previous.png</file> </qresource> </RCC>
At the build time, qmake and rcc (Qt Resource Compiler) embed your resources into the application binary.
Now that the form part is clear, we can analyze the AlbumListWidget.h file:
#include <QWidget> #include <QItemSelectionModel> namespace Ui { class AlbumListWidget; } class AlbumModel; class AlbumListWidget : public QWidget { Q_OBJECT public: explicit AlbumListWidget(QWidget *parent = 0); ~AlbumListWidget(); void setModel(AlbumModel* model); void setSelectionModel(QItemSelectionModel* selectionModel); private slots: void createAlbum(); private: Ui::AlbumListWidget* ui; AlbumModel* mAlbumModel; };
The setModel() and setSelectionModel()functions are the most important lines in this snippet. This widget require two things to work correctly:
- AlbumModel: This is the model class that provides access to data. We already created this class in the gallery-core project.
- QItemSelectionModel: This is a Qt class that handles the selection in a view. By default, views use their own selection model. Sharing the same selection model with different views or widgets will help us to synchronize album selection easily.
This is the main part of AlbumListWidget.cpp:
#include "AlbumListWidget.h" #include "ui_AlbumListWidget.h" #include <QInputDialog> #include "AlbumModel.h" AlbumListWidget::AlbumListWidget(QWidget *parent) : QWidget(parent), ui(new Ui::AlbumListWidget), mAlbumModel(nullptr) { ui->setupUi(this); connect(ui->createAlbumButton, &QPushButton::clicked, this, &AlbumListWidget::createAlbum); } AlbumListWidget::~AlbumListWidget() { delete ui; } void AlbumListWidget::setModel(AlbumModel* model) { mAlbumModel = model; ui->albumList->setModel(mAlbumModel); } void AlbumListWidget::setSelectionModel(QItemSelectionModel* selectionModel) { ui->albumList->setSelectionModel(selectionModel); }
The two setters will mainly be used to set the model and the selection model of the albumList. Our QListView class will then automatically request the model (AlbumModel) to get the row count and the Qt::DisplayRole (the album's name) for each one of them.
Let's now see the last part of the AlbumListWidget.cpp file that handles the album creation:
void AlbumListWidget::createAlbum() { if(!mAlbumModel) { return; } bool ok; QString albumName = QInputDialog::getText(this, "Create a new Album", "Choose an name", QLineEdit::Normal, "New album", &ok); if (ok && !albumName.isEmpty()) { Album album(albumName); QModelIndex createdIndex = mAlbumModel->addAlbum(album); ui->albumList->setCurrentIndex(createdIndex); } }
We already worked with the QInputDialog class. This time we are using it to ask the user to enter an album's name. Then we create an Album class with the requested name. This object is just a "data holder;" addAlbum() will use it to create and store the real object with a unique ID.
The function addAlbum() returns us the QModelIndex value corresponding to the created album. From here, we can request the list view to select this new album.