0

我写了一个GUI程序,它在后面做了很多计算,同时显示一个进度条。完成后,一个新的屏幕将显示结果。

然后我想在计算之前再做一个界面让用户选择是否要使用最后的计算结果,从而跳过计算。

我制作了一个带有连接到计算的按钮的屏幕,以及一个用于选择最后一个计算结果文件的组合框。

但是,当我单击按钮时,它什么也没做。大约 10 秒后(计算的持续时间),结果屏幕弹出。因此,它跳过了进度条屏幕。为什么?

这是原始程序的一部分:

import sys
import configparser
import getpass
import telnetlib
import time
import subprocess
from datetime import *

from log_tracker import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtCore
from PyQt4 import QtGui

class Task_Checker(QMainWindow):

    def __init__(self):
        super(Task_Checker, self).__init__()

        config = configparser.RawConfigParser()
        config.read('profile.cfg')
        self.log_path = config.get('Config', 'log_path')
        self.log_prefix = config.get('Config', 'log_prefix')
        self.log_suffix = config.get('Config', 'log_suffix')

        self.initUI()

    def check_production(self):
        self.log_tracker = Log_Tracker(self)
        self.log_tracker.tick.connect(self.pbar.setValue)
        self.log_tracker.parseConfig()
        self.log_tracker.connectDb()
        self.log_tracker.trackLog()



    def initUI(self):
        self.resize(1400, 768)
        self.center()

        self.statusBar().showMessage('Checking Production Programs')

        self.wait_message = QLabel('Checking Production Programs')
        self.wait_message.setAlignment(Qt.Alignment(Qt.AlignHCenter))
        self.pbar = QProgressBar(self)
        self.pbar.setMinimum(0)
        self.pbar.setMaximum(100)

        vbox = QVBoxLayout()
        vbox.addWidget(self.wait_message)
        vbox.addWidget(self.pbar)
        tmpWidget2 = QWidget()
        tmpWidget2.setLayout(vbox)
        self.setCentralWidget(tmpWidget2)
        self.show()

        self.check_production()

        self.pbar.hide()
        self.statusBar().showMessage('Processing Information')

        self.tabs = QTabWidget()        
        mua_table = self.processInfo('MUA')
        bps_table = self.processInfo('BPS')
        obdua_table = self.processInfo('OBDUA')
        sua_table = self.processInfo('SUA')
        ngr_ftp_table = self.processInfo('NGR_FTP')
        bpspdfbill_table = self.processInfo('BpsPdfBill')
        disk_space_table = self.processInfo('Disk_Space')        
        self.tabs.addTab(mua_table, 'MUA')
        self.tabs.addTab(bps_table, 'BPS')
        self.tabs.addTab(obdua_table, 'ODBUA')
        self.tabs.addTab(sua_table, 'SUA')
        self.tabs.addTab(ngr_ftp_table, 'NGR_FTP')
        self.tabs.addTab(bpspdfbill_table, 'BpsPdfBill')
        self.tabs.addTab(disk_space_table, 'Disk_Space')
        self.setCentralWidget(self.tabs)

        self.statusBar().showMessage('Ready')

        self.setWindowTitle('Task Checker')    
        self.show()

    def center(self):

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())



    def processInfo(self, project_name):
        ...the processing...

为了在进度条之前添加一个新屏幕(最初它会立即加载计算),我对 initUI() 进行了一些更改,并将计算部分移动到一个新的子程序 checkProd(),然后用一个按钮连接它:

import sys
import configparser
import getpass
import telnetlib
import time
import subprocess
from datetime import *

from log_tracker import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtCore
from PyQt4 import QtGui

class Task_Checker(QMainWindow):

    def __init__(self):
        super(Task_Checker, self).__init__()

        config = configparser.RawConfigParser()
        config.read('profile.cfg')
        self.log_path = config.get('Config', 'log_path')
        self.log_prefix = config.get('Config', 'log_prefix')
        self.log_suffix = config.get('Config', 'log_suffix')

        self.initUI()

    def check_production(self):
        self.log_tracker = Log_Tracker(self)
        self.log_tracker.tick.connect(self.pbar.setValue)
        self.log_tracker.parseConfig()
        self.log_tracker.connectDb()
        self.log_tracker.trackLog()



    def initUI(self):
        self.resize(1400, 768)
        self.center()

        btn_check = QPushButton('Check Lastest Status', self)
        btn_check.setToolTip('Click this if you want to check the lastest status in production')

        combo = QComboBox()
        dirlist = os.listdir(self.log_path)
        for f in dirlist:
            combo.addItem(f)

        QtCore.QObject.connect(btn_check, QtCore.SIGNAL('clicked()'), self.checkProd)

        hbox = QHBoxLayout()
        hbox.addWidget(btn_check)
        hbox.addWidget(combo)
        tmpWidget = QWidget()
        tmpWidget.setLayout(hbox)        
        self.setCentralWidget(tmpWidget)
        self.show()

    def checkProd(self):
        self.statusBar().showMessage('Checking Production Programs')

        self.wait_message = QLabel('Checking Production Programs')
        self.wait_message.setAlignment(Qt.Alignment(Qt.AlignHCenter))
        self.pbar = QProgressBar(self)
        self.pbar.setMinimum(0)
        self.pbar.setMaximum(100)

        vbox = QVBoxLayout()
        vbox.addWidget(self.wait_message)
        vbox.addWidget(self.pbar)
        tmpWidget2 = QWidget()
        tmpWidget2.setLayout(vbox)
        self.setCentralWidget(tmpWidget2)
        self.show()


        self.check_production()

        self.pbar.hide()
        self.statusBar().showMessage('Processing Information')

        self.tabs = QTabWidget()        
        mua_table = self.processInfo('MUA')
        bps_table = self.processInfo('BPS')
        obdua_table = self.processInfo('OBDUA')
        sua_table = self.processInfo('SUA')
        ngr_ftp_table = self.processInfo('NGR_FTP')
        bpspdfbill_table = self.processInfo('BpsPdfBill')
        disk_space_table = self.processInfo('Disk_Space')        
        self.tabs.addTab(mua_table, 'MUA')
        self.tabs.addTab(bps_table, 'BPS')
        self.tabs.addTab(obdua_table, 'ODBUA')
        self.tabs.addTab(sua_table, 'SUA')
        self.tabs.addTab(ngr_ftp_table, 'NGR_FTP')
        self.tabs.addTab(bpspdfbill_table, 'BpsPdfBill')
        self.tabs.addTab(disk_space_table, 'Disk_Space')

        self.setCentralWidget(self.tabs)

        self.statusBar().showMessage('Ready')

        self.setWindowTitle('Task Checker')    
        self.show()


    def center(self):

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())



    def processInfo(self, project_name):
        ...the processing...
4

1 回答 1

0

这是很多不必要的代码,但我设法从中解析出来的是,您正在主线程中进行大量计算,同时期望主线程中的另一个小部件也能保持响应能力。

这是使用 PyQt4(可能还有大多数使用主线程事件循环的 GUI 框架)时的常见缺陷。问题在于,当您启动应用程序时,主事件循环会不断轮询要从您的 GUI 处理的新事件。它期望每个操作都应该花费很短的时间来完成,或者定期将控制权交还给事件循环。现在,您的计算占用了主线程的所有可用性,而您的进度窗口试图做的任何事情都只是备份到队列中,等待事件循环获取它的机会。

对此的简单回答是:在单独的QThread中进行任何繁重的计算,并通过信号与主线程通信。这将需要您进行一些改造。您不应该在任何类的 init 中添加任何繁重的东西。但是您已在第二个示例中通过将计算附加到按钮来解决此问题。好的开始。该按钮实际上应该在另一个线程中启动计算,因此不会阻塞主线程。

Qt4.7 线程基础

GUI 线程和工作线程
如前所述,每个程序在启动时都有一个线程。该线程称为“主线程”(在 Qt 应用程序中也称为“GUI 线程”)。Qt GUI 必须在这个线程中运行。所有小部件和几个相关的类,例如 QPixmap,都不能在辅助线程中工作。辅助线程通常被称为“工作线程”,因为它用于从主线程卸载处理工作。
...
使用线程 线程
基本上有两种用例:
1. 通过使用多核处理器来加快处理速度。
2. 通过卸载持久处理或阻塞对其他线程的调用来保持 GUI 线程或其他时间关键线程的响应。

如果您只想查看一些结果,作为快速解决方法,您可以定期QtGui.QApplication.processEvents()从您的计算方法中调用。这将经常允许事件循环清除挂起的操作。这样做会让你的进度小部件之类的东西真正发挥作用。本质上,您正在做的是手动“泵送”事件循环。虽然这不是最好的方法。通常它是为重量较轻的一次性东西保留的。如果您想要最佳性能,请将其移至线程。

于 2012-07-07T05:30:56.960 回答