71960


pyqt5でQThreadを使って、計算を実行してる最中にプログレスバーを動かしたいです。コードでは左側のプロットをした後、３秒置いて右側のキャンバスにプロットしています。それに伴い、プログレスバーが0%から50%、100%へと変化するようにしたいです。しかし、実際には2つのキャンバスの記述が終わった後に、プログレスバーが一気に100%まで動きます。どのように書き直せばプログレスバーが計算と並行して動作するようになるのでしょうか。

* * *

**表示されるGUI**  
[![画像](https://i.stack.imgur.com/2Yg87.png)](https://i.stack.imgur.com/2Yg87.png)

**ソースコード**

[code]

    import sys
    from PyQt5 import QtGui,QtCore, QtWidgets
    from PyQt5.QtWidgets import *
    from PyQt5.Qt import *
    from PyQt5.QtGui import *
    from matplotlib.figure import Figure
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
    from mpl_toolkits.mplot3d import Axes3D
    import time
    
    
    class External(QThread):
        countChanged = pyqtSignal(int)
        finished = pyqtSignal()
        def __init__(self, parent=None):
            super(External, self).__init__(parent)
            self.win=parent
    
        def run(self):
            #count_v=0
            count_v=self.win.v
            while count_v < 100:
                count_v=self.win.v
                time.sleep(0.1)
                self.countChanged.emit(count_v)     
                #print(count_v)
    
            self.finished.emit()
    
    
    class Main(QDialog):
        def __init__(self, parent=None):
            super(Main, self).__init__(parent)
            
            self.v=0
            self.figure = plt.figure(figsize=(6,6),dpi=100)        
            self.canvas = FigureCanvas(self.figure)
            self.axes = Axes3D(self.figure)
            self.axes.dist=12
    
            self.figure2 = plt.figure(figsize=(6,6),dpi=100)        
            self.canvas2 = FigureCanvas(self.figure2)
            self.axes2 = Axes3D(self.figure2)
            self.axes2.dist=12
            
            self.button = QPushButton('Start')
            self.button.clicked.connect(self.plot)
            self.progress = QProgressBar(self)
            #self.plot()       
            layout=QHBoxLayout()
            layout.addWidget(self.canvas)
            layout.addWidget(self.canvas2)
    
            layout2=QVBoxLayout()
            layout2.addLayout(layout)
            layout2.addWidget(self.button)
            layout2.addWidget(self.progress)
            self.setLayout(layout2)
    
            self.show()
    
        def plot(self):
            self.calc = External(self)
            self.calc.countChanged.connect(self.onCountChanged)
            #self.calc.countChanged.connect(self.progress.setValue)
            self.calc.finished.connect(self.onFinished)
            self.calc.start()
            
            self.v=10
            self.plot1()
            self.v=50
            self.plot2()
            time.sleep(3)
            self.v=100
            
        def plot1(self):
            x = np.arange(-3, 3, 0.25)
            y = np.arange(-6, 6, 0.25)
            X, Y = np.meshgrid(x, y)
            Z = np.sin(X)+ np.cos(Y)
            
            self.axes.plot_surface(X,Y,Z,cmap='jet')
            self.axes.set_xlabel("x")
            self.axes.set_ylabel("y")
            self.axes.set_zlabel("z")
            
            self.canvas.draw()
    
        def plot2(self):
            x = np.arange(-3, 3, 0.25)
            y = np.arange(-6, 6, 0.25)
            X, Y = np.meshgrid(x, y)
            Z = np.sin(X)+ np.cos(Y)
            
            self.axes2.plot_surface(X,Y,Z,cmap='jet')
            self.axes2.set_xlabel("x")
            self.axes2.set_ylabel("y")
            self.axes2.set_zlabel("z")
            
            self.canvas2.draw()
            
        def onCountChanged(self, value):
            self.progress.setValue(value)
            #print(value)
           
        def onFinished(self):
            self.progress.setValue(0)
            print("finished")
            
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        win = Main()
        #sys.exit(app.exec_())
        app.exec_()
    
[/code]


CC BY-SA 4.0
2020-11-14T18:00:56.250
71954
2020-11-15T02:44:03.917
26529
question
python pyqt5
pyqt5でQThreadを使って計算中にプログレスバーを動かしたい


main thread(Qt の application loop) で `time.sleep()` を実行すると main thread
が停止してしまいますので、signal を受け取っても `onCountChanged()` や Qt widget の更新が実行されなくなります。そこで
`time.sleep()` の代わりに
[QTest.qwait()](https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qttest/qtest.html?highlight=qwait#qWait)
を使う方法はどうでしょうか。

※ 現時点(2020/11/15)で `QTest` モジュールのドキュメント全般が `TODO` 状態なので判りづらいかと思いますが。。。

変更点だけ記載します。

[code]

    from PyQt5.QtTest import *  # import QtTest
              :
    
    class Main(QDialog):
              :
    
        def plot(self):
              :        
    
            self.v=10
            self.plot1()
            self.v=50
            QTest.qWait(3000) # add qWait()
            self.plot2()
            #time.sleep(3)
            self.v=100
              :        
    
        def onFinished(self):
            self.progress.setValue(100) # 100%, not 0%
            #self.progress.setValue(0)
            print("finished")
    
[/code]


CC BY-SA 4.0
2020-11-15T02:44:03.917
71960
2020-11-15T02:44:03.917
71954
answer