【问题标题】:pyqt: How to dynamically update widget property on outer variable value change?pyqt:如何在外部变量值更改时动态更新小部件属性?
【发布时间】:2014-01-19 07:53:49
【问题描述】:

我有 class Ui_MainWindow(object) 创建一个带有进度条的窗口和 class OtherClass(object) 包含局部 int 变量循环递增的方法。

如何将局部变量值变化与进度条值变化联系起来?

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

【问题讨论】:

  • 请出示您目前拥有的代码。

标签: python pyqt signals-slots


【解决方案1】:

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

首先,您应该切勿编辑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()

【讨论】:

    【解决方案2】:

    以下帖子有一个版本,每次按下按钮时,进度条都会增加 10%。还有一个使用计时器来增加进度条的版本。 (我自己也在学习这个)

    在 Qt Designer 中,添加一个进度条和一个按钮。单击“编辑信号/插槽”,将一条线从按钮拖到窗口中的某处,当按钮被“按下()”时,添加一个名为“button_pressed()”的插槽(或信号??)(使用+按钮做这个)。完成此操作后,“确定”按钮显示为灰色 - 选择您创建的插槽,然后按“确定”。

    将文件另存为 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
    

    有一个很好的教程here,我用它来创建一个备用的“mainWindow.py”,它使用一个计时器来增加进度条。它不会通过使用睡眠的循环或执行 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
    

    【讨论】:

      【解决方案3】:

      您必须使用信号和槽...以及多处理或多线程。

      这里有一个很好的示例,专门带您浏览进度条: ZetCode Progress Bar

      另外,问题已经在这里回答过: SO Progress Bar

      【讨论】:

        猜你喜欢
        • 2020-01-19
        • 1970-01-01
        • 2017-04-21
        • 1970-01-01
        • 2012-07-25
        • 2023-01-13
        • 2016-10-04
        • 1970-01-01
        • 2019-01-21
        相关资源
        最近更新 更多