首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于Qt模型更新的视图更新

基于Qt模型更新的视图更新
EN

Stack Overflow用户
提问于 2022-03-30 08:23:20
回答 1查看 643关注 0票数 0

当由模型包装的数据使用更改时,我在更新qtableview时遇到了问题。我不是在这里讨论附加/添加数据,而是专门讨论修改现有数据。视图只有在滚动或选择单元格时才会更新。换句话说,只有当重新绘制被触发时才会更新它(这实际上是我的猜测)。因此,这让我认为在修改数据时对小部件调用update()就足够了,但事实并非如此。

我以编程方式向模型添加数据,用户不能修改或添加模型中的数据。

下面是一个最小的、可重复的例子:

没药。h:

代码语言:javascript
复制
#pragma once

#include <QAbstractTableModel>
#include <QVector>

#include "myobject.h"

class MyModel : public QAbstractTableModel
{
    Q_OBJECT
private:
    QVector<MyObject> my_objects_; /// underlying data structure for the model.
public:
    MyModel(QObject * parent = {});
    int rowCount(const QModelIndex &) const override;
    int columnCount(const QModelIndex &) const override;
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::EditRole) const override;

    void add(const MyObject& my_object);
    void edit(const MyObject& my_object);
};

mymodel.cpp:

代码语言:javascript
复制
#include "mymodel.h"

#include <QDebug>
#include <iostream>

MyModel::MyModel(QObject * parent)
    : QAbstractTableModel{parent}
{
}

int MyModel::rowCount(const QModelIndex &) const
{
    return my_objects_.count();
}

int MyModel::columnCount(const QModelIndex &) const {
    return 4;
}

QVariant MyModel::data(const QModelIndex &index, int role) const {
   const auto row = index.row();
   if(row == -1) {
       return {};
   }

   const auto my_object = my_objects_[row];

   if(role == Qt::DisplayRole) {
       switch (index.column()) {
           case 0: return my_object.id;
           case 1: return my_object.a;
           case 2: return my_object.b;
           case 3: return my_object.c;
           default: return {};
       };
   }

   return {};
}

QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const {
   if (orientation != Qt::Horizontal || role != Qt::DisplayRole) {
       return {};
   }

   switch (section) {
       case 0: return "id";
       case 1: return "a";
       case 2: return "b";
       case 3: return "c";
       default: return {};
   }
}

void MyModel::add(const MyObject &my_object)
{
    beginInsertRows({}, my_objects_.count(), my_objects_.count());
    my_objects_.push_back(my_object);
    endInsertRows();
}

void MyModel::edit(const MyObject& my_object) {
    const auto id = my_object.id;

    for(auto& my_object_ : my_objects_) {
        if(my_object_.id == id) {

            my_object_.a = my_object.a;
            my_object_.b = my_object.b;
            my_object_.c = my_object.c;
            /// should I use dataChanged signal here? If so, how?

            break;
        }
    }
}

我的目标:

代码语言:javascript
复制
#pragma once

#include <QString>

struct MyObject {
    int id;
    int a;
    double b;
    QString c;
};

主窗h:

代码语言:javascript
复制
#pragma once

#include <QMainWindow>
#include "mymodel.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void onEditClicked();

private:
    Ui::MainWindow *ui;
    MyModel my_model_;
};

mainwindow.cpp:

代码语言:javascript
复制
#include "mainwindow.h"
#include "./ui_mainwindow.h"

const static QVector<MyObject> g_my_objects{
    {0, 1, 1.1, "object1"},
    {1, 11, 1.2, "object2"},
    {2, 12, 1.3, "object3"},
    {3, 13, 1.4, "object4"},
    {4, 14, 1.5, "object5"},
    {5, 15, 1.6, "object6"},
    {6, 16, 1.7, "object7"},
    {7, 17, 1.8, "object8"}
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

    ui->tableView->setModel(&my_model_);

    for(const auto& g_my_object : g_my_objects) {
        my_model_.add(g_my_object);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onEditClicked()
{
    qDebug() << __PRETTY_FUNCTION__;

    my_model_.edit({2, 22222, 2222.222, "myobject22222"});

    update(); /// seems to be doing nothing.
}

main.cpp:

代码语言:javascript
复制
#include "mainwindow.h"

#include <QApplication>
#include <QVector>

#include "myobject.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.ui:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QPushButton" name="pushButton">
      <property name="text">
       <string>Edit</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QTableView" name="tableView"/>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>pushButton</sender>
   <signal>clicked()</signal>
   <receiver>MainWindow</receiver>
   <slot>onEditClicked()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>604</x>
     <y>41</y>
    </hint>
    <hint type="destinationlabel">
     <x>951</x>
     <y>20</y>
    </hint>
   </hints>
  </connection>
 </connections>
 <slots>
  <slot>onEditClicked()</slot>
 </slots>
</ui>

CMakeLists.txt:

代码语言:javascript
复制
cmake_minimum_required(VERSION 3.5)

project(model_view_example VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)

set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mymodel.cpp
        mainwindow.h
        mainwindow.ui
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(model_view_example
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )
# Define target properties for Android with Qt 6 as:
#    set_property(TARGET model_view_example APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
#                 ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
    if(ANDROID)
        add_library(model_view_example SHARED
            ${PROJECT_SOURCES}
        )
# Define properties for Android with Qt 5 after find_package() calls as:
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
    else()
        add_executable(model_view_example
            ${PROJECT_SOURCES}
        )
    endif()
endif()

target_link_libraries(model_view_example PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

set_target_properties(model_view_example PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(model_view_example)
endif()

那么,为什么在调用update()时没有更新视图呢?我的实现有什么问题吗?

在这里,我单击了“编辑”按钮,但只有在单击单元格时,视图才会使用其新值进行更新:

我觉得Qt示例并不能很好地映射到我在这里是如何做到的。如果可能的话,我不知道如何以更简单的方式实现这个逻辑。

下面是用于最小项目的github回购:

示例

EN

回答 1

Stack Overflow用户

发布于 2022-03-30 08:47:28

当现有项中的数据发生更改时,您应该发出信号dataChanged。QTableView应该自动更新。

请参见:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71673874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档