C++ 如何使用Qt Custom TableModel(源自QabStretctTableModel)强制刷新已更改的单元格?

C++ 如何使用Qt Custom TableModel(源自QabStretctTableModel)强制刷新已更改的单元格?,c++,qt,qtableview,C++,Qt,Qtableview,我是新来的。我正在尝试实现一个自定义表模型: 我有一个类DataSource,它包含我的所有数据,并在行更改时或一行中只有一些值更改时触发事件(传统的事件,而不是Qt signa/slots)。以下是一个简化版本: class DataSource{ public: int size(); int nbColumns(); const std::string& data(int row, int col); bool hasChanges(); }; 我将Table

我是新来的。我正在尝试实现一个自定义表模型:

我有一个类DataSource,它包含我的所有数据,并在行更改时或一行中只有一些值更改时触发事件(传统的事件,而不是Qt signa/slots)。以下是一个简化版本:

class DataSource{
  public:
  int size();
  int nbColumns();
  const std::string& data(int row, int col);
  bool hasChanges();
};
我将TableModel实现为数据源的包装器:

class MyTableModel : public QAbstractTableModel {
  public:

  int rowCount(const QModelIndex& parent) const {
      return datasource->size();
  }

  int columnCount(const QModelIndex& parent) const {
    return datasource->nbColumns();
  }

  QVariant data(const QModelIndex& index, int role) const {
    return QVariant(datasource.data(index.row(), index.column());
  }
};
我使用计时器刷新表格(我的应用程序中更新太多):

这不起作用(我原以为视图会在重新绘制时查询模型,但也许我应该调用另一个方法?)

因此,我在调用重新绘制之前添加了以下内容:

tableModel->update();
其定义如下:

void MyTableModel::update()
{
  beginResetModel();
  endResetModel();
  //doesn't work: emit dataChanged(createIndex(0,0), createIndex(DataSource->size(), DataSource->nbColumns()));
}
它可以工作,但是如果只改变一个单元格,我想应该有比重置整个模型更有效的方法了?为什么emit DataChanged不起作用? 文档中不清楚Qt框架调用了哪个函数,以及应该显式调用哪个函数

编辑:感谢下面的评论,我理解了它的工作原理。我不需要在QTableView本身上调用任何东西,我只需更新我的模型并调用
beginResetModel(); ... endResetModel()

或者仅当单元格发生变化时:
发射数据改变(…)

Qt版本一直在变化。从一个版本更改到另一个版本是微不足道的。规划你的项目是非常重要的。为用户界面(ui)选择的Qt小部件是导入的。Qt小部件传输信号,您可以使用插槽连接到这些信号。取决于你想对你的项目做什么。在实现某些函数时,调用适当的函数以使所有连接的视图都知道任何更改是很重要的。QAbstractTableModel对于希望实现自己的表模型或自定义委托的开发人员可能很有用。MVC(模型、视图和控制器)背后有一个理论。实现MVC将解决这个问题。有很多策略可以用来实现它。起点是规划。 您可以使用类DataSource和类MyTableModel作为模型。缺少的是视图和控制器的定义。您的“#include”在Qt中也很重要。QAbstractTableModel提供了访问数据的标准MVAPI。我们可以使用QtableView使用不同的视图查看数据。必须实现的基本函数有:rowCount()、columnCount()、data()、headerData()。要使TableModel可编辑,它必须提供insertRows()、removeRows()、setData()和flags()函数的实现


  • 演示自定义表格。


  • main.cpp


  • 享受。

  • 如果您是Qt新手。Qt使用C++。它实现了GUI。大多数C++应用程序都使用控制台应用程序。Qt使用设计模式和框架。享受吧



    为什么要手动更新视图?@scopchanov我并不想要它,如果你知道只要更新模型,我就可以重新绘制视图,那就更好了。。。但是现在还不清楚我应该调用哪种方法来让它工作。模型/视图背后的想法是,一旦模型中的数据发生变化,视图应该自动更新。因此,无需手动执行此操作。为了能够进一步帮助您,请准备一份复制该问题的报告(包括您的自定义模型)。虽然我没有详细阅读您的长篇回复(我已经找到了解决方案),但我接受它作为回答,因为这对其他人可能有用。
    void MyTableModel::update()
    {
      beginResetModel();
      endResetModel();
      //doesn't work: emit dataChanged(createIndex(0,0), createIndex(DataSource->size(), DataSource->nbColumns()));
    }
    
    //
    #include "widget.h"
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w;
    w.show();
    
    return a.exec();
    }
    //
    
    //
    #ifndef WIDGET_H
    #define WIDGET_H
    #include <QWidget>
    #include <QTableView>
    #include <QListView>
    #include <QLabel>
    #include <QLineEdit>
    #include <QTextBrowser>
    #include <QDateEdit>
    #include <QString>
    //namespace Ui {
    //class Widget;
    //}
    class MyTableModel;
    class Widget : public QWidget
    {
    Q_OBJECT
    public:
    //explicit Widget(QObject t, QWidget *parent = 0);
    Widget(QWidget *parent = 0);
    ~Widget();
    public slots:
    void updateView();
    private:
    //Ui::Widget *ui;
    QTableView *tableView;
    MyTableModel *tableModel;
    QLineEdit *ledMessage;
    QLabel *lblMessage;
    QTextBrowser *logs;
    QDateEdit *dateEdit;
    };
    #endif // WIDGET_H
    //
    
    //
    #include <QtGui>
    #include "mytablemodel.h"
    #include "widget.h"
    //#include "ui_widget.h"
    #include <QGridLayout>
    
    Widget::Widget(QWidget *parent) :
    QWidget(parent)/*,
    ui(new Ui::Widget*)*/
    {
    //ui->setupUi(this);
    tableModel = new MyTableModel(this);
    tableView = new QTableView;
    tableView->setModel(tableModel);
    lblMessage = new QLabel(tr("&Message:"));
    ledMessage = new QLineEdit;
    lblMessage->setBuddy(ledMessage);
    dateEdit = new QDateEdit(QDate::currentDate());
    logs = new QTextBrowser;
    logs->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
    
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(lblMessage, 0, 0);
    layout->addWidget(ledMessage, 0, 1);
    layout->addWidget(dateEdit, 0, 2);
    layout->addWidget(tableView, 1, 0, 1, 2);
    layout->addWidget(logs, 2, 0, 1, 2);
    
    setLayout(layout);
    setWindowTitle(tr("Demo Custom Table."));
    //connect(ledMessage, SIGNAL(textChanged(const QString &)),
    //             tableModel, SLOT(newMessage(const QString &)));
    //connect(tableModel, SIGNAL(updateMode()),
    //             this, SLOT(updateView()));
    connect(ledMessage, SIGNAL(editingFinished()), this, SLOT(updateView()));
    }
    
    Widget::~Widget()
    {
    //delete ui;
    }
    
    void Widget::updateView()
    {
    QModelIndex p = tableView->currentIndex();
    tableModel->update(p,ledMessage->text(), dateEdit->text());
    logs->append(tr("%1 : ").arg(p.row()));
    logs->append(ledMessage->text());
    }
    //
    
    //
    #ifndef MYTABLEMODEL_H
    #define MYTABLEMODEL_H
    
    #include <QAbstractTableModel>
    #include <QLabel>
    //#include <QDateEdit>
    #include <QDateTime>
    #include "datasource.h"
    
    class MyTableModel : public QAbstractTableModel
    {
    Q_OBJECT
    public:
    //explicit MyTableModel(QObject t, QObject t2,QObject *parent = 0);
    MyTableModel(QObject *parent = 0);
    MyTableModel(QList< QPair<QString,QString> > t, QObject *parent = 0);
    int rowCount(const QModelIndex &parent = QModelIndex()) const;
    int columnCount(const QModelIndex &parent = QModelIndex()) const;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    QVariant headerData(int part, Qt::Orientation orient, int role) const;
    void update(const QModelIndex &parent,const QString &mes, const QString &date);
    bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole);
    Qt::ItemFlags flags(const QModelIndex &index) const;
    bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex());
    bool removeRows(int position, int rows, const QModelIndex &index=QModelIndex());
    
    signals:
    void updateMod();
    
    public slots:
    void newMessage(const QString &mes);
    
    protected:
    void update(const QModelIndex &parent);
    
    private:
    DataSource *datasource;
    QPair<QString,QString> message;
    QList< QPair<QString,QString> > messageList;
    QList<QString> dList;
    int listSize;
    int col;
    QLabel *lblNumber;
    QDateTime *dTime;
    //QDateEdit *dateEdit;
    };
    
    #endif // MYTABLEMODEL_H
    //
    
    //    
    #include "mytablemodel.h"
    #include <QApplication>
    
    MyTableModel::MyTableModel(QObject *parent) :
    QAbstractTableModel(parent)
    {
    datasource = new DataSource();
    lblNumber = new QLabel;
    dTime = new QDateTime();
    //dateEdit = new QDateEdit(QDate::currentDate());
    col = datasource->nbColumns();
    int l = datasource->size();
    for(int i = 0; i < l; i++)
    {
        message.first = datasource->data(i,0);
        message.second = datasource->data(i,1);
        messageList.append(message);
        dList.append(dTime->currentDateTime().toString());
    }
    listSize = messageList.size();
    
    }
    
    MyTableModel::MyTableModel(QList< QPair<QString,QString> > t, QObject *parent) :
    QAbstractTableModel(parent)
    {
    messageList = t;
    datasource = new DataSource();
    listSize = t.length();
    col = datasource->nbColumns();
    }
    
    void MyTableModel::update(const QModelIndex &,const QString &mes, const QString &d)
    {
    int first = messageList.count();
    int last = first + 1;
    first = last;
    lblNumber->setText(tr("%1").arg(first));
    beginInsertRows(QModelIndex(),first,last);
    message.first = lblNumber->text();
    message.second = mes;
    messageList.append(message);
    dList.append(d);
    listSize++;
    endInsertRows();
    datasource->hasChanges();
    }
    
    int MyTableModel::rowCount(const QModelIndex &p) const
    {
    Q_UNUSED(p);
    return listSize;
    }
    
    int MyTableModel::columnCount(const QModelIndex &p) const
    {
    Q_UNUSED(p);
    return col;
    }
    
    QVariant MyTableModel::data(const QModelIndex &index, int role) const
    {
    int c = 0;
    if (!index.isValid())
    {
       return QVariant();
    }
    if(index.row() < 0)
    {
       return QVariant();
    }
    if (role == Qt::DisplayRole)
    {
        c = index.column();
        if(c == 0)
        {
           return messageList.at(index.row()).first;
        }
        else if (c == 1)
        {
           return messageList.at(index.row()).second;
        }
    
        return dList.at(index.row());
    }
    
    return QVariant();
    }
    
    void MyTableModel::update(const QModelIndex &p)
    {
    Q_UNUSED(p);
    emit updateMod();
    }
    
    void MyTableModel::newMessage(const QString &mes)
    {
    listSize++;
    message.first = lblNumber->text();
    message.second = mes;
    messageList.append(message);
    dList.append(dTime->currentDateTime().toString());
    }
    
    bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    QString d = dTime->currentDateTime().toString();
    if (index.isValid() && role == Qt::EditRole)
    {
        int row = index.row();
    
        message = messageList.value(row);
        if (index.column() == 0)
        message.first = value.toString();
        else if (index.column() == 1)
        message.second = value.toString();
        else
        return false;
    
        messageList.replace(row, message);
        dList.replace(row,d);
        emit(dataChanged(index, index));
    
         return true;
     }
    
     return false;
    }
    
    bool MyTableModel::insertRows(int post, int rows, const QModelIndex &p)
    {
     Q_UNUSED(p);
     beginInsertRows(QModelIndex(), post, post+rows-1);
     for (int row=0; row < rows; row++)
     {
         message.first = " ";
         message.second = " ";
         messageList.insert(post, message);
         dList.insert(post, " ");
     }
     endInsertRows();
     return true;
    }
    
    bool MyTableModel::removeRows(int post, int rows, const QModelIndex &p)
    {
     Q_UNUSED(p);
     beginRemoveRows(QModelIndex(), post, post+rows-1);
     for (int row=0; row < rows; ++row)
     {
         messageList.removeAt(post);
         dList.removeAt(post);
     }
     endRemoveRows();
     return true;
    }
    
    Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
    {
     if (!index.isValid())
         return Qt::ItemIsEnabled;
    
     return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;
    }
    
    QVariant MyTableModel::headerData(int part, Qt::Orientation orient, int role) const
    {
     if (role != Qt::DisplayRole)
         return QVariant();
    
     if (orient == Qt::Horizontal)
     {
         switch (part)
         {
             case 0:
                 return tr("Number");
    
             case 1:
                 return tr("Message");
    
             case 2:
                 return tr("Date");
    
             default:
                 return QVariant();
         }
     }
     return QVariant();
    }
    //
    
    //
    #include <QString>
    #include <QVariant>
    #include <QList>
    #include <QPair>
    
    class DataSource
    {
    public:
    DataSource();
    int size();
    int nbColumns();
    const QString& data(int row, int col);
    bool hasChanges();
    
    private:
    int beginRow;
    int columns;
    QPair<QString,QString> message;
    QList< QPair<QString,QString> > messages;
    };
    
    #endif // DATASOURCE_H
    //
    
    //
    #include "datasource.h"
    
    DataSource::DataSource()
    {
    beginRow = 1;
    columns = 3;
    message.first = "One";
    message.second = "Testing123";
    messages.push_back(message);
    message.first = "Two";
    message.second = "QObject";
    messages.push_back(message);
    message.first = "Three";
    message.second = "QWidget";
    messages.push_back(message);
    }
    
    int DataSource::size()
    {
    return messages.length();
    }
    
    int DataSource::nbColumns()
    {
    return columns;
    }
    
    const QString& DataSource::data(int r, int c)
    {
    int l = messages.length();
    if(r < l)
    {
        message = messages.at(r);
        if (c == 0)
        {
            return message.first;
        }
        else if (c == 1)
        {
           return message.second;
        }
    }
    return "Testing123";
    }
    
    
    bool DataSource::hasChanges()
    {
    beginRow++;
    return true;
    }
    //
    
    //
    #-------------------------------------------------
    #
    # Project created by QtCreator 2018-09-10T15:39:01
    #
    #-------------------------------------------------
    
    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    TARGET = customtab
    TEMPLATE = app
    
    
    SOURCES += main.cpp\
        widget.cpp \
    datasource.cpp \
    mytablemodel.cpp
    
    HEADERS  += widget.h \
    datasource.h \
    mytablemodel.h
    
    #//FORMS    += widget.ui
    //