QAbstractItemModel::data() 在两种情况下被触发: 1) QAbstractItemModel 释放dataChanged 信号时; 2)QAbstractItemModel 调用appendRow方法时。但是 dataChanged 并不能总是触发data函数。下面用一个例子 来说明。
先建立一个mainwindow类,里面含有一个ui,ui中包含qtableview。此外mainwindow还有一个model成员,是QStandardItemModel的派生类:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QKeyEvent>
#include <QMouseEvent>
#include "model.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
model m_LstModel;
void vSetHrntHeader();
private:
Ui::MainWindow *ui;
protected:
void mouseDoubleClickEvent(QMouseEvent *);
void keyPressEvent(QKeyEvent *);
};
#endif // MAINWINDOW_H
#ifndef MODEL_H
#define MODEL_H
#include <QStandardItemModel>
#include <QKeyEvent>
#include <QVariant>
class model : public QStandardItemModel
{
Q_OBJECT
public:
explicit model(QObject *parent = 0);
void update(QKeyEvent *);
bool m_bGreen;
QVariant data(const QModelIndex & , int role = Qt::DisplayRole) const;
signals:
public slots:
};
#endif // MODEL_H
当用户双击mainwindow时,model::appendRow()会被调用;当用户点击按键时,会调用model的update()函数,进而释放dataChanged()信号。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qdebug.h>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableView->setFocusPolicy(Qt::NoFocus);
vSetHrntHeader();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::vSetHrntHeader()
{
QStringList HrntList;
HrntList<<"hello"<<"789"<<"123";
m_LstModel.setHorizontalHeaderLabels(HrntList);
ui->tableView->setModel(&m_LstModel);
ui->tableView->setFocusPolicy(Qt::NoFocus);
ui->tableView->setAlternatingRowColors(true);
ui->tableView->setStyleSheet("QTableView{background-color: rgb(250, 0, 0);"
"alternate-background-color: rgb(141, 163, 215);"
"gridline-color: rgb(0,60,0);"
"text-align: center;}");
ui->tableView->verticalHeader()->setVisible(false);
}
void MainWindow::mouseDoubleClickEvent(QMouseEvent *e)
{
QStandardItem * qitem1 = new QStandardItem(QString("a"));
QStandardItem * qitem2 = new QStandardItem(QString("b"));
QStandardItem * qitem3 = new QStandardItem(QString("c"));
QList<QStandardItem *> qlstTmp;
qlstTmp<<qitem1<<qitem2<<qitem3;
m_LstModel.appendRow(qlstTmp);
}
void MainWindow::keyPressEvent(QKeyEvent *e)
{
if(e->key() == Qt::Key_A)
qDebug()<<"A pressed";
m_LstModel.update(e);
}
#include "model.h"
model::model(QObject *parent) : QStandardItemModel(parent)
{
m_bGreen = false;
}
void model::update(QKeyEvent *e)
{
if(e->key() == Qt::Key_A)
{
m_bGreen = true;
emit dataChanged(createIndex(0,0), createIndex(0,0));
}
else
{
m_bGreen = false;
emit dataChanged(createIndex(0,0), createIndex(0,0));
}
}
QVariant model::data(const QModelIndex & index, int role) const
{
if(index.column() == 0)
{
if(role == Qt::BackgroundRole)
{
return m_bGreen? QBrush(Qt::green):QBrush(Qt::blue);
}
else if(role == Qt::TextAlignmentRole)
{
return Qt::AlignCenter;
}
else if(role == Qt::DisplayRole)
{
return QString("0");
}
else
{
return QVariant();
}
}
else
{
if(role == Qt::BackgroundRole)
{
return QBrush(Qt::yellow);
}
else if(role == Qt::TextAlignmentRole)
{
return Qt::AlignLeft;
}
else if(role == Qt::DisplayRole)
{
return QString("not 0");
}
else
{
return QVariant();
}
}
}
现在看效果。
1)启动程序后,直接按下A键界面无反应。不仅无反应,在model::data()处设置断点,断点也不会触发。这是因为model里面没有内容。虽然dataChanged已经发射出去了,但不会触发data()
2) 双击mainwindow,data()被触发,且新添加的一行显示了出来。由于步骤1)里已经把m_bGreen设为true(这也说明dataChanged确实发出去了,只是没被data()响应),所以(0,0)的背景色就是绿的:
3) 现在按下"B"键,(0,0)又变回蓝色,说明data()可以响应dataChanged()信号了。
总结一下:
1)当QAbstractItemModel还没有内容时,data() 函数不会响应dataChanged信号;
2)当QAbstractItemModel调用 appendRow方法后,会自动调用 data();
3)只有当QAbstractItemModel有内容时,data()才会响应dataChanged()。dataChanged()的前两个变量分别表示数据变化区域的左上角和右下角。事实上,一个dataChanged()会触发data()好几次,不仅会修改响应单元格的内容,也会改变其背景色等。