当前位置:网站首页>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


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 :
 Insert picture description here

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

 Insert picture description here

原网站

版权声明
本文为[Manon Feifei]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207060958206255.html