PyQt:如何在外部变量值更改时动态更新小部件属性?

3

我有一个名为class Ui_MainWindow(object)的类,它创建了一个带有进度条的窗口,还有一个名为class OtherClass(object)的类,其中包含一个在循环中递增的本地整数变量。

如何将本地变量值的更改与进度条值的更改相连接?

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

请展示一下你目前的代码。 - ekhumoro
3个回答

10

你需要稍微重新组织一下代码。

首先,你应该永远不要编辑由pyuic生成的UI模块中的代码。相反,将其导入到主模块中,在那里实现所有应用逻辑。

其次,你应该在主模块中创建一个主窗口类,并在其__init__方法中完成所有设置。

解决将循环变量连接到进度条的问题的一种方法是,将OtherClass作为QObject的子类,并发出自定义信号:

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

有了这个设置,您将把pushButton和它的插槽的设置移动到"mainGUI.py"中,并使用pyuic重新生成"Ui_MainWindow.py"。然后会添加一个插槽来处理自定义valueChanged信号,它会更新进度条并处理任何挂起的GUI事件。

因此,"mainGUI.py"最终会看起来像这样:

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()

4
以下文章有两个版本,一个是每次按按钮时将进度条增加10%的版本。另一个版本使用计时器来增加进度条。(我自己正在学习这个过程)
在Qt Designer中,添加一个进度条和一个按钮。单击“编辑信号/槽”,从按钮向窗口中的某个位置拖动一条线,并在按钮被“pressed()”时添加一个名为“button_pressed()”的槽(或信号??)(使用+按钮进行创建)。完成后,OK按钮变灰 - 选择您创建的槽,并按OK。
将文件保存为ui_MainWindow.ui(请注意大写字母)。 使用批处理文件>转换为py文件。
pyuic4 -x ui_MainWindow.ui -o ui_MainWindow.py

这个文件应该看起来像……(您不需要编辑此内容)。
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_())

创建一个 'program.py' 文件。 这是您要运行的文件...
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 ()

现在,当您子类化主窗口时,好东西就发生了。将此文件命名为“mainWindow.py”。注意大写字母。
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

这里有一篇很好的教程(链接),我用它来创建了一个替代的“mainWindow.py”,使用定时器来增加进度条。它不会通过使用sleep或执行CPU密集型循环来阻塞代码。我还没有理解多线程、多处理器选项,因此无法对其进行评论。

#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

1
你需要使用信号和槽,以及多进程或多线程。这里有一个很好的例子,专门介绍了进度条:ZetCode进度条。此外,这里之前也有人回答过相关问题:SO进度条

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接