Обновления виджетов основного потока данными из дополнительного потока
Написал функцию для обновления виджетов, но когда дело дошло до обновления виджета textEdit
, в который нужно поместить разные данные из БД, перестало все получаться.
В классе написал sql запрос, чтобы он при сканировании инвентарника искал и сравнивал в БД, и после всю строку выводил в отдельные виджеты.
Подскажите, что можно сделать чтобы данные выводил и не выдавал ошибок.
Сама функция:
class ProgressBarThread(QThread):
def __init__(self, mainwindow, parant=None):
super().__init__()
self.mainwindow = mainwindow
def AddTextEdit(self):
conn = sqlite3.connect(DeviceBase)
cursor = conn.cursor()
Inv = """SELECT Inv FROM DeviceList WHERE Inv = res1[0][0]"""
Model = """SELECT Model FROM DeviceList WHERE Inv = ?"""
Serial = """SELECT Serial FROM DeviceList WHERE Inv = ?"""
Owner = """SELECT Owner FROM DeviceList WHERE Inv = ?"""
Location = """SELECT Location FROM DeviceList WHERE Inv = ?"""
cursor = conn.cursor()
cursor.execute(Inv, (res1[0][0],))
inv = cursor.fetchone()
cursor.execute(Model, (res1[0][0],))
model = cursor.fetchone()
cursor.execute(Serial, (res1[0][0],))
serial = cursor.fetchone()
cursor.execute(Owner, (res1[0][0],))
owner = cursor.fetchone()
cursor.execute(Location, (res1[0][0],))
location = cursor.fetchone()
conn.commit()
return inv, model, serial, owner, location
def run(self):
global res1
global test_rfid
current_rfid = ''
while True:
self.mainwindow.pushButton_2.setEnabled(True)
with open(textbase) as file:
RFID_original = file.readlines()[-1]
RFID = RFID_original.partition(';')[0]
if current_rfid != RFID:
font = QFont("Arial", 8)
self.mainwindow.RFID_Label.setFont(font)
self.mainwindow.RFID_Label.setText(RFID_original)
if RFID in str(RFID_list):
*res1, = list(filter(lambda x: x[1] == RFID, RFID_list))
res1 = np.array(res1)
self.mainwindow.Device_Label.setText(f"<html><head/><body><p align=\"center\"><span style=\" font-size:20pt; font-weight:600;\">{str(res1[0][0])}</span></p></body></html>")
current_rfid = RFID
for item in DeviceList:
if str(res1[0][0]) == str(item[0]):
inv, model, serial, owner, location = self.AddTextEdit()
self.mainwindow.textEdit.setText(" ".join(str(cell) for cell in inv))
self.mainwindow.textEdit_2.setText(" ".join(str(cell) for cell in model))
self.mainwindow.textEdit_3.setText(" ".join(str(cell) for cell in serial))
self.mainwindow.textEdit_4.setText(" ".join(str(cell) for cell in owner))
self.mainwindow.textEdit_5.setText(" ".join(str(cell) for cell in location))
else:
test_rfid = RFID
self.mainwindow.pushButton_2.setEnabled(True)
time.sleep(1)
Ответы (1 шт):
Вы не предоставляете минимально-воспроизводимый пример, который демонстрирует проблему и в этом ВАША ОСНОВНАЯ ПРОБЛЕМА.
Но я вижу, что вы уже давно не можете решить проблему и попробую вам помочь.
Запомните, что нельзя взаимодействовать с виджетами в дополнительном потоке.
Т.е. элементы графического интерфейса (все, что унаследовано или связано с подклассом QWidget
) должны быть созданы и доступны только из основного потока Qt.
Еще раз, графический интерфейс не должен обновляться непосредственно в другом потоке, который не является основным потоком, и это также означает, что вы не должны создавать виджеты в другом потоке читайте Основы работы с потоками
Сигналы и слоты используются для связи между объектами.
Механизм сигналов и слотов является центральной особенностью Qt и, вероятно, той частью, которая больше всего отличается от функций, предоставляемых другими платформами.
Также внимательно читаем Support for Signals and Slots
и то что я написал в комментариях кода.
Очень приблизительно ваш код может выглядеть так:
# Какие-то импорты
RFID_list = ???
DeviceList = ???
textbase = ???
class ProgressBarThread(QThread):
values_changed = pyqtSignal(object) # 1 создаем сигналы
label_changed = pyqtSignal(str, str) # 2
def __init__(self):
super().__init__()
# self.mainwindow = mainwindow
self.res1 = None # ?
self.test_rfid = None # ?
def run(self):
# забудьте про глобальные переменные
# global res1
# global test_rfid
current_rfid = ''
while True:
# self.mainwindow.pushButton_2.setEnabled(True)
with open(textbase) as file:
RFID_original = file.readlines()[-1]
RFID = RFID_original.partition(';')[0]
if current_rfid != RFID:
# font = QFont("Arial", 8)
# self.mainwindow.RFID_Label.setFont(font)
# self.mainwindow.RFID_Label.setText(RFID_original)
self.label_changed.emit('RFID_Label', str(RFID_original)) # !!! 5
self.msleep(10)
if RFID in str(RFID_list):
*res1, = list(filter(lambda x: x[1] == RFID, RFID_list))
res1 = np.array(res1)
# self.mainwindow.Device_Label.setText(f"<html><head/><body><p align=\"center\"><span style=\" font-size:20pt; font-weight:600;\">{str(res1[0][0])}</span></p></body></html>")
text = f"<html><head/><body><p align=\"center\"><span style=\" font-size:20pt; font-weight:600;\">{str(res1[0][0])}</span></p></body></html>"
self.label_changed.emit('Device_Label', text) # !!! 5
self.msleep(10)
current_rfid = RFID
for item in DeviceList:
if str(res1[0][0]) == str(item[0]):
inv, model, serial, owner, location = self.addTextEdit()
# Излючаем сигнал и передаем аргументы подключенному слоту
# !!! 5
self.values_changed.emit((inv, model, serial, owner, location))
# self.mainwindow.textEdit.setText(" ".join(str(cell) for cell in inv))
# self.mainwindow.textEdit_2.setText(" ".join(str(cell) for cell in model))
# self.mainwindow.textEdit_3.setText(" ".join(str(cell) for cell in serial))
# self.mainwindow.textEdit_4.setText(" ".join(str(cell) for cell in owner))
# self.mainwindow.textEdit_5.setText(" ".join(str(cell) for cell in location))
else:
test_rfid = RFID
# self.mainwindow.pushButton_2.setEnabled(True)
self.label_changed.emit('pushButton_2', 'True') # !!! 5
self.msleep(1000) # Заставляет текущий поток спать (1000) миллисекунд msecs.
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# я надеюсь что из метода addTextEdit() вы возвращаете то что вам надо
def addTextEdit(self):
conn = sqlite3.connect(DeviceBase)
cursor = conn.cursor()
Inv = """SELECT Inv FROM DeviceList WHERE Inv = res1[0][0]"""
Model = """SELECT Model FROM DeviceList WHERE Inv = ?"""
Serial = """SELECT Serial FROM DeviceList WHERE Inv = ?"""
Owner = """SELECT Owner FROM DeviceList WHERE Inv = ?"""
Location = """SELECT Location FROM DeviceList WHERE Inv = ?"""
cursor = conn.cursor()
cursor.execute(Inv, (res1[0][0],))
inv = cursor.fetchone()
cursor.execute(Model, (res1[0][0],))
model = cursor.fetchone()
cursor.execute(Serial, (res1[0][0],))
serial = cursor.fetchone()
cursor.execute(Owner, (res1[0][0],))
owner = cursor.fetchone()
cursor.execute(Location, (res1[0][0],))
location = cursor.fetchone()
conn.commit()
return inv, model, serial, owner, location
# очень приблизительный вариан того что у вас написано, я так думаю
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
...
self.pushButton_2 = QPushButton()
self.RFID_Label = QLabel()
font = QFont("Arial", 8)
self.RFID_Label.setFont(font)
self.Device_Label = QLabel()
self.textEdit = QTextEdit()
self.textEdit_2 = QTextEdit()
self.textEdit_3 = QTextEdit()
self.textEdit_4 = QTextEdit()
self.textEdit_5 = QTextEdit()
...
# я незнаю каким событием вы запускаете дополнительный поток
# пость это будет вызов метода startThread(), сделайте это как там у вас
def startThread(self):
self.thread = ProgressBarThread() # !!!
self.thread.values_changed.connect(self.slot_values_changed) # !!! 3
self.thread.label_changed.connect(self.slot_value_label) # !!! 4
self.thread.start() # !!!
self.pushButton_2.setEnabled(True)
def slot_value_label(self, name, value_changed): # !!! 6
#print(f'{name}: {value_changed}')
if name = 'RFID_Label':
self.RFID_Label.setText(value_changed)
elif name = 'Device_Label':
self.Device_Label.setText(value_changed)
elif name = 'pushButton_2':
self.pushButton_2.setEnabled(True)
def slot_values_changed(self, values_changed): # !!! 6
#print(f'{values_changed}')
inv, model, serial, owner, location = values_changed
self.textEdit.setText(" ".join(str(cell) for cell in inv))
self.textEdit_2.setText(" ".join(str(cell) for cell in model))
self.textEdit_3.setText(" ".join(str(cell) for cell in serial))
self.textEdit_4.setText(" ".join(str(cell) for cell in owner))
self.textEdit_5.setText(" ".join(str(cell) for cell in location))
...