【问题标题】:Automatically refreshing a QTableView when data changed数据更改时自动刷新 QTableView
【发布时间】:2019-10-08 17:55:02
【问题描述】:

我已经编写了一个自定义数据模型来显示几个 QTableView。

从技术上讲,一切正常:我的视图显示了我的模型所做的更改。我的数据模型是可编辑的,setData() 方法确实会发出dataChanged() 信号并在成功编辑时返回true

但是,我的问题是我必须将鼠标移到 QTableView 上才能显示实际更改,而我希望所有视图在进行更改时都显示更改,而无需与视图交互以便更新。

有什么想法吗?谢谢,


值得一提的是,我不使用默认的Qt::EditRole 角色来编辑数据,而是使用自定义枚举值(名为ActiveRole)。

这就是我想要的:我的数据模型包含有关如何显示数据的属性,用于生成提供给 viewS 的样式表。

因此,在更改模型时,对于每个视图,它的所有项目都会受到影响,这就是为什么 dataChanged() 信号被发送,索引覆盖所有单元格。

我也尝试发出layoutChanged(),但它似乎并没有改变我的行为。

这里是setData()方法的摘录:

bool DataModel::setData(QModelIndex const& idx, QVariant const& value, int role)
{
  if (ActiveRole == role)
  {
    // Update data...

    QModelIndex topLeft = index(0, 0);
    QModelIndex bottomRight = index(rowCount() - 1, columnCount() - 1);

    emit dataChanged(topLeft, bottomRight);
    emit layoutChanged();

    return true;
  }
  return false;
}

这是data() 方法的示例:

QVariant DataModel::data(QModelIndex const& idx, int role) const
{
  if (ActiveRole == role)
  {
    boost::uuids::uuid id;

    return qVariantFromValue(id);
  }

  return QVariant();
}

flags() 确实表示可编辑模型:

Qt::ItemFlags DataModel::flags(QModelIndex const& idx) const
{
  if (false == idx.isValid())
  {
    return Qt::ItemIsEditable;
  }

  return QAbstractTableModel::flags(idx) | Qt::ItemIsEditable;
}

我有一个自定义委托,它严重依赖 SO thread 来覆盖 paintsizeHint 方法以绘制 QTextDocument。另外,它把ActiveRole的内容提供给setEditorData中的编辑器,并在setModelData中调用DataMode::setData

void DataModelDelegate::setEditorData(QWidget* editor, QModelIndex const& idx) const
{
  auto active = qVariantValue<boost::uuids::uuid>(idx.data(ActiveRole));
  static_cast<DataModelEditor*>(editor)->setActive(active);
}

void DataModelDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, QModelIndex const& idx) const
{
  auto active = static_cast<DataModelEditor*>(editor)->getActive();
  model->setData(idx, qVariantFromValue(active), ActiveRole);
}

createEditor() 中,我将来自编辑器的信号插入到我的委托的插槽以提交数据:

QWidget* DataModelDelegate::createEditor(QWidget* parent, QStyleOptionViewItem const& option, QModelIndex const& idx) const
{
  auto editor = new DataModelEditor(parent);
  connect(editor, SIGNAL(activeItem()), this, SLOT(commitEditorData()));
  return editor;
}

当点击一个项目时,编辑器触发activeItem信号;连接的插槽commitEditorData 反过来引发commitData 信号,编辑器在参数中。

所以我的所有视图都使用这些自定义委托、编辑器和数据模型。我正在与之交互的视图确实会立即显示更改,但其他视图也需要将鼠标悬停在它们上方才能显示更改。

【问题讨论】:

  • 你能显示setData()函数的代码吗?
  • 因此您的 setData 可用于自定义 ActiveRole 而不是标准 EditRole/DisplayRole,但是您为这些项目设置了什么角色?你是否也覆盖data()?你的视图有自定义渲染委托吗?
  • 我用一些数据实现、setData、createEditor 等更新了我的问题。希望这会有所帮助!

标签: c++ qt model-view-controller


【解决方案1】:

我实际上发现了问题,我的另一个视图没有正确通知数据更改:我的视图每个都显示了我数据的不同部分,因此需要将dataChanged()通知其他视图,但是对于他们自己的,适当的,索引。

顺便说一句,当我的 Qt 应用程序不是我的窗口管理器中的活动窗口时,我还遇到了更新视图的问题。解决方法是在主窗口调用repaint()

【讨论】:

  • 解决方案(调用repaint())对我不起作用。此外,IMO,答案并不完整。应该描述或举例说明如何在代码中使用dataChanged()来达到预期的效果。
【解决方案2】:

我遇到了同样的问题,让我在piwi的答案中添加一个详细的解释。如果您更改数据,以及更新单列或多列(或行,取决于您的要求),您应该发出一组从左上角到右下角的索引。例如,如果您有如下表:

而且,现在您已经更改了一些数据,并且想要更新单元格第 1 行、第 1-2 列,那么您应该发出信号 dataChange

emit datachange(index(1,1),index(1,2));

【讨论】:

  • 如何从模型外部进行操作?也就是说,没有QModelIndexes?
  • 我也面临同样的问题,我的原始表是一个非 Qt 库,我通过 qt 模型使用它,无法获取更改数据的确切索引。
【解决方案3】:

你打电话给setData()吗? dataChanged() 信号真的发出了吗?将一些调试日志插槽连接到它。我敢推测这和你的问题非常相似:

http://www.qtcentre.org/threads/18388-Refreshing-a-QTableView-when-QAbstractTableModel-changes?s=fd88b7c4e59f4487a5457db551f3df2c

【讨论】:

  • 数据已正确更改,dataChanged 在需要时发出,在setData 内;更改确实会立即显示在我正在与之交互的视图上。唯一的问题是显示相同数据的 other 视图需要将鼠标悬停在其上才能显示更改。我正在使用您的链接进行勘探!
  • 关于链接,问题是数据模型被改变但不是通过Qt手段,因此没有发出dataChanged信号;不是我的情况:-/
  • 如何从模型外部进行操作?也就是说,没有QModelIndexes?我不能从整数索引中生成QModelIndexes,因为构造函数是私有的。
猜你喜欢
  • 2017-01-09
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 2011-05-14
  • 1970-01-01
  • 2017-03-04
  • 2011-11-22
  • 2014-07-05
相关资源
最近更新 更多