Форум программистов, компьютерный форум, киберфорум
Python: GUI, графика
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.80/15: Рейтинг темы: голосов - 15, средняя оценка - 4.80
5 / 0 / 0
Регистрация: 20.09.2019
Сообщений: 26

Зависают виджеты созданные библиотекой PyQt5 при использовании многопоточной библиотеки QThread

04.08.2021, 21:10. Показов 3181. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Уважаемые знатоки. Проблема следующая.
Написал простенькую программу которая принимает данные извне. В данную программу в любой момент времени приходят данные (целочисленные значения типа Int).
В моём коде для наглядной иллюстрации приход данных имитируется функцией (make_data) Main класса. Данная функция запускается вторым потоком из класса DataMaker путем нажатия на кнопку Start.
После нажатия кнопки в программу раз в 1 секунду начинает приходить список из четырёх числе (10, 20, 11, 21).
Проходимся по данному списку через цикл for и определяем переменные index и key. Index это первая цифра числа, а key это вторая цифра.
Если вторая (key) цифра равна нулю, то изменяем цвет лейбла (mark_0 или mark_1) на зеленый в зависимости от того какая (index) цифра была первой (1 или 2) при помощи метода (activate_mark)
Если же вторая (key) цифра была 1, то добавляем к значению списка self.result_list[index] единицу и при помощи метода insetr_in_winget отражаем значение из списка в одном из (point_0 или point_1). Далее также зажигаем зеленом нужный из (mark_0 или mark_1) при помощи метода (activate_mark).
Далее создается новый поток при помощи метода (deactivate_mark) и снова меняет цвет (mark_0 или mark_1) на красный. Тем самым программа показывает исправный прием данных.
Также кнопками Clear можно обнулить значения в result_list, а кнопкой Stop остановить прием данных.

Суть проблемы следующая. Если дать программе немного поработать, то визуализация зависнет т.е. значения в (point_0 или point_1) и (mark_0 или mark_1) перестанут обновляться. Причем в консоль данные при помощи функции print выводиться не перестанут, а значит второй поток исправно работает и значения приходят При нажатии на любую их кнопок Clear в одной графе все обнуляется, а во второй значения начисляются сразу за все пропущенное время. Т.е. если программа зависля на 100 очках в виджетах point и простояла 10 секунд. Я нажимаю на кнопку Clear и в одной графе все очищается, а во вторую начисляются те 10 секунд простоя, что программа не работала.

Помогите, никак не могу побороть данную проблему. Код Xml и самой программы прилагается.
main.py:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import time, sys
from threading import Thread
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QThread
 
 
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = uic.loadUi('gui.ui')
        self.point_tuple = (self.ui.point_0, self.ui.point_1)
        self.mark_tuple = (self.ui.mark_0, self.ui.mark_1)
        self.result_list = [0, 0]
 
        self.subFlow = DataMaker(self.make_data)
 
        self.ui.startBtn.clicked.connect(lambda: self.starter())
        self.ui.stopBtn.clicked.connect(lambda: self.stopper())
        self.ui.clearBtn_0.clicked.connect(lambda: self.clear_point(0))
        self.ui.clearBtn_1.clicked.connect(lambda: self.clear_point(1))
 
    def starter(self):
        self.subFlow.start()
 
    def stopper(self):
        self.subFlow.terminate()
 
    def clear_point(self, index):
        self.result_list[index] = 0
        self.insert_in_widget(index)
 
    def make_data(self):
        data = [10, 20, 11, 21]
        print(data)
        for value in data:
            index = (value // 10) - 1
            key = value % 10
            if key == 1:
                self.result_list[index] += 1
                self.insert_in_widget(index)
            self.activate_mark(index)
            time.sleep(1)
 
    def insert_in_widget(self, index):
        self.point_tuple[index].setText(str(self.result_list[index]))
 
    def activate_mark(self, index):
        self.mark_tuple[index].setStyleSheet('QLabel {background-color: green;}')
        th = Thread(target=self.deactivate_mark, args=(index, ))
        th.start()
 
    def deactivate_mark(self, index):
        time.sleep(0.5)
        self.mark_tuple[index].setStyleSheet('QLabel {background-color: red;}')
 
class DataMaker(QThread):
    def __init__(self, func, parent=None):
        super(DataMaker, self).__init__(parent)
        self.delay = 1
        self.func = func
 
    def run(self):
        while True:
            self.func()
            time.sleep(self.delay)
 
 
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    open = MainWindow()
    open.ui.show()
    app.exec()
gui.ui:

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<?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>273</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Gui</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <widget class="QWidget" name="layoutWidget">
    <property name="geometry">
     <rect>
      <x>100</x>
      <y>70</y>
      <width>611</width>
      <height>51</height>
     </rect>
    </property>
    <layout class="QHBoxLayout" name="horizontalLayout_2">
     <item>
      <widget class="QLabel" name="point_1">
       <property name="styleSheet">
        <string notr="true">font: 24pt &quot;Ubuntu&quot;;</string>
       </property>
       <property name="frameShape">
        <enum>QFrame::Box</enum>
       </property>
       <property name="text">
        <string>0</string>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QLabel" name="mark_1">
       <property name="styleSheet">
        <string notr="true">background-color: rgb(239, 41, 41);</string>
       </property>
       <property name="frameShape">
        <enum>QFrame::Box</enum>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="clearBtn_1">
       <property name="styleSheet">
        <string notr="true">font: 24pt &quot;Ubuntu&quot;;</string>
       </property>
       <property name="text">
        <string>Clear</string>
       </property>
      </widget>
     </item>
    </layout>
   </widget>
   <widget class="QPushButton" name="startBtn">
    <property name="geometry">
     <rect>
      <x>100</x>
      <y>170</y>
      <width>199</width>
      <height>41</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">font: 24pt &quot;Ubuntu&quot;;</string>
    </property>
    <property name="text">
     <string>Start</string>
    </property>
   </widget>
   <widget class="QPushButton" name="stopBtn">
    <property name="geometry">
     <rect>
      <x>510</x>
      <y>170</y>
      <width>199</width>
      <height>41</height>
     </rect>
    </property>
    <property name="styleSheet">
     <string notr="true">font: 24pt &quot;Ubuntu&quot;;</string>
    </property>
    <property name="text">
     <string>Stop</string>
    </property>
   </widget>
   <widget class="QWidget" name="">
    <property name="geometry">
     <rect>
      <x>100</x>
      <y>10</y>
      <width>611</width>
      <height>51</height>
     </rect>
    </property>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QLabel" name="point_0">
       <property name="styleSheet">
        <string notr="true">font: 24pt &quot;Ubuntu&quot;;</string>
       </property>
       <property name="frameShape">
        <enum>QFrame::Box</enum>
       </property>
       <property name="text">
        <string>0</string>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QLabel" name="mark_0">
       <property name="styleSheet">
        <string notr="true">background-color: rgb(239, 41, 41);</string>
       </property>
       <property name="frameShape">
        <enum>QFrame::Box</enum>
       </property>
       <property name="text">
        <string/>
       </property>
       <property name="alignment">
        <set>Qt::AlignCenter</set>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="clearBtn_0">
       <property name="styleSheet">
        <string notr="true">font: 24pt &quot;Ubuntu&quot;;</string>
       </property>
       <property name="text">
        <string>Clear</string>
       </property>
      </widget>
     </item>
    </layout>
   </widget>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>22</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.08.2021, 21:10
Ответы с готовыми решениями:

QT: лаги программы при использовании QVector<QThread>
Создал тестовую программу, где реализовал шаблон потоков QVector&lt;VlThread*&gt;. vlthread.h: #ifndef VLTHREAD_H #define VLTHREAD_H ...

PyQt5 QThread
Здравствуйте форумчане. Собственно решил побаловаться с потоками в PyQt5. Придумал небольшую учебную задачку для себя по данной теме. ...

Ошибка при установке библиотеки pyqt5-tools
Добрый вечер, возникла проблема с инсталляцией библиотеки pyqt5-tools, которая нужна мне для перевода файлов формата .ui в .py....

5
290 / 205 / 68
Регистрация: 18.09.2019
Сообщений: 407
Записей в блоге: 58
04.08.2021, 22:51
Как интересно! Вот буквально позавчера была тема Отображение главного окна программы | QThread просто близнец поднятой Вами. И Вас тоже не остановило прямое указание в документации Qt, что GUI исполняется исключительно в главном потоке, иначе называемом GUI-потоком. Фантастика!

Добавлено через 3 минуты
И вот эта тоже позавчера была Не до конца закрывается программа с бесконечным циклом while
Как-то кучно пошло.

Добавлено через 19 минут
И тут https://doc.qt.io/qt-5/threads-technologies.html тоже вроде бы ясно расписаны пределы применимости разных вариантов использования QThread и способ получения данных от QThread.
0
290 / 205 / 68
Регистрация: 18.09.2019
Сообщений: 407
Записей в блоге: 58
05.08.2021, 09:20
А самое печальное, что тут даже обсуждать-то нечего - Ваше решение просто неприменимо.
0
 Аватар для kapbepucm
1567 / 740 / 321
Регистрация: 02.05.2020
Сообщений: 1,659
06.08.2021, 10:39
Лучший ответ Сообщение было отмечено Удалов Павел как решение

Решение

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import sys
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QThread, pyqtSignal, QTimer
 
class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.ui = uic.loadUi('gui.ui')
        self.point_tuple = (self.ui.point_0, self.ui.point_1)
        self.mark_tuple = (self.ui.mark_0, self.ui.mark_1)
        self.result_list = [0, 0]
 
        self.subFlow = DataMaker()
 
        self.ui.startBtn.clicked.connect(self.starter)
        self.ui.stopBtn.clicked.connect(self.stopper)
        self.ui.clearBtn_0.clicked.connect(lambda: self.clear_point(0))
        self.ui.clearBtn_1.clicked.connect(lambda: self.clear_point(1))
        self.subFlow.insert.connect(self.insert_in_widget)
        self.subFlow.activate.connect(self.activate_mark)
 
    def starter(self):
        self.subFlow.start()
 
    def stopper(self):
        self.subFlow.terminate()
 
    def clear_point(self, index):
        self.result_list[index] = -1
        self.insert_in_widget(index)
 
    def insert_in_widget(self, index):
        self.result_list[index] += 1
        self.point_tuple[index].setText(str(self.result_list[index]))
 
    def activate_mark(self, index):
        self.mark_tuple[index].setStyleSheet('QLabel {background-color: green;}')
        QTimer.singleShot(500, lambda i=index: self.deactivate_mark(i))
 
    def deactivate_mark(self, index):
        self.mark_tuple[index].setStyleSheet('QLabel {background-color: red;}')
 
class DataMaker(QThread):
    insert = pyqtSignal(int)
    activate = pyqtSignal(int)
    def __init__(self, parent=None):
        super(DataMaker, self).__init__(parent)
        self.delay = 1
 
    def run(self):
        while True:
            self.make_data()
            QThread.sleep(self.delay)
 
    def make_data(self):
        data = [10, 20, 11, 21]
        print(data)
        for value in data:
            index = (value // 10) - 1
            key = value % 10
            if key == 1:
              self.insert.emit(index)
            self.activate.emit(index)
            QThread.sleep(1)
 
if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    open = MainWindow()
    open.ui.show()
    app.exec_()
3
290 / 205 / 68
Регистрация: 18.09.2019
Сообщений: 407
Записей в блоге: 58
06.08.2021, 12:20
Спасибо, kapbepucm! Умыл Во как можно! И даже terninate() без матов. Век живи, век учись...
0
5 / 0 / 0
Регистрация: 20.09.2019
Сообщений: 26
08.08.2021, 13:28  [ТС]
Спасибо большое, kapbepucm. Решение крылось в сигналах и слотах.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
08.08.2021, 13:28
Помогаю со студенческими работами здесь

Добрый день, возникла проблема: при попытке импортировать из библиотеки PyQt5!
Добрый день, возникла проблема: при попытке импортировать из библиотеки PyQt5, импортируемые объекты выделяются как ошибки =&gt; при...

Проблема с библиотекой PyQT5
Здравствуйте, не устанавливается библиотека PyQT5

Ошибка при использовании библиотеки
Traceback (most recent call last): File &quot;*путь файла*&quot;, line 1, in &lt;module&gt; from PIL import Image ModuleNotFoundError: No...

Почему при нажатии кнопки при использовании библиотеки createjs функция запускается несколько раз?
Здравствуйте, на creatjs делаю переключения между уровнями. Когда нажимаю на кнопку то уровень очищается и появляются новые объекты, щелкаю...

Ошибка при использовании библиотеки getch
У меня ошибка при использовании библиотеки getch Ввожу: import getch print(getch.getch()) Вывод:


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
[Owen Logic] Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора
ФедосеевПавел 14.03.2026
Поддержание уровня воды в резервуаре количеством включённых насосов: моделирование и выбор регулятора ВВЕДЕНИЕ Выполняя задание на управление насосной группой заполнения резервуара,. . .
делаю науч статью по влиянию грибов на сукцессию
anaschu 13.03.2026
прикрепляю статью
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru