2017-01-23 2 views
1

В качестве продолжения вопроса я получил решение here несколько дней назад, у меня есть графический интерфейс PyQt4, который включает два PlotWidgets от PyQtGraph, каждый из которых устанавливает/обновляет данные из потокового случайно-присоединяемого массива, вызванного кнопка. Он работает красиво, и графический интерфейс является отзывчивым. Но наступает момент, когда графики перестают показывать обновления внутри своих соответствующих PlotWidgets, и мне нужно минимизировать/максимизировать, чтобы увидеть обновления, созданные внутри PlotWidgets. Код выглядит следующим образом:QThreading PyQtGraph PlotWidgets в PyQt4

import random 
import sys 

import pyqtgraph as pg 
import time 
from PyQt4 import QtGui, QtCore 


class MyThread(QtCore.QThread): 
    def __init__(self, curve, parent=None): 
     super(MyThread, self).__init__(parent=parent) 
     self.curve = curve 
     self.data = [0] 
     app.processEvents()#increases the time the drawings are shown 

    def run(self): 
     app.processEvents() #increases the time the drawings are shown 
     while True: 
      self.data.append(self.data[-1] + 0.2 * (0.5 - random.random())) 
      self.curve.setData(self.data, downsample=10) #crashes without 
      time.sleep(0.1) 


class LoginWidget(QtGui.QWidget): 
    def __init__(self, parent=None): 
     super(LoginWidget, self).__init__(parent) 
     layout = QtGui.QHBoxLayout() 
     self.button = QtGui.QPushButton('Start Plotting') 
     layout.addWidget(self.button) 
     self.plot = pg.PlotWidget() 
     layout.addWidget(self.plot) 
     self.setLayout(layout) 
     self.button.clicked.connect(self.plotter) 
     app.processEvents() 

    def plotter(self): 
     self.curve = self.plot.getPlotItem().plot() 
     myThread = MyThread(self.curve, self) 
     myThread.start() 


class MainWindow(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(MainWindow, self).__init__(parent) 
     self.centralwidget = QtGui.QWidget(self) 
     self.setCentralWidget(self.centralwidget) 
     self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget) 
     self.login_widget_1 = LoginWidget(self) 
     self.horizontalLayout.addWidget(self.login_widget_1) 
     self.login_widget_2 = LoginWidget(self) 
     self.horizontalLayout.addWidget(self.login_widget_2) 
     self.setCentralWidget(self.centralwidget) 


if __name__ == '__main__': 
    global app 
    app = QtGui.QApplication(sys.argv) 
    w = MainWindow() 
    w.show()  
    sys.exit(app.exec_()) 

Любой ключ или обходной путь для того, что я могу сделать для того, чтобы не развернуть/свернуть, чтобы получить обновления в GUI сделает меня невероятно рад.

Следуя советам из @ImportanceOfBeingErnest в ответ ниже, я попытался после Python Wiki для подключения графического интерфейса пользователя и нитку с сигналами и слотами как:

import random 
import sys 
import pyqtgraph as pg 
import time 
from PyQt4 import QtGui, QtCore 


class MyThread(QtCore.QThread): 
    def __init__(self, parent=None): 
     super(MyThread, self).__init__(parent=parent) 
     self.data = [0] 

    def run(self): 
     while True: 
      self.data.append(self.data[-1] + 0.2 * (0.5 - random.random())) 
      self.emit(SIGNAL("output(data)"), self.data) 
      time.sleep(0.1) 


class LoginWidget(QtGui.QWidget): 
    def __init__(self, parent=None): 
     super(LoginWidget, self).__init__(parent) 
     self.myThread = MyThread() 
     layout = QtGui.QHBoxLayout() 
     self.button = QtGui.QPushButton('Start Plotting') 
     layout.addWidget(self.button) 
     self.plot = pg.PlotWidget() 
     layout.addWidget(self.plot) 
     self.setLayout(layout) 
     self.button.clicked.connect(self.plotter) 
     self.connect(self.myThread, SIGNAL("output(data)"), self.plotter) 

    def plotter(self, data): 
     self.curve = self.plot.getPlotItem().plot() 
     self.curve.setData(data, downsample=10) 


class MainWindow(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(MainWindow, self).__init__(parent) 
     self.centralwidget = QtGui.QWidget(self) 
     self.setCentralWidget(self.centralwidget) 
     self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget) 
     self.login_widget_1 = LoginWidget(self) 
     self.horizontalLayout.addWidget(self.login_widget_1) 
     self.login_widget_2 = LoginWidget(self) 
     self.horizontalLayout.addWidget(self.login_widget_2) 
     self.setCentralWidget(self.centralwidget) 


if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    w = MainWindow() 
    w.show() 
    sys.exit(app.exec_()) 

Но это дает мне ошибку:

"in self.connect(self.myThread, SIGNAL("output(data)"), self.plotter) 
NameError: name 'SIGNAL' is not defined" 

читая question from 4 years ago, я заменяю СИГНАЛ на QtCore.SIGNAL, чтобы получить следующее сообщение об ошибке:

"in self.connect(self.myThread, QtCore.SIGNAL("output(data)"), self.plotter) 
TypeError: C++ type 'data' is not supported as a slot argument type" 

Тогда регистр не в TypeError, как:

try: 
    self.connect(self.myThread, QtCore.SIGNAL("output(data)"), self.plotter) 
except TypeError: 
    pass 

Графический интерфейс запускается, но когда я, наконец, нажмите на кнопку и подключить к функции self.plotter я получаю следующее сообщение об ошибке:

"in plotter 
self.curve.setData(data, downsample=10) 
File "C:\Users\iyv\AppData\Local\Programs\Python\Python34_64\lib\site- 
packages\pyqtgraph\graphicsItems\PlotDataItem.py", line 381, in setData 
raise Exception('Invalid data type %s' % type(data)) 
Exception: Invalid data type <class 'bool'>" 

Я довольно смущен. Должен ли я связаться с PyQtGraph? Любая помощь с благодарностью приветствовалась.

+0

Я отредактировал свой ответ ниже, чтобы показать рабочий пример. – ImportanceOfBeingErnest

ответ

2

Вам нужно, чтобы графический интерфейс и поток были отделены друг от друга. В этом случае они не должны использовать какой-либо объект GUI, например, виджет графика.

Я не уверен, нужна ли вам потоковая передача, так как ваши данные не очень большие и обновляются только 10 раз в секунду. Но если вы решите использовать его, используйте только signals and slots для связи между потоком и графическим интерфейсом.


Ниже представлена ​​измененная версия вашей программы, которая использует потоки и отлично работает. Он использует новый стиль signals and slots. Это, надеюсь, легче понять, потому что вы можете просто использовать object как тип данных.

Две вещи шляпы делают никакого смысла в вашей программе нет:

  • переопределения self.curve в слоте черчения.
  • вы вызываете слот для печати при нажатии кнопки. Вместо этого нажимайте кнопку, чтобы начать поток.

Я исправил их.

import random 
import sys 
import pyqtgraph as pg 
import time 
from PyQt4 import QtGui, QtCore 


class MyThread(QtCore.QThread): 
    signal = QtCore.pyqtSignal(object) 
    def __init__(self, parent=None): 
     super(MyThread, self).__init__(parent=parent) 
     self.data = [0] 

    def __del__(self): 
     self.exiting = True 
     self.wait() 

    def run(self): 
     while True: 
      self.data.append(random.random()) 
      self.signal.emit(self.data) 
      time.sleep(0.1) 


class LoginWidget(QtGui.QWidget): 
    def __init__(self, parent=None): 
     super(LoginWidget, self).__init__(parent) 
     self.myThread = MyThread() 
     layout = QtGui.QHBoxLayout() 
     self.button = QtGui.QPushButton('Start Plotting') 
     layout.addWidget(self.button) 
     self.plot = pg.PlotWidget() 
     layout.addWidget(self.plot) 
     self.setLayout(layout) 
     self.curve = self.plot.getPlotItem().plot() 
     self.button.clicked.connect(self.start) 


    def plotter(self, data): 
     self.curve.setData(data) 

    def start(self): 
     self.myThread.start() 
     self.myThread.signal.connect(self.plotter) 


class MainWindow(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(MainWindow, self).__init__(parent) 
     self.centralwidget = QtGui.QWidget(self) 
     self.setCentralWidget(self.centralwidget) 
     self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget) 
     self.login_widget_1 = LoginWidget(self) 
     self.horizontalLayout.addWidget(self.login_widget_1) 
     self.login_widget_2 = LoginWidget(self) 
     self.horizontalLayout.addWidget(self.login_widget_2) 
     self.setCentralWidget(self.centralwidget) 


if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    w = MainWindow() 
    w.show() 
    sys.exit(app.exec_()) 
Смежные вопросы