描述:在主UI线程中,启动了一个子线程进行计算,计算完毕,回调更新UI中的一个tabelview。界面已经更新,但是线程出现报错。
程序结构QObject: Cannot create children for a parent that is in a different thread.
(Parent is QHeaderView(0x1ec5ce55eb0), parent's thread is QThread(0x1ec4d609c30), current thread is BigWorkThread(0x1ec5cdd4820)
QBasicTimer::start: Timers cannot be started from another thread
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QHeaderView(0x1ec5ce58d70), parent's thread is QThread(0x1ec4d609c30), current thread is BigWorkThread(0x1ec5cdd4820)
QBasicTimer::start: Timers cannot be started from another thread
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QTableView(0x1ec4d629d40), parent's thread is QThread(0x1ec4d609c30), current thread is BigWorkThread(0x1ec5cdd4820)
以下是回调函数:
#线程计算完毕,回调,显示计算结果
def display_result_df_callBack(self, df):
model = pandasModel(df)
view = self.tableView_result
view.setModel(model) #调试后发现,这一句是报错的根源
view.show()
logging.info("回调函数")
查询后发现:
It is not good to access the model directly from another thread since the QObjects are not thread-safe, instead it creates a QObject that sends the data to the main thread through signals, in this case for a simple operation I created the slot update_item that receives the row, column and data.
How to correctly update view in pyQt after editing abstract model in another thread?
import sys
import threading
import time
from PyQt5 import QtCore, QtGui, QtWidgets
class CopterDataModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None):
super(CopterDataModel, self).__init__(parent)
self.data_contents = [[1, 2]]
def rowCount(self, n=None):
return len(self.data_contents)
def columnCount(self, n=None):
return 2
def data(self, index, role):
row = index.row()
col = index.column()
# print('row {}, col {}, role {}'.format(row, col, role)) #for debug
if role == QtCore.Qt.DisplayRole:
return self.data_contents[row][col] or ""
def setData(self, index, value, role=QtCore.Qt.EditRole):
if not index.isValid():
return False
if role == QtCore.Qt.EditRole:
self.data_contents[index.row()][index.column()] = value
print("edit", value)
self.dataChanged.emit(
index, index, (QtCore.Qt.EditRole,)
) # NOT WORKING
else:
return False
return True
def flags(self, index):
return QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled
@QtCore.pyqtSlot(int, int, QtCore.QVariant)
def update_item(self, row, col, value):
ix = self.index(row, col)
self.setData(ix, value)
class SignalManager(QtCore.QObject):
fooSignal = QtCore.pyqtSignal(int, int, QtCore.QVariant)
if __name__ == "__main__":
def timer(obj):
idc = 1001
while True:
obj.fooSignal.emit(0, 0, idc)
idc += 1
time.sleep(1)
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)
foo = SignalManager()
tableView = QtWidgets.QTableView()
myModel = CopterDataModel()
foo.fooSignal.connect(myModel.update_item)
tableView.setModel(myModel)
tableView.show()
t = threading.Thread(target=timer, args=(foo,), daemon=True)
t.start()
app.exec_()
解决方法:
线程中在定义一个信号(名字:displayResultAfterCalculating(list)----计算完毕显示计算结果,返回一个list,list中装一个dataframe)
线程计算完毕后:带上计算结果,发送一个该信号
主线程接收信号,并用该计算结果更新ui
结束!!!!
网友评论