如何避免QListView内部拖拽移动时出现闪烁问题
QListView内部拖拽移动时重复项目闪烁问题解决
问题描述
将QListView与QStandardItemModel关联,启用内部拖拽移动(QAbstractItemView::InternalMove)时,拖拽过程中视图会瞬间显示重复项目,导致明显闪烁,且列表项目越多,该现象越频繁:
before: during: after: item 1 item 1 item 2 item 2 item 2 item 1 item 3 item 1 item 3 item 3
尝试过调整QStandardItemModel::insertRows()、QListView::viewport()->setUpdatesEnabled()、QListView::blockSignals()等方法,均未解决问题。
解决方案
方法一:自定义QListView,控制拖拽过程的视图更新
重写QListView的拖拽事件处理方法,在拖拽过程中临时关闭视图更新,避免临时插入的项目被渲染:
#include <QApplication> #include <QListView> #include <QStandardItemModel> #include <QDragMoveEvent> class CustomListView : public QListView { protected: void dragMoveEvent(QDragMoveEvent* event) override { viewport()->setUpdatesEnabled(false); QListView::dragMoveEvent(event); viewport()->setUpdatesEnabled(true); } void dropEvent(QDropEvent* event) override { viewport()->setUpdatesEnabled(false); QListView::dropEvent(event); viewport()->setUpdatesEnabled(true); viewport()->update(); } }; int main(int argc, char* argv[]) { QApplication a(argc, argv); QStandardItemModel model; for (int i = 0; i < 100; ++i) { QStandardItem* item = new QStandardItem(QString("item %0").arg(i)); item->setDropEnabled(false); model.appendRow(item); } CustomListView list; list.setModel(&model); list.setDragDropMode(QAbstractItemView::InternalMove); list.show(); return a.exec(); }
方法二:重写QStandardItemModel的拖放逻辑,避免临时插入
默认内部拖拽会先插入临时项目再删除原位置项目,重写dropMimeData方法,直接移动项目,从根源消除重复显示:
#include <QApplication> #include <QListView> #include <QStandardItemModel> #include <QMimeData> class CustomItemModel : public QStandardItemModel { public: using QStandardItemModel::QStandardItemModel; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override { if (action != Qt::MoveAction) { return QStandardItemModel::dropMimeData(data, action, row, column, parent); } QModelIndexList sourceIndexes = decodeMimeData(data); if (sourceIndexes.isEmpty()) { return false; } int targetRow = row; if (targetRow == -1) { targetRow = parent.isValid() ? parent.row() : rowCount(); } int sourceRow = sourceIndexes.first().row(); if (sourceRow < targetRow) { targetRow--; } QStandardItem* item = takeItem(sourceRow); insertRow(targetRow, item); return true; } }; int main(int argc, char* argv[]) { QApplication a(argc, argv); CustomItemModel model; for (int i = 0; i < 100; ++i) { QStandardItem* item = new QStandardItem(QString("item %0").arg(i)); item->setDropEnabled(false); model.appendRow(item); } QListView list; list.setModel(&model); list.setDragDropMode(QAbstractItemView::InternalMove); list.show(); return a.exec(); }
方法三:优化视图更新策略
通过调整视图的更新模式和滚动设置,减少不必要的重绘,缓解闪烁:
// 在初始化QListView时添加以下配置 list.setViewportUpdateMode(QListView::SmartViewportUpdate); list.setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); list.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
内容的提问来源于stack exchange,提问作者MrJ
相关产品推荐
相关产品推荐

