当前位置:网站首页>Introduction to the usage of model view delegate principal-agent mechanism in QT
Introduction to the usage of model view delegate principal-agent mechanism in QT
2022-07-06 17:59:00 【Manon Feifei】
List of articles
In a previous article QT The principal-agent mechanism , At that time, because of the shallow understanding, I simply gave an example . Recently, I have done some related work , I found that there was something wrong with my previous understanding . Here is a detailed introduction QT The usage of the principal-agent mechanism , Hopefully that helped .
Model-View-Delegate The mechanism can be simply understood as taking some local data as specific UI The form comes out . Common data structures include list data (list)、 Tabular data (table)、 Tree data (tree), Corresponding to QT Medium QListView、QTableView、QTreeView Control . The relationship between local data and view agents is shown in the following figure :
The data source in the data model can be local XML file 、JSON file 、 binary data , You can also use the data table in the database . The data in these data sources are loaded into the corresponding data model according to a certain structure , We can indirectly manipulate the data in the data source by manipulating the data in the data model .
occasionally , We need to re process the data in the data model , Including data filtering 、 Data sorting 、 Data processing and so on , At this time, we need to introduce model proxy , Be responsible for processing the data model . Of course, model proxy is not necessary .QT There are two kinds of model agents in QAbstractProxyModel Subclasses of . Namely QIdentityProxyModel and QSortFilterProxyModel.
QIdentityProxyModel The agent will not modify the original data model , It's just rewritten data() function , The data returned to the view is recombined and modified .
QSortFilterProxyModel The agent will filter and sort the data of the model .
With these two proxy classes , We can process the data in the model .
After the data model is loaded ,View The layer will present the data in the data model . Because the data in the data model exists in data units , We can specify the corresponding UI. This uses the principal-agent Delegate, Delegate controls can assign fixed to each element in the data model UI. Through the principal-agent mechanism , We can present local data in a personalized graphical interface .
Here is a detailed example , Let's explain the usage of the principal-agent mechanism . The main function of the example is to manage local image files in the form of thumbnails , Similar to a picture manager .
Local data loading (Data)
The image data in the example mainly contains two fields , A field is a picture ID, Another field is the image URL. The corresponding data structure is as follows :
//Picture
class Picture
{
public:
Picture(const QString & filePath = "")
{
mPictureUrl = QUrl::fromLocalFile(filePath);
}
Picture(const QUrl& fileUrl)
{
mPictureUrl = fileUrl;
}
int pictureId() const
{
return mPictureId;
}
void setPictureId(int pictureId)
{
mPictureId = pictureId;
}
QUrl pictureUrl() const
{
return mPictureUrl;
}
void setPictureUrl(const QUrl &pictureUrl)
{
mPictureUrl = pictureUrl;
}
private:
int mPictureId; // picture ID
QUrl mPictureUrl; // The address of the picture
};
Because there may be a lot of local image data , In order to facilitate the management of a large number of image data , Here we use SQLITE The database will locally persist the image information . First , We create a new database management class , Manage database connections .
//DatabaseManager.h
#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H
#include <memory>
#include <QString>
#include "PictureDao.h"
class QSqlQuery;
class QSqlDatabase;
const QString DATABASE_FILENAME = "picture.db";
class DatabaseManager
{
public:
static void debugQuery(const QSqlQuery& query);
// Database management class is singleton mode
static DatabaseManager& instance();
~DatabaseManager();
protected:
// Used to build a fixed name database
DatabaseManager(const QString& path = DATABASE_FILENAME);
DatabaseManager& operator=(const DatabaseManager& rhs);
private:
std::unique_ptr<QSqlDatabase> mDatabase;
public:
// Image data operation class
const PictureDao mpictureDao;
};
#endif // DATABASEMANAGER_H
//DatabaseManager.cpp
#include "DatabaseManager.h"
#include <QSqlDatabase>
#include <QDebug>
#include <QSqlError>
#include <QSqlQuery>
void DatabaseManager::debugQuery(const QSqlQuery& query)
{
if (query.lastError().type() == QSqlError::ErrorType::NoError) {
qDebug() << "Query OK:" << query.lastQuery();
} else {
qWarning() << "Query KO:" << query.lastError().text();
qWarning() << "Query text:" << query.lastQuery();
}
}
DatabaseManager&DatabaseManager::instance()
{
static DatabaseManager singleton;
return singleton;
}
DatabaseManager::DatabaseManager(const QString& path) :
mDatabase(new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE"))),
mpictureDao(*mDatabase)
{
mDatabase->setDatabaseName(path);
bool openStatus = mDatabase->open();
qDebug() << "Database connection: " << (openStatus ? "OK" : "Error");
mpictureDao.init();
}
DatabaseManager::~DatabaseManager()
{
mDatabase->close();
}
After creating the database management class , We need to add the database access object of the image data table , The visiting object is responsible for the basic operations such as adding, deleting, modifying and checking the picture data table , The corresponding implementation is as follows :
//PictureDao.h
#ifndef PICTUREDAO_H
#define PICTUREDAO_H
#include <memory>
#include <vector>
class QSqlDatabase;
class Picture;
class PictureDao
{
public:
explicit PictureDao(QSqlDatabase& database);
void init() const;
// Add images
void addPicture(Picture& picture) const;
// Delete pictures
void removePicture(int id) const;
// Loading pictures
std::unique_ptr<std::vector<std::unique_ptr<Picture>>> loadPictures() const;
// Delete all data
void removeAllPictures() const;
private:
QSqlDatabase& mDatabase;
};
#endif // PICTUREDAO_H
//PictureDao.cpp
#include "PictureDao.h"
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QVariant>
#include "DatabaseManager.h"
#include "picturemodel.h"
using namespace std;
PictureDao::PictureDao(QSqlDatabase& database) :
mDatabase(database)
{
}
void PictureDao::init() const
{
if (!mDatabase.tables().contains("pictures")) {
QSqlQuery query(mDatabase);
query.exec(QString("CREATE TABLE pictures")
+ " (id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ "url TEXT)");
DatabaseManager::debugQuery(query);
}
}
void PictureDao::addPicture(Picture& picture) const
{
QSqlQuery query(mDatabase);
query.prepare(QString("INSERT INTO pictures")
+ " (url)"
+ " VALUES ("
+ ":url"
+ ")");
query.bindValue(":url", picture.pictureUrl());
query.exec();
DatabaseManager::debugQuery(query);
picture.setPictureId(query.lastInsertId().toInt());
}
void PictureDao::removePicture(int id) const
{
QSqlQuery query(mDatabase);
query.prepare("DELETE FROM pictures WHERE id = (:id)");
query.bindValue(":id", id);
query.exec();
DatabaseManager::debugQuery(query);
}
unique_ptr<vector<unique_ptr<Picture>>> PictureDao::loadPictures() const
{
QSqlQuery query(mDatabase);
query.prepare("SELECT * FROM pictures");
query.exec();
DatabaseManager::debugQuery(query);
unique_ptr<vector<unique_ptr<Picture>>> list(new vector<unique_ptr<Picture>>());
while(query.next()) {
unique_ptr<Picture> picture(new Picture());
picture->setPictureId(query.value("id").toInt());
picture->setPictureUrl(query.value("url").toString());
list->push_back(move(picture));
}
return list;
}
void PictureDao::removeAllPictures() const
{
QSqlQuery query(mDatabase);
query.prepare("DELETE FROM pictures WHERE 1=1");
query.exec();
DatabaseManager::debugQuery(query);
}
After building the data access layer , Our application has the ability to operate on the underlying raw data . This is the basic ability of application .
Add data model (Model)
After completing the data operation class , Next, we need to build the corresponding data model . Since there is no correlation between image information, the method used here is based on QAbstractListModel List data model , The corresponding implementation is as follows :
//picturemodel.h
#ifndef PICTUREMODEL_H
#define PICTUREMODEL_H
#include <memory>
#include <vector>
#include <QAbstractListModel>
#include <QUrl>
#include "DatabaseManager.h"
class PictureModel : public QAbstractListModel
{
Q_OBJECT
public:
// Customize the data type of each element
enum Roles {
UrlRole = Qt::UserRole + 1,
FilePathRole
};
PictureModel(QObject* parent = 0);
// Add individual data to the data model
QModelIndex addPicture(const Picture& picture);
Q_INVOKABLE void addPictureFromUrl(const QUrl& fileUrl);
// Number of rows of the model
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
// Get the data of an element
QVariant data(const QModelIndex& index, int role) const override;
// Delete some rows of data
Q_INVOKABLE bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
// The name of each element category
QHash<int, QByteArray> roleNames() const override;
// Load user pictures
Q_INVOKABLE void loadPictures();
// Clear the data in the model , But do not remove local file data
void clearPictures();
public slots:
// Empty the model , Delete the data in the local file
void deleteAllPictures();
private:
void resetPictures();
bool isIndexValid(const QModelIndex& index) const;
private:
DatabaseManager& mDatabase;
std::unique_ptr<std::vector<std::unique_ptr<Picture>>> mPictures;
};
#endif // PICTUREMODEL_H
//picturemodel.cpp
#include "picturemodel.h"
#include <QUrl>
using namespace std;
PictureModel::PictureModel(QObject* parent) :
QAbstractListModel(parent),
mPictures(new vector<unique_ptr<Picture>>()),
mDatabase(DatabaseManager::instance())
{
}
QModelIndex PictureModel::addPicture(const Picture& picture)
{
int rows = rowCount();
beginInsertRows(QModelIndex(), rows, rows);
unique_ptr<Picture>newPicture(new Picture(picture));
mDatabase.mpictureDao.addPicture(*newPicture);
mPictures->push_back(move(newPicture));
endInsertRows();
return index(rows, 0);
}
void PictureModel::addPictureFromUrl(const QUrl& fileUrl)
{
addPicture(Picture(fileUrl));
}
int PictureModel::rowCount(const QModelIndex& /*parent*/) const
{
return mPictures->size();
}
QVariant PictureModel::data(const QModelIndex& index, int role) const
{
if (!isIndexValid(index))
{
return QVariant();
}
const Picture& picture = *mPictures->at(index.row());
switch (role) {
// The display data is the name of the picture
case Qt::DisplayRole:
return picture.pictureUrl().fileName();
break;
// The image URL
case Roles::UrlRole:
return picture.pictureUrl();
break;
// Picture address
case Roles::FilePathRole:
return picture.pictureUrl().toLocalFile();
break;
default:
return QVariant();
}
}
bool PictureModel::removeRows(int row, int count, const QModelIndex& parent)
{
if (row < 0
|| row >= rowCount()
|| count < 0
|| (row + count) > rowCount()) {
return false;
}
beginRemoveRows(parent, row, row + count - 1);
int countLeft = count;
while(countLeft--) {
const Picture& picture = *mPictures->at(row + countLeft);
mDatabase.mpictureDao.removePicture(picture.pictureId());
}
mPictures->erase(mPictures->begin() + row,
mPictures->begin() + row + count);
endRemoveRows();
return true;
}
QHash<int, QByteArray> PictureModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "name";
roles[Roles::FilePathRole] = "filepath";
roles[Roles::UrlRole] = "url";
return roles;
}
void PictureModel::loadPictures()
{
beginResetModel();
mPictures = mDatabase.mpictureDao.loadPictures();
endResetModel();
}
void PictureModel::clearPictures()
{
resetPictures();
}
void PictureModel::resetPictures()
{
beginResetModel();
mPictures.reset(new vector<unique_ptr<Picture>>());
endResetModel();
return;
}
void PictureModel::deleteAllPictures()
{
mDatabase.mpictureDao.removeAllPictures();
resetPictures();
}
bool PictureModel::isIndexValid(const QModelIndex& index) const
{
if (index.row() < 0
|| index.row() >= rowCount()
|| !index.isValid()) {
return false;
}
return true;
}
QT Allow developers to target each data unit in the data model ModelIndex Define different data roles . Simply speaking , Each data unit can provide various types of data for external use . Here we define UrlRole and FilePathRole Each represents the image URL And the address of the picture .
Add proxy model (Proxy)
Model agent is the secondary processing of the data in the original model , Including sorting, filtering and other operations . The model agent cannot directly modify the data in the model , It is only responsible for the secondary processing of the data in the data model . At the same time, model proxy is not necessary , We can also interact directly with the original data model and view . The corresponding implementation of the model proxy is as follows :
//picproxymodel.h
#ifndef PICTURE_PROXY_MODEL_H
#define PICTURE_PROXY_MODEL_H
#include <QIdentityProxyModel>
#include <QHash>
#include <QPixmap>
class PictureModel;
class PictureProxyModel : public QIdentityProxyModel
{
public:
PictureProxyModel(QObject* parent = 0);
// By rewriting data The interface performs secondary processing of data
QVariant data(const QModelIndex& index, int role) const override;
// Set get source data model
void setSourceModel(QAbstractItemModel* sourceModel) override;
PictureModel* pictureModel() const;
private:
// Reload thumbnails
void reloadPictures();
// Generate thumbnails
void generatePictures(const QModelIndex& startIndex, int count);
private:
QHash<QString, QPixmap*>mPictureHashMaps;
};
#endif
//picproxymodel.cpp
#include "picproxymodel.h"
#include "PictureModel.h"
const unsigned int PICTURE_SIZE = 350;
PictureProxyModel::PictureProxyModel(QObject* parent) :
QIdentityProxyModel(parent),
mPictureHashMaps()
{
}
QVariant PictureProxyModel::data(const QModelIndex& index, int role) const
{
// Second process the data in the original data model
// For the front end to call
if (role != Qt::DecorationRole) {
return QIdentityProxyModel::data(index, role);
}
QString filepath = sourceModel()->data(index, PictureModel::Roles::FilePathRole).toString();
return *mPictureHashMaps[filepath];
}
void PictureProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
{
QIdentityProxyModel::setSourceModel(sourceModel);
if (!sourceModel) {
return;
}
connect(sourceModel, &QAbstractItemModel::modelReset, [this] {
reloadPictures();});
connect(sourceModel, &QAbstractItemModel::rowsInserted, [this](const QModelIndex& /*parent*/, int first, int last) {
generatePictures(index(first, 0), last - first + 1);
});
}
PictureModel* PictureProxyModel::pictureModel() const
{
return static_cast<PictureModel*>(sourceModel());
}
void PictureProxyModel::reloadPictures()
{
qDeleteAll(mPictureHashMaps);
mPictureHashMaps.clear();
generatePictures(index(0, 0), rowCount());
}
void PictureProxyModel::generatePictures(const QModelIndex& startIndex, int count)
{
if (!startIndex.isValid()) {
return;
}
const QAbstractItemModel* model = startIndex.model();
int lastIndex = startIndex.row() + count;
for(int row = startIndex.row(); row < lastIndex; row++) {
QString filepath = model->data(model->index(row, 0), PictureModel::Roles::FilePathRole).toString();
QPixmap pixmap(filepath);
auto thumbnail = new QPixmap(pixmap.scaled(PICTURE_SIZE, PICTURE_SIZE,Qt::KeepAspectRatio,
Qt::SmoothTransformation));
mPictureHashMaps.insert(filepath, thumbnail);
}
}
Add a proxy for the element (Delegate)
Element proxy is the corresponding of each element in the data table UI, We use custom controls to render the corresponding data . Here we use QStyledItemDelegate instead of QItemDelegate, Because QStyledItemDelegate Support the operation of style sheets , and QItemDelegate I won't support it , The corresponding implementation is as follows :
//picturedelegate.h
#ifndef PICTUREDELEGATE_H
#define PICTUREDELEGATE_H
#include <QStyledItemDelegate>
#include <QMouseEvent>
class PictureDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
PictureDelegate(QObject* parent = 0);
// Agent's drawing event
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
// The size of the agent
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
protected:
};
#endif // PICTUREDELEGATE_H
//picturedelegate.cpp
#include "picturedelegate.h"
#include <QPainter>
// Dimension style of title block
const unsigned int LABEL_HEIGHT = 20;
const unsigned int LABEL_COLOR = 0x303030;
const unsigned int LABEL_ALPHA = 200;
const unsigned int LABEL_TEXT_COLOR = 0xffffff;
const unsigned int HIGHLIGHT_ALPHA = 100;
// The size and style of the picture
const unsigned int PIXMAP_WIDTH = 200;
const unsigned int PIXMAP_HEIGHT = 200;
PictureDelegate::PictureDelegate(QObject* parent) :
QStyledItemDelegate(parent)
{
}
void PictureDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
painter->save();
// Draw the corresponding picture
QPixmap pixmap = index.model()->data(index, Qt::DecorationRole).value<QPixmap>();
painter->drawPixmap(option.rect.x(), option.rect.y(),PIXMAP_WIDTH,PIXMAP_HEIGHT,pixmap);
// The title bar of the drawing picture shows the name of the picture
QRect bannerRect = QRect(option.rect.x(), option.rect.y(), PIXMAP_WIDTH, LABEL_HEIGHT);
QColor bannerColor = QColor(LABEL_COLOR);
bannerColor.setAlpha(LABEL_ALPHA);
painter->fillRect(bannerRect, bannerColor);
// Draw title text
QString filename = index.model()->data(index, Qt::DisplayRole).toString();
painter->setPen(LABEL_TEXT_COLOR);
painter->drawText(bannerRect, Qt::AlignCenter, filename);
// Set the color after the element is selected
if (option.state.testFlag(QStyle::State_Selected)) {
QColor selectedColor = option.palette.highlight().color();
selectedColor.setAlpha(HIGHLIGHT_ALPHA);
painter->fillRect(option.rect, selectedColor);
}
painter->restore();
}
QSize PictureDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& index) const
{
const QPixmap& pixmap = index.model()->data(index, Qt::DecorationRole).value<QPixmap>();
return QSize(PIXMAP_WIDTH,PIXMAP_HEIGHT);
}
We can also achieve QStyledItemDelegate::createEditor() Interface , To edit the data in each element proxy , I won't go into details here , It was written in the previous article .
Add view layer (View)
After perfecting the data model and element proxy , The corresponding view layer operation is relatively simple . In the view layer, we have added an interface to interact with users , Users can use the corresponding UI operation , Add, delete, modify and check the data in the data model . At the same time, we added menus for elements in the view , We can delete a specific element through the right-click menu .
//mylistview.h
#ifndef MYLISTVIEW_H
#define MYLISTVIEW_H
#include <QWidget>
#include <QItemSelectionModel>
#include <QMouseEvent>
#include <QMenu>
namespace Ui {
class MyListView;
}
class PictureProxyModel;
class MyListView : public QWidget
{
Q_OBJECT
public:
explicit MyListView(QWidget *parent = 0);
~MyListView();
// Set up the data model
void setPictureModel(PictureProxyModel *pictureModel);
// Set the selected data model
void setPictureSelectionModel(QItemSelectionModel *selectionModel);
private slots:
void addPictures();
void delPictures();
void clearPictures();
void delAllPicture();
void delCurrentPicture();
void showCustomMenu(const QPoint& pos);
private:
Ui::MyListView *ui;
// Picture data model
PictureProxyModel* mPictureModel;
// The data model of the selected element
QItemSelectionModel* mPictureSelectionModel;
QModelIndex mCurrentIndex;
QMenu* m_func_menu = nullptr;
QAction* m_del_current_pic = nullptr;
};
#endif // MYLISTVIEW_H
//mylistview.cpp
#pragma execution_character_set("utf-8")
#include "mylistview.h"
#include "picturedelegate.h"
#include "picproxymodel.h"
#include "ui_mylistview.h"
#include "picturemodel.h"
#include <QFileDialog>
#include <QInputDialog>
#include <QStandardPaths>
MyListView::MyListView(QWidget *parent) :
QWidget(parent),
ui(new Ui::MyListView)
{
ui->setupUi(this);
// Set the interval between elements
ui->pic_list_view->setSpacing(5);
// Set the size change strategy
ui->pic_list_view->setResizeMode(QListView::Adjust);
// Set the change mode when the element is increased or decreased
ui->pic_list_view->setFlow(QListView::LeftToRight);
// Set whether to wrap lines automatically when scaling
ui->pic_list_view->setWrapping(true);
// Set the proxy for each element
ui->pic_list_view->setItemDelegate(new PictureDelegate(this));
// Open the customized menu
ui->pic_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
// Initialize the function menu
m_func_menu = new QMenu(this);
m_del_current_pic = new QAction(" Delete the current picture ",this);
m_func_menu->addAction(m_del_current_pic);
connect(m_del_current_pic,&QAction::triggered,this,&MyListView::delCurrentPicture);
// Add, delete, modify and check the picture data
connect(ui->add_pic_btn, &QPushButton::clicked, this, &MyListView::addPictures);
connect(ui->clear_btn, &QPushButton::clicked,this, &MyListView::clearPictures);
connect(ui->del_pic_btn, &QPushButton::clicked, this, &MyListView::delPictures);
connect(ui->del_all_pic_btn,&QPushButton::clicked,this,&MyListView::delAllPicture);
connect(ui->pic_list_view,&QListView::customContextMenuRequested,this,&MyListView::showCustomMenu);
}
MyListView::~MyListView()
{
delete ui;
}
void MyListView::setPictureModel(PictureProxyModel* pictureModel)
{
mPictureModel = pictureModel;
ui->pic_list_view->setModel(pictureModel);
}
void MyListView::setPictureSelectionModel(QItemSelectionModel* selectionModel)
{
mPictureSelectionModel = selectionModel;
ui->pic_list_view->setSelectionModel(selectionModel);
}
void MyListView::addPictures()
{
QStringList filenames = QFileDialog::getOpenFileNames(this,
" Add images ",
QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
"Picture files (*.jpg *.png)");
if (!filenames.isEmpty()) {
QModelIndex lastModelIndex;
for (auto filename : filenames) {
Picture picture(filename);
lastModelIndex = mPictureModel->pictureModel()->addPicture(picture);
lastModelIndex = mPictureModel->index(lastModelIndex.row(),lastModelIndex.column());
}
if(lastModelIndex.isValid())
{
ui->pic_list_view->setCurrentIndex(lastModelIndex);
}
}
}
void MyListView::delPictures()
{
if (mPictureSelectionModel->selectedIndexes().isEmpty()) {
return;
}
int row = mPictureSelectionModel->currentIndex().row();
mPictureModel->sourceModel()->removeRow(row);
// Select the previous picture
QModelIndex previousModelIndex = mPictureModel->sourceModel()->index(row - 1, 0);
if(previousModelIndex.isValid()) {
previousModelIndex = mPictureModel->index(previousModelIndex.row(),previousModelIndex.column());
mPictureSelectionModel->setCurrentIndex(previousModelIndex, QItemSelectionModel::SelectCurrent);
return;
}
// Select the next picture
QModelIndex nextModelIndex = mPictureModel->sourceModel()->index(row, 0);
if(nextModelIndex.isValid()) {
nextModelIndex = mPictureModel->index(nextModelIndex.row(),nextModelIndex.column());
mPictureSelectionModel->setCurrentIndex(nextModelIndex, QItemSelectionModel::SelectCurrent);
return;
}
}
void MyListView::clearPictures()
{
PictureModel* pic_model = (PictureModel*)mPictureModel->sourceModel();
pic_model->clearPictures();
}
void MyListView::delAllPicture()
{
PictureModel* pic_model = (PictureModel*)mPictureModel->sourceModel();
pic_model->deleteAllPictures();
}
void MyListView::delCurrentPicture()
{
if(mCurrentIndex.isValid())
{
PictureModel* pic_model = (PictureModel*)mPictureModel->sourceModel();
pic_model->removeRow(mCurrentIndex.row());
}
}
void MyListView::showCustomMenu(const QPoint &pos)
{
QPoint point = pos;
mCurrentIndex = ui->pic_list_view->indexAt(pos);
if(mCurrentIndex.isValid() && mCurrentIndex.row() >= 0)
{
m_func_menu->exec(ui->pic_list_view->mapToGlobal(point));
}
}
After perfecting the list view , We can use the main interface , Added view control , This is also UI The last step of the layer , The corresponding implementation is as follows :
//mainwwindow.h
#ifndef MAINWWINDOW_H
#define MAINWWINDOW_H
#include <QWidget>
#include "mylistview.h"
namespace Ui {
class MainwWindow;
}
class MainwWindow : public QWidget
{
Q_OBJECT
public:
explicit MainwWindow(QWidget *parent = 0);
~MainwWindow();
private:
MyListView* mListView=nullptr;
};
#endif // MAINWWINDOW_H
//mainwwindow.cpp
#include "mainwwindow.h"
#include "ui_mainwwindow.h"
#include "picturemodel.h"
#include "picproxymodel.h"
#include <QHBoxLayout>
MainwWindow::MainwWindow(QWidget *parent) :
QWidget(parent)
{
mListView = new MyListView(this);
PictureModel* pic_model = new PictureModel(this);
PictureProxyModel* pic_proxy_model = new PictureProxyModel(this);
pic_proxy_model->setSourceModel(pic_model);
QItemSelectionModel* pictureSelectionModel = new QItemSelectionModel(pic_proxy_model, this);
mListView->setPictureModel(pic_proxy_model);
mListView->setPictureSelectionModel(pictureSelectionModel);
pic_model->loadPictures();
QHBoxLayout* main_layout = new QHBoxLayout(this);
main_layout->addWidget(mListView);
this->setLayout(main_layout);
this->setFixedSize(910,600);
}
MainwWindow::~MainwWindow()
{
}
Use effect
边栏推荐
- ASEMI整流桥DB207的导通时间与参数选择
- Basic configuration and use of spark
- Jielizhi obtains the customized background information corresponding to the specified dial [chapter]
- 78 year old professor Huake has been chasing dreams for 40 years, and the domestic database reaches dreams to sprint for IPO
- 视频融合云平台EasyCVR增加多级分组,可灵活管理接入设备
- Getting started with pytest ----- test case pre post, firmware
- C语言指针*p++、*(p++)、*++p、*(++p)、(*p)++、++(*p)对比实例
- MySQL stored procedure
- adb常用命令
- How to output special symbols in shell
猜你喜欢
78 year old professor Huake has been chasing dreams for 40 years, and the domestic database reaches dreams to sprint for IPO
Reppoints: advanced order of deformable convolution
Distinguish between basic disk and dynamic disk RAID disk redundant array
C语言指针*p++、*(p++)、*++p、*(++p)、(*p)++、++(*p)对比实例
C语言通过指针交换两个数
Interview shock 62: what are the precautions for group by?
编译原理——预测表C语言实现
ASEMI整流桥DB207的导通时间与参数选择
How to solve the error "press any to exit" when deploying multiple easycvr on one server?
node の SQLite
随机推荐
C语言指针*p++、*(p++)、*++p、*(++p)、(*p)++、++(*p)对比实例
Summary of Android interview questions of Dachang in 2022 (II) (including answers)
Guidelines for preparing for the 2022 soft exam information security engineer exam
EasyCVR电子地图中设备播放器loading样式的居中对齐优化
Selected technical experts from China Mobile, ant, SF, and Xingsheng will show you the guarantee of architecture stability
Heavy! Ant open source trusted privacy computing framework "argot", flexible assembly of mainstream technologies, developer friendly layered design
STM32按键状态机2——状态简化与增加长按功能
Debug xv6
1700C - Helping the Nature
The latest financial report release + tmall 618 double top, Nike energy leads the next 50 years
Solid principle
10 advanced concepts that must be understood in learning SQL
Scratch epidemic isolation and nucleic acid detection Analog Electronics Society graphical programming scratch grade examination level 3 true questions and answers analysis June 2022
STM32 key state machine 2 - state simplification and long press function addition
李書福為何要親自掛帥造手機?
Pytorch extract middle layer features?
Video fusion cloud platform easycvr adds multi-level grouping, which can flexibly manage access devices
8位MCU跑RTOS有没有意义?
Four processes of program operation
How to use scroll bars to dynamically adjust parameters in opencv