参考:
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
目录
- [item view](#item view)
- [model view](#model view)
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,如
QStringListModel
、QDirModel
和QSOrtFilterProxyModel
- 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.