使用qt6.2.3开发列表,发现在删除行的时候,会出现无响应,CPU飙升,如下图所示
经过排查,最终定位为QAbstractItemModelPrivate::rowsRemoved方法,如下图所示
当前persistent_moved的大小为table的(row * column)
persistent_moved是在QAbstractItemModelPrivate::rowsAboutToBeRemoved里由persistent.indexes决定的,如下图所示
通过抓取窗体windows消息,发现是由WM_GETOBJECT导致persistent.indexes飙升,参考https://learn.microsoft.com/zh-cn/windows/win32/winauto/wm-ge...,UI自动化程序获取到了窗体句柄,QT处理该消息,进而持久化index
原因
有自动化程序调用了如下代码(python):
import uiautomation as ui
MainWin = ui.WindowControl(searchDepth=1, ClassName='TaskManagerWindow')
DataGrid = MainWin.DataGridControl(searchDepth=5, ClassName='TmScrollViewer')
TaskList = DataGrid.GetChildren()
解决方法
- 重载QMainWindow的nativeevent方法,拦截WM_GETOBJECT消息即可
- 不使用endremoverows,删除也使用beginresetmodel()和endresetmodel()
在main函数里自定义QAcessible的updateHandler方法,使之不做任何事
QAccessible::installUpdateHandler([](QAccessibleEvent* event) { // do nothing });
测试代码
#include "mainwindow.h"
#include <QApplication>
#include <QAccessible>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QAccessible::installUpdateHandler([](QAccessibleEvent* event) {
// do nothing
});
MainWindow w;
w.show();
return a.exec();
}
#ifndef MYMODEL_H
#define MYMODEL_H
#include <QAbstractTableModel>
class MyModel : public QAbstractTableModel {
public:
explicit MyModel(QObject* parent = nullptr);
int getPILSize() { return this->persistentIndexList().size(); }
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
};
#endif // MYMODEL_H
#include "mymodel.h"
MyModel::MyModel(QObject *parent)
: QAbstractTableModel{parent}
{}
int MyModel::rowCount(const QModelIndex &parent) const
{
return 100;
}
int MyModel::columnCount(const QModelIndex &parent) const
{
return 20;
}
QVariant MyModel::data(const QModelIndex &index, int role) const
{
return 1;
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MyModel;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result);
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
MyModel * m_model;
int m_getobjectcount = 0;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "mymodel.h"
#include "ui_mainwindow.h"
#ifdef Q_OS_WIN
# include <Windows.h>
# include <windowsx.h>
# pragma comment(lib, "user32.lib")
#endif
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
m_model = new MyModel(this);
ui->tableView->setModel(m_model);
}
MainWindow::~MainWindow() { delete ui; }
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, qintptr* result) {
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_GETOBJECT) {
++m_getobjectcount;
}
return QMainWindow::nativeEvent(eventType, message, result);
}
void MainWindow::on_pushButton_clicked() {
int v = m_model->getPILSize();
ui->label->setText(QString::number(v));
ui->label_2->setText(QString::number(m_getobjectcount));
}
<?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_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>WM_GETOBJECT_COUNT</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>PerIndexCount</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableView" name="tableView"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。