3

I have class Ui_MainWindow(object) that creates a window with a progress bar and class OtherClass(object) that contains method in which the local int variable increments in cycle.

How to connect local variable value change to progres bar value change?

mainGUI.py

import sys
from PyQt4.uic.Compiler.qtproxies import QtGui
from PyQt4 import QtGui
from Ui_MainWindow import Ui_MainWindow

def main():

    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())



if __name__ == '__main__':
    main()

Ui_MainWindow.py

from PyQt4 import QtCore, QtGui
from MainGui.OtherClass import OtherClass

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

class Ui_MainWindow(object):

    def myButtonSlot(self):
        objVar=OtherClass()
        objVar.method()

    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(389, 332)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))

        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        self.pushButton.clicked.connect(self.myButtonSlot)
        self.verticalLayout.addWidget(self.pushButton)

        self.progressBar = QtGui.QProgressBar(self.centralwidget) 
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName(_fromUtf8("progressBar"))

        self.verticalLayout.addWidget(self.progressBar)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 389, 21))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.setText(QtGui.QApplication.translate("MainWindow", "PushButton", None, QtGui.QApplication.UnicodeUTF8))  

OtherClass.py

class OtherClass(object):  
    def method(self):
        for i in range(100): # i want to connect variable i to progress bar value
            print i 
            for j in range(100500):
                pass
Sashko Lykhenko
  • 1,554
  • 4
  • 20
  • 36

3 Answers3

10

You need to re-organize your code a little bit.

Firstly, you should never edit the code in the UI module generated by pyuic. Instead, import it into your main module and implement all your application logic there.

Secondly, you should create a main-window class in your main module, and do all the setup inside its __init__ method.

One way to solve your problem of connecting the loop variable to the progress bar, is to make OtherClass a subclass of QObject and emit a custom signal:

from PyQt4 import QtCore

class OtherClass(QtCore.QObject):
    valueUpdated = QtCore.pyqtSignal(int)

    def method(self):
        # i want to connect variable i to progress bar value
        for i in range(100):
            print i
            self.valueUpdated.emit(i)
            for j in range(100500):
                pass

With that in place, you would then move the setup for pushButton and its slot to "mainGUI.py", and re-generate "Ui_MainWindow.py" with pyuic. A slot would then be added to handle the custom valueChanged signal, which would update the progress bar and also process any pending GUI events.

So "mainGUI.py" would end up looking something like this:

import sys
from PyQt4 import QtGui
from Ui_MainWindow import Ui_MainWindow
from OtherClass import OtherClass

class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        self.setupUi(self)
        self.pushButton.clicked.connect(self.myButtonSlot)
        self.otherclass = OtherClass(self)
        self.otherclass.valueUpdated.connect(self.handleValueUpdated)

    def myButtonSlot(self):
        self.otherclass.method()

    def handleValueUpdated(self, value):
        self.progressBar.setValue(value)
        QtGui.qApp.processEvents()

def main():
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

if __name__ == '__main__':

    main()
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
4

The following post has a version that increments the progress bar 10% each time you press the button. And a version which uses a timer to increment the progress bar. (I'm just in the process of learning this myself)

In Qt Designer, add a progress bar and a button. Click on 'Edit Signals/Slots', drag a line from the button to somewhere in the window and when the button is 'pressed()' add a slot(or signal??) called 'button_pressed()' (use the + button to make this). When you have done this, the OK button is greyed out - select the slot you made, and press OK.

Save the file as ui_MainWindow.ui (note the capitals carefully). Convert to a py file using the batch file >

pyuic4 -x ui_MainWindow.ui -o ui_MainWindow.py

This file should look something like....(you don't need to edit this).

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(800, 600)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.progressBar = QtGui.QProgressBar(self.centralwidget)
        self.progressBar.setGeometry(QtCore.QRect(110, 90, 118, 23))
        self.progressBar.setProperty("value", 24)
        self.progressBar.setObjectName(_fromUtf8("progressBar"))
        self.pushButton = QtGui.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(120, 200, 75, 23))
        self.pushButton.setObjectName(_fromUtf8("pushButton"))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("pressed()")), MainWindow.button_pressed)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.pushButton.setText(_translate("MainWindow", "PushButton", None))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Create a 'program.py' file. This is the file you will run...

import sys
from PyQt4 import QtGui
#from PyQt5 import QtCore, QtGui, QtWidgets #works for pyqt5
from mainWindow import MainWindow

def main():
    #app = QtWidgets.QApplication (sys.argv) #works for pyqt5
    app = QtGui.QApplication (sys.argv) #works for pyqt4
    m = MainWindow ()
    m.show ()
    sys.exit (app.exec_ () )

if __name__ == '__main__':
    main ()

Now this is where the good stuff happens when you subclass the mainwindow. Call this file 'mainWindow.py'. Careful with the capitalizations.

from PyQt4 import QtCore, QtGui
from ui_MainWindow import Ui_MainWindow #note the capitalization

class MainWindow (QtGui.QMainWindow):
    def __init__ (self, parent = None):
        super (MainWindow, self).__init__ ()
        self.ui = Ui_MainWindow ()
        self.ui.setupUi (self)
        #------------do your custom stuff from here on-----------
        self.progress = 0 #Start value of progress bar
        self.ui.progressBar.setValue(self.progress)

    def button_pressed(self):
        print('button pressed')
        self.ui.statusbar.showMessage(str(self.progress)) #this is at bottom left of window. Discovered this accidentially when doing this!
        self.ui.progressBar.setValue(self.progress)
        self.progress+=10

There is a good tutorial here which I used to create an alternate 'mainWindow.py' which uses a timer to increment the progress bar. It does not block the code with a loop using sleep or by doing a CPU intensive loop. I don't understand multithreading, multi-processor options yet to comment on using these.

#from PyQt5 import QtCore, QtGui, QtWidgets #works for PyQt5
from PyQt4 import QtCore, QtGui
from ui_MainWindow import Ui_MainWindow #note the capitalization

class MainWindow (QtGui.QMainWindow):
    def __init__ (self, parent = None):
        super (MainWindow, self).__init__ ()
        self.ui = Ui_MainWindow () #same name as appears in mainWindowUi.py
        self.ui.setupUi (self)
        self.progress = 0 #Start value of progress bar
        self.ui.progressBar.setValue(self.progress)

        self.timer = QtCore.QBasicTimer()

    def button_pressed(self):
        self.timerEvent(64) #this needs an argument to work but I'm not sure what is is yet so I just put in some random number

    def timerEvent(self, e):
        self.ui.progressBar.setValue(self.progress)
        if self.progress >=100:
            self.timer.stop()
       else:
            if self.timer.isActive():
                pass
            else:
                self.timer.start(10,self) #10 milliseconds
        self.progress+=1
Ninga
  • 689
  • 7
  • 14
1

You have to use a signal and slot...and multiprocessing or multithreading.

There's a good example here that specifically takes you through the progress bar: ZetCode Progress Bar

Also, question has been answered here before: SO Progress Bar

Community
  • 1
  • 1
catwalker333
  • 213
  • 1
  • 7