qt5-入门-ModelView架构1

参考:

Qt model-view 架构_w3cschool

https://www.w3cschool.cn/learnroadqt/vtxz1j4y.html

QListWidget_w3cschool

https://www.w3cschool.cn/learnroadqt/yb2k1j51.html

C++ GUI Programming with Qt 4, Second Edition

本地环境:

win10专业版,64位,Qt 5.12


目录

MVC在Qt中的实现是ModelView。其中model类似MVC中的model,但是view是view+delegate,就是对每种视图,Qt都提供了一个默认的代理。代理其实类似controller,负责渲染item和同步。

可以给一个model注册多个view,让这些view以不同的显示方式显示同一组数据,当model修改时,Qt自动同步这些view。如果数据很少,可以不用model,只用item view类 ,也就是QListWidget,QTableWidget,QTreeWidget,这些可以直接对item进行操作。如果数据很大,需要使用view类 ,如QListView,QTableView和QTreeView,同时需要提供一个model(可以是预制的也可以是自定义的)。

item view

是Qt封装好了的一些model-view类。易于使用但功能简单,同时缺少实时性支持。包括QListWidget,QTableWidget,QTreeWidget。前两个会给出实例,最后一个等用到了我再补。

QListWidget

效果:

实现

创建一个没有底部按钮的对话框,包含一个QListWidget类型的私有变量:

cpp 复制代码
QListWidget *faqListWidget;

然后修改构造函数即可:

cpp 复制代码
FAQDialog::FAQDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::FAQDialog)
{
    ui->setupUi(this);
	// 实例化
    faqListWidget = new QListWidget;
    // source
    QStringList faqList = {tr("xxxx收费吗?"),
                           // 若干行内容
                           tr("您可以联系在线客服。我们非常期待您的建议,希望能给您带来更好的产品和体验。")};
    int listWidgetRows = faqList.length();
    for (int i = 0; i < listWidgetRows; i++) {
        if (i % 2 == 1) {
            // 自定义的格式,省略
        } else {
        	// 如果省略第一个参数,就没有前面的icon啦
            QListWidgetItem* item = new QListWidgetItem(QIcon("://resources/icon/help.png"), faqList[i]);
            item->setTextColor(QColor("#xxxxxx"));
            // 如果要指定字体,使用这种方式
            //item->setFont(QFont("Arial", 10));
            
            QFont myfont;
            myfont.setBold(false);
            // 如果不希望修改字体,只想修改字号
            myfont.setPointSize(10);
            item->setFont(myfont);
            // 添加
            faqListWidget->addItem(item);
        }
    }
    // 自动换行
    faqListWidget->setWordWrap(true);
    QHBoxLayout *layout = new QHBoxLayout;
    layout->addWidget(faqListWidget);
    setLayout(layout);
}

QTableWidget

这里写过:

qt5-入门-QTableWidget简单使用-CSDN博客

https://blog.csdn.net/pxy7896/article/details/136727852

model view

  • model更新的时候会自动更新view
  • model一般是数据集合,可以为不同的业务建立不同的model
  • Qt预定义了一些model,如QStringListModelQDirModelQSOrtFilterProxyModel
  • view大致有list、tree和table

QStringListModel

效果

有三个按钮,点击新增:

增加一个e:

删除Letter C:

点击Show展示所有数据:

实现

头文件:

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStringListModel>
#include <QListView>
#include <QWidget>

namespace Ui {
class MainWindow;
}

class MainWindow : public QWidget
{
    Q_OBJECT

public:
    MainWindow();
    ~MainWindow();

private slots:
    void insertData();
    void delData();
    void showData();

private:
    QStringListModel *model;
    QListView *listView;
};

#endif // MAINWINDOW_H

源文件说明:

  • listView->currentIndex()是获取QListView当前行,但是返回值是QModelIndex类型,这个类型保存了行、列和属于哪个model。
  • insertRows(row, 1)是在哪行(row),插入几次(1)
  • model->setData(index, text);第一个参数是QModelIndex类型
  • 插入流程:先在Model中插入空白行(insertRows(row, 1)),然后给空白行设置内容(model->setData(index, text);),再设置当前的index,最后设置这行是可以编辑的(listView->edit(index);
  • 如果model是空的,那么listView->currentIndex()的行列都是-1
cpp 复制代码
#include "mainwindow.h"
//#include "ui_mainwindow.h"

#include <QHBoxLayout>
#include <QPushButton>
#include <QInputDialog>
#include <QMessageBox>

MainWindow::MainWindow()
{

    model = new QStringListModel(this);
    QStringList data;
    data << "Letter A" << "Letter B" << "Letter C";
    model->setStringList(data);

    listView = new QListView(this);
    listView->setModel(model);

    // 布局
    QHBoxLayout *btnLayout = new QHBoxLayout;
    QPushButton *insertBtn = new QPushButton(tr("insert"), this);
    QPushButton *delBtn = new QPushButton(tr("Delete"), this);
    QPushButton *showBtn = new QPushButton(tr("Show"), this);
    btnLayout->addWidget(insertBtn);
    btnLayout->addWidget(delBtn);
    btnLayout->addWidget(showBtn);
    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(listView);
    mainLayout->addLayout(btnLayout);
    this->setLayout(mainLayout);

    // 连接
    connect(insertBtn, SIGNAL(clicked()), this, SLOT(insertData()));
    connect(delBtn, SIGNAL(clicked()), this, SLOT(delData()));
    connect(showBtn, SIGNAL(clicked()), this, SLOT(showData()));
}

MainWindow::~MainWindow()
{
}

void MainWindow::insertData() {
    bool isOK;
    QString text = QInputDialog::getText(NULL, "Insert", "Please input new data:",
                                         QLineEdit::Normal, "You are inserting new data.",
                                         &isOK);
    if(isOK) { // 如果用户点击了ok按钮
    	// 获取行
        int row = listView->currentIndex().row();
        // 第二个参数是count,1表示插入1次
        model->insertRows(row, 1);
        QModelIndex index = model->index(row);
        model->setData(index, text);
        listView->setCurrentIndex(index);
        // 表示可以被编辑
        listView->edit(index); 
    }
}

void MainWindow::delData() {
    if(model->rowCount() > 1) {
        model->removeRows(listView->currentIndex().row(), 1);
    }
}

void MainWindow::showData() {
    QStringList data = model->stringList();
    QString str;
    foreach(QString s, data) {
            str += s + "\n";
    }

    QMessageBox::information(this, "Data", str);
}

上述的代码,如果model是空的,那么无法做插入操作,因为: listView->currentIndex().row()此时为-1,那么model->insertRows(row, 1)会报错。这个显然不符合逻辑。。因此注释掉data << "Letter A" << "Letter B" << "Letter C";,修改插入和删除函数:

cpp 复制代码
void MainWindow::insertData() {
    bool isOK;
    QString text = QInputDialog::getText(NULL, "Insert", "Please input new data:",
                                         QLineEdit::Normal, "You are inserting new data.",
                                         &isOK);
    if(isOK) {
        int row = listView->currentIndex().row();
        //qDebug() << row;
        QModelIndex index;
        // 此时model其实是空的
        if (row == -1) {
            model->insertRows(0, 1);
            index = model->index(0);

        } else {
            model->insertRows(row, 1);
            index = model->index(row);
        }
        model->setData(index, text);
        listView->setCurrentIndex(index);
        listView->edit(index);
    }
}

void MainWindow::delData() {
    model->removeRows(listView->currentIndex().row(), 1);
}

done.

相关推荐
sukalot9 分钟前
windows C++-使用任务和 XML HTTP 请求进行连接(一)
c++·windows
落落落sss15 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
ぃ扶摇ぅ27 分钟前
Windows系统编程(三)进程与线程二
c++·windows
简单.is.good33 分钟前
【测试】接口测试与接口自动化
开发语言·python
Yvemil71 小时前
MQ 架构设计原理与消息中间件详解(二)
开发语言·后端·ruby
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
我是陈泽1 小时前
一行 Python 代码能实现什么丧心病狂的功能?圣诞树源代码
开发语言·python·程序员·编程·python教程·python学习·python教学
优雅的小武先生1 小时前
QT中的按钮控件和comboBox控件和spinBox控件无法点击的bug
开发语言·qt·bug
Death2001 小时前
使用Qt进行TCP和UDP网络编程
网络·c++·qt·tcp/ip
虽千万人 吾往矣1 小时前
golang gorm
开发语言·数据库·后端·tcp/ip·golang