c++ 拖放后更新QHeaderView的模型

rslzwgfq  于 2023-02-10  发布在  其他
关注(0)|答案(1)|浏览(161)

我有一个QTableWidget,其中使用表小部件的QHeaderView示例启用了拖放:
m_tableWidget->verticalHeader()->setSectionsMovable(true);
另外,我已经实现了一个撤销机制。现在,我想实现一个拖放操作可以使用撤销机制来撤销。
对于这个撤销机制,我需要在拖放之前和之后保存数据。假设我有一个方法来存储旧数据,这现在并不重要。
为了存储新数据并将其压入撤消堆栈,我连接到QHeaderViewsectionMoved信号:
connect(m_tableWidget->verticalHeader(), &QHeaderView::sectionMoved, this, &MyTableWidget::dragAndDrop);
然后调用的函数基本上如下所示:

void
MyTableWidget::dragAndDrop(int logicalIndex, int oldVisualIndex, int newVisualIndex)
{
    // Get the table data which is stored in a vector
    auto& tableData = oldVector;
    // Synchronize to reflect the drag & drop change
    auto synchronizedTableData = synchronize(oldVisualIndex, newVisualIndex);
    // Push on the undo stack
    m_undoStack->push(new Undo(synchronizedTableData, oldTableData));
}

最后,撤消堆栈中的函数基本上如下所示:

void
Undo::redo()
{
    tableWidget->setRowCount(synchronizedTableData.size());
    // Apply the synchronized vector data to the table
    for (int i = 0; i < synchronizedTableData.size(); ++i) {
        for (int j = 0; j < synchronizedTableData.at(i).size(); ++j) {
                m_tableWidget->setItem(i, j, new QTableWidgetItem(synchronizedTableData.at(i).at(j).toString()));
            }
        }
    }
}

然而,整个方法有一个重大缺陷:当然,使用垂直标题的拖放操作只会更改视图,而模型本身不会更新。因此,基本上,如果我遍历表格并显示其内容,我仍然会按照拖放操作之前的方式排列项目。现在,如果表格按照undo stack函数中所示进行设置,则视图会被破坏,如下图所示:

如果要将第二行拖动到最后一行之前,则应如下所示:

但是,它看起来像这样:

这看起来就像拖放实际上已经执行了两次:123456 -〉134526 -〉145236。然而,有趣的是,如果我再一次迭代表,数据已经被正确地更改了。所以现在,模型是完整的,但是视图没有被正确地更新。
现在,我猜想我混淆了视图和垂直标题模型之间的某些东西。因此,我的想法是,我可以通过在拖放一行后更新标题后面的模型来解决这个问题。或者,我必须在撤消堆栈中成功更新模型后重新更新视图。
但我不知道如何实现。我仍然不知道到底是什么在标题被调用两次,使视图被改变两次。也许整个方法本身是有缺陷的?任何想法将不胜感激。
先谢了!

u3r8eeie

u3r8eeie1#

所以,我找到了第一个解决方案。然而,它只是作为某种变通办法。
新的想法是,我可以保存头状态并恢复它。

QByteArray m_headerState;

connect(m_tableWidget->verticalHeader(), &QHeaderView::sectionPressed, this, [](int logicalIndex) {
    m_headerState = m_tableWidget->verticalHeader->saveState();
});

所以基本上,每次我想通过拖放来重新排列标题项时,我必须按下这样一个项。我可以用它来存储旧的标题状态。然后,在拖放之后,我可以做以下事情:

void
MyTableWidget::dragAndDrop(int logicalIndex, int oldVisualIndex, int newVisualIndex)
{
    // Restore the old header state
    m_tableWidget->verticalHeader()->restoreState(m_headerState);

    // Get the table data which is stored in a vector
    auto& tableData = oldVector;
    // Synchronize to reflect the drag & drop change
    auto synchronizedTableData = synchronize(oldVisualIndex, newVisualIndex);
    // Push on the undo stack
    m_undoStack->push(new Undo(synchronizedTableData, oldTableData));
}

现在,我在拖放操作后手动恢复这个状态,这当然容易出错,但至少可以防止拖放操作重复。
但是,它本身并没有回答问题。因此,我不会将其标记为答案。但如果其他人可能遇到这个问题,这可能会帮助您。

相关问题