模型、视图和代理之间使用信号和槽通信
继承关系
QAbstractItemmodel
QAbstractListModel
QStringListModel
QAbstractProxyModel
QSortFilterProxyModel
QAbstractTableModel
QSqlQueryModel
QSlTableModel
QSlRelationTableModel
QStandardItemModel
QFileSystemModel
显示数据时,只需要调用视图类的setModel()函数
QAbstractItemView
QListView
QListWidget
QTableView
QTableWidget
QTreeView
QTreeWidget
QColumnView
QHeaderView
代理时在视图组件上为编辑数据提供编辑器,QAbstractItemDeleget是所有代理类的基类。
如Windows则资源管理器,使用QFileSystemModel童工的接口函数,可以创建目录、删除目录、重命名目录,可以获得文件名称、目录名称、文件大小等参数,还可以获取文件的详细信息。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
fileModel = new QFileSystemModel(this);
fileModel->setRootPath(QDir::currentPath());
ui->treeView->setModel(fileModel);
ui->listView->setModel(fileModel);
ui->tableView->setModel(fileModel);
ui->tableView->verticalHeader()->setVisible(false);
connect(ui->treeView, SIGNAL(clicked(QModelIndex)), ui->listView,
SLOT(setRootIndex(QModelIndex)));
connect(ui->treeView, SIGNAL(clicked(QModelIndex)), ui->tableView,
SLOT(setRootIndex(QModelIndex)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
ui->labelName->setText(fileModel->fileName(index));
unsigned int sz = fileModel->size(index)/1024;
if(sz < 1024){
ui->labelSize->setText(QString::asprintf("%d KB", sz));
}
else{
ui->labelSize->setText(QString::asprintf("%.2f MB", (float)sz/1024));
}
ui->labelType->setText(fileModel->type(index));
ui->labelPath->setText(fileModel->filePath(index));
ui->checkBox->setChecked(fileModel->isDir(index));
}
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
theModel = new QStringListModel(this);
QStringList strList;
strList<<"Item1"<<"Item2"<<"Item3"<<"Item4"<<"Item5"<<"Item6";
theModel->setStringList(strList);
ui->listView->setModel(theModel);
// 编辑:双击或者选择项单击
ui->listView->setEditTriggers(QAbstractItemView::DoubleClicked|
QAbstractItemView::SelectedClicked);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnDisplay_clicked()
{
QStringList strList = theModel->stringList();
foreach (auto str, strList) {
ui->plainTextEdit->appendPlainText(str);
}
}
void Widget::on_btnClear_clicked()
{
ui->plainTextEdit->clear();
}
void Widget::on_btnInitList_clicked()
{
QStringList strList;
strList<<"Item1"<<"Item2"<<"Item3"<<"Item4"<<"Item5"<<"Item6";
theModel->setStringList(strList);
}
void Widget::on_btnListClear_clicked()
{
theModel->removeRows(0, theModel->rowCount());
}
void Widget::on_btnListDelete_clicked()
{
theModel->removeRow(ui->listView->currentIndex().row());
}
void Widget::on_btnListAppend_clicked()
{
theModel->insertRow(theModel->rowCount());
QModelIndex index = theModel->index(theModel->rowCount()-1, 0); // 添加之后count会加一
theModel->setData(index, "new Item", Qt::DisplayRole);
ui->listView->setCurrentIndex(index);
}
void Widget::on_btnInsert_clicked()
{
theModel->insertRow(ui->listView->currentIndex().row());
QModelIndex index = theModel->index(ui->listView->currentIndex().row()-1, 0); // 插入之后count会加一
theModel->setData(index, "insert Item", Qt::DisplayRole);
ui->listView->setCurrentIndex(index);
}
void Widget::on_listView_clicked(const QModelIndex &index)
{
ui->label->setText(QString::asprintf("行:%d列:%d", index.row(), index.column()));
}
以项数据为基础的标准数据模型类,通常与QTableView组合成为Model/View结构,实现通用的二位数据管理功能。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
labCurrFile = new QLabel("当前文件", this);
labCellPos = new QLabel("当前单元格", this);
labCellText = new QLabel("单元格内容", this);
theModel = new QStandardItemModel(10, fixedColoumCount,this);
theSelection = new QItemSelectionModel(theModel);
ui->tableView->setModel(theModel);
ui->tableView->setSelectionModel(theSelection);
labCurrFile->setMinimumWidth(200);
labCellPos->setMinimumWidth(150);
labCellText->setMinimumWidth(200);
ui->statusBar->addWidget(labCurrFile);
ui->statusBar->addWidget(labCellPos);
ui->statusBar->addWidget(labCellText);
connect(theSelection, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this, SLOT(on_currentChanged(QModelIndex,QModelIndex)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
{
Q_UNUSED(previous)
if(! current.isValid()){
return;
}
QStandardItem *item = theModel->itemFromIndex(current);
labCellPos->setText(QString::asprintf("当前单元格:%d行:%d列", current.row(), current.column()));
labCellText->setText("单元格内容:"+item->text());
QFont font = item->font();
ui->actFontBold->setChecked(font.bold());
}
void MainWindow::initModelFromStringList(QStringList &fileContent)
{
theModel->setRowCount(fileContent.count()-1);
// 表头
QString header = fileContent.at(0);
QStringList headerList = header.split(",");
theModel->setHorizontalHeaderLabels(headerList);
// 表格数据
int col;
QStandardItem *item;
for (int row = 1; row < fileContent.count(); ++row) {
QString lineText = fileContent.at(row);
QStringList colList = lineText.split(",");
for (col = 0; col < fixedColoumCount-1; ++col) {
item = new QStandardItem(colList.at(col));
theModel->setItem(row-1, col, item);
}
item = new QStandardItem(headerList.at(col));
if(colList.at(col) == "1"){
item->setCheckState(Qt::Checked);
}
else{
item->setCheckState(Qt::Unchecked);
}
theModel->setItem(row-1, col, item);
}
}
#include <QFileDialog>
#include <QFile>
#include <QTextStream>
void MainWindow::on_actOpen_triggered()
{
QString strCurrPath = QCoreApplication::applicationDirPath();
QString strFileName = QFileDialog::getOpenFileName(this, "打开一个文件",
strCurrPath, "数据文件(*.txt);;所有文件(*.*)");
if(strFileName.isEmpty()){
return;
}
QStringList fileContent;
QFile file(strFileName);
if(file.open(QIODevice::ReadOnly|QIODevice::Text)){
QTextStream stream(&file);
ui->plainTextEdit->clear();
while (!stream.atEnd()) {
QString str = stream.readLine();
ui->plainTextEdit->appendPlainText(str);
if(!str.isEmpty()){
fileContent.append(str);
}
}
file.close();
this->labCurrFile->setText("当前文件:"+strFileName);
initModelFromStringList(fileContent);
ui->tableView->resizeColumnsToContents();
ui->tableView->resizeRowsToContents();
ui->actSave->setEnabled(true);
ui->actAppend->setEnabled(true);
ui->actDelete->setEnabled(true);
ui->actInsert->setEnabled(true);
}
}
void MainWindow::on_actSave_triggered()
{
QString strCurrPath = QCoreApplication::applicationDirPath();
QString strFileName = QFileDialog::getSaveFileName(this, "另存为文件",
strCurrPath, "数据文件(*.txt);;所有文件(*.*)");
if(strFileName.isEmpty()){
return;
}
QStringList fileContent;
QFile file(strFileName);
if(file.open(QIODevice::ReadWrite|QIODevice::Text|QIODevice::Truncate)){
QTextStream stream(&file);
ui->plainTextEdit->clear();
QString str;
int i;
for (i = 0; i < theModel->columnCount()-1; ++i) {
QStandardItem *item = theModel->horizontalHeaderItem(i);
str += item->text()+",";
}
QStandardItem *item = theModel->horizontalHeaderItem(i);
str += item->text();
stream<<str<<"\n";
ui->plainTextEdit->appendPlainText(str);
int j;
for (int i = 0; i < theModel->rowCount(); ++i) {
str = "";
for (j = 0; j < theModel->columnCount()-1; ++j) {
QStandardItem *item = theModel->item(i,j);
str += item->text()+",";
}
QStandardItem *item = theModel->item(i,j);
if(item->checkState() == Qt::Checked){
str += "1";
}
else{
str += "0";
}
stream<<str<<"\n";
ui->plainTextEdit->appendPlainText(str);
}
file.close();
}
}
void MainWindow::on_actModelData_triggered()
{
ui->plainTextEdit->clear();
QString str;
for (int i = 0; i < theModel->columnCount(); ++i) {
QStandardItem *item = theModel->horizontalHeaderItem(i);
str += item->text()+",";
}
ui->plainTextEdit->appendPlainText(str);
int j;
for (int i = 0; i < theModel->rowCount(); ++i) {
str = "";
for (j = 0; j < theModel->columnCount()-1; ++j) {
QStandardItem *item = theModel->item(i,j);
str += item->text()+",";
}
QStandardItem *item = theModel->item(i,j);
if(item->checkState() == Qt::Checked){
str += "1";
}
else{
str += "0";
}
ui->plainTextEdit->appendPlainText(str);
}
}
void MainWindow::on_actAppend_triggered()
{
QList<QStandardItem*> itemList;
QStandardItem *item;
for (int i = 0; i < fixedColoumCount-1; ++i) {
item = new QStandardItem("0");
itemList << item;
}
QString str = theModel->headerData(theModel->columnCount()-1,
Qt::Horizontal, Qt::DisplayRole).toString();
item = new QStandardItem(str);
item->setCheckState(Qt::Checked);
itemList << item;
theModel->appendRow(itemList);
theSelection->clearSelection();
QModelIndex index = theModel->index(theModel->rowCount()-1, 0);
theSelection->setCurrentIndex(index, QItemSelectionModel::Select);
}
void MainWindow::on_actInsert_triggered()
{
QList<QStandardItem*> itemList;
QStandardItem *item;
for (int i = 0; i < fixedColoumCount-1; ++i) {
item = new QStandardItem("0");
itemList << item;
}
QString str = theModel->headerData(theModel->columnCount()-1,
Qt::Horizontal, Qt::DisplayRole).toString();
item = new QStandardItem(str);
item->setCheckState(Qt::Checked);
itemList << item;
theModel->insertRow(theSelection->currentIndex().row(), itemList);
theSelection->clearSelection();
QModelIndex index = theModel->index(theSelection->currentIndex().row(), 0);
theSelection->setCurrentIndex(index, QItemSelectionModel::Select);
}
void MainWindow::on_actDelete_triggered()
{
if(theSelection->currentIndex().row() ==
theModel->rowCount()-1){
theModel->removeRow(theSelection->currentIndex().row());
}
else{
theModel->removeRow(theSelection->currentIndex().row());
QModelIndex index = theModel->index(theSelection->currentIndex().row(), 0);
theSelection->setCurrentIndex(index, QItemSelectionModel::Select);
}
}
void MainWindow::on_actAlignLeft_triggered()
{
if(!theSelection->hasSelection()){
return;
}
QModelIndexList selectedIndexes = theSelection->selectedIndexes();
for (int i = 0; i < selectedIndexes.count(); ++i) {
QModelIndex index = selectedIndexes.at(i);
QStandardItem *item = theModel->itemFromIndex(index);
item->setTextAlignment(Qt::AlignLeft);
}
}
void MainWindow::on_actAlignCenter_triggered()
{
if(!theSelection->hasSelection()){
return;
}
QModelIndexList selectedIndexes = theSelection->selectedIndexes();
for (int i = 0; i < selectedIndexes.count(); ++i) {
QModelIndex index = selectedIndexes.at(i);
QStandardItem *item = theModel->itemFromIndex(index);
item->setTextAlignment(Qt::AlignCenter);
}
}
void MainWindow::on_actAlignRight_triggered()
{
if(!theSelection->hasSelection()){
return;
}
QModelIndexList selectedIndexes = theSelection->selectedIndexes();
for (int i = 0; i < selectedIndexes.count(); ++i) {
QModelIndex index = selectedIndexes.at(i);
QStandardItem *item = theModel->itemFromIndex(index);
item->setTextAlignment(Qt::AlignRight);
}
}
void MainWindow::on_actFontBold_triggered(bool checked)
{
if(!theSelection->hasSelection()){
return;
}
QModelIndexList selectedIndexes = theSelection->selectedIndexes();
for (int i = 0; i < selectedIndexes.count(); ++i) {
QModelIndex index = selectedIndexes.at(i);
QStandardItem *item = theModel->itemFromIndex(index);
QFont font = item->font();
font.setBold(checked);
item->setFont(font);
}
}
代理是介于Model和View之间,主要用于数据修改。
QAbstractItemDelegate
QStyledItemDelegate
QItemDelegate
QSqlRelationalDelegate
必须实现以下几个函数:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
labCurrFile = new QLabel("当前文件", this);
labCellPos = new QLabel("当前单元格", this);
labCellText = new QLabel("单元格内容", this);
theModel = new QStandardItemModel(10, fixedColoumCount,this);
theSelection = new QItemSelectionModel(theModel);
ui->tableView->setModel(theModel);
ui->tableView->setSelectionModel(theSelection);
labCurrFile->setMinimumWidth(200);
labCellPos->setMinimumWidth(150);
labCellText->setMinimumWidth(200);
ui->statusBar->addWidget(labCurrFile);
ui->statusBar->addWidget(labCellPos);
ui->statusBar->addWidget(labCellText);
ui->tableView->setItemDelegateForColumn(0, &intSpinDelegate); //给0列设置代理
connect(theSelection, SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this, SLOT(on_currentChanged(QModelIndex,QModelIndex)));
}
#include "qintdelegate.h"
#include <QSpinBox>
QIntDelegate::QIntDelegate()
{
}
QWidget *QIntDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index)
Q_UNUSED(option)
QSpinBox *edit = new QSpinBox(parent);
edit->setMinimum(0);
edit->setMaximum(1000);
edit->setFrame(false); //无边框
return edit;
}
void QIntDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
void QIntDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText(); // 确保获得的是最新更新的数据
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void QIntDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index)
editor->setGeometry(option.rect);
}