从另一个 Python 进程更新 Python GUI

Posted

技术标签:

【中文标题】从另一个 Python 进程更新 Python GUI【英文标题】:Update Python GUI from another Python process 【发布时间】:2015-07-29 07:19:45 【问题描述】:

我已经在谷歌上搜索了将近两天,以找到有关我在 Python 中遇到的问题的答案。而且我完全迷茫和困惑我应该如何解决我的问题。

这就是我想要做的。我有一个 Python 文件名 mymain.py(GUI) 并且它正在运行并处于活动状态,我想通过在终端中运行此命令来更改和更新我的 GUI 中的 Qlabel 文本

sudo python myarg.py -i [任意数字]

其中 [number] 是用户定义的。例如我在终端运行这段代码

sudo python myarg.py -i 5

GUI 中的 Qlabel 文本应更改为 5。

这是我的代码:

mymain.py

from PyQt4 import QtCore, QtGui
import PyQt4
import sys
import os
from time import sleep

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

class Ui_MainWindow(QtGui.QMainWindow):
    updatenumber = QtCore.pyqtSignal(int)
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.setupUi(self)
        self.num = 0 
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(536, 537)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget)
        self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
        self.gridLayout = QtGui.QGridLayout()
        self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
        self.lblNumber = QtGui.QLabel(self.centralwidget)
        font = QtGui.QFont()
        font.setFamily(_fromUtf8("DS-Digital"))
        font.setPointSize(300)
        self.lblNumber.setFont(font)
        self.lblNumber.setObjectName(_fromUtf8("lblNumber"))
        self.lblNumber.setAlignment(QtCore.Qt.AlignCenter)
        self.gridLayout.addWidget(self.lblNumber)
        self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
        MainWindow.setCentralWidget(self.centralwidget)

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

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
        self.lblNumber.setText(QtGui.QApplication.translate("MainWindow", "0", None, QtGui.QApplication.UnicodeUTF8))
        self.thread =  Thread()
        self.thread.update.connect(self.lblNumber.text)

class Thread(QtCore.QThread):
    update = QtCore.pyqtSignal(str)
    def init(self, parent=app):
        QtCore.QThread.init(self,parent)
        self.num = ''
    def run(self):
        self.update.emit(self.num)

if __name__=='__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Ui_MainWindow()
    ex.show()
    sys.exit(app.exec_())

myarg.py

from mymain import Thread
import sys, getopt
from PyQt4 import QtCore, QtGui
import PyQt4

def main(argv):
   ctr = ''
   try:
      opts, args = getopt.getopt(argv,"hi:",["ifile="])
   except getopt.GetoptError:
      print 'sigarg.py -i <ctr>'
      sys.exit(1)
   for opt, arg in opts:
      if opt == '-h':
         print 'sigarg.py -i <ctr>'
         sys.exit()
      elif opt in ("-i", "--ifile"):
         ctr = arg
   m = Thread()
   m.num = ctr
   m.start()

if __name__ == "__main__":
   main(sys.argv[1:])

我使用的 Python 版本是 2.7,我的机器是 Raspberry Pi。

【问题讨论】:

为什么要这样做?你所问的并不完全是微不足道的。您需要设置某种进程间通信(您正在启动一个单独的进程来更新非常不寻常的 GUI) @three_pineapples。这实际上很常见 - 例如,在同一窗口中打开所有文档的选项卡式编辑器/浏览器。 【参考方案1】:

您的用例与单实例应用程序非常相似。在第一次调用命令时,会显示主窗口;然后所有后续调用只是将它们的参数发送到正在运行的应用程序。

他们有很多方法可以做到这一点,但最简单的方法之一是使用本地套接字。为了让您了解它是如何工作的,这里有一个基于我曾经写过的 osd 音量控制的演示:

import sys, getopt
from PyQt4 import QtCore, QtGui, QtNetwork

QtGui.QApplication.setApplicationName('foobar')
QtGui.QApplication.setApplicationVersion('0.1')

class Window(QtGui.QLabel):
    def __init__(self, name):
        super(Window, self).__init__()
        self.server = QtNetwork.QLocalServer(self)
        self.server.newConnection.connect(self.handleMessage)
        if not self.server.listen(name):
            raise RuntimeError(self.server.errorString())

    def closeEvent(self, event):
        self.server.close()
        self.server.removeServer(self.server.fullServerName())

    def handleMessage(self, message=None):
        socket = self.server.nextPendingConnection()
        if socket is not None:
            if socket.waitForReadyRead(2000):
                message = socket.readAll().data().decode('utf-8')
                socket.disconnectFromServer()
            socket.deleteLater()
        if message == 'stop':
            self.close()
        else:
            self.setText(message)

def usage():
    print("""
usage: %s [opts] [message]

options:
 -h  display this help and exit
 -V  display version information
 -s  stop the server
""" % QtGui.QApplication.applicationName())

def main():
    keys = 'hVs'
    try:
        options, args = getopt.getopt(sys.argv[1:], keys)
    except getopt.GetoptError as exception:
        print('ERROR: %s' % exception)
        usage()
        return 2
    else:
        options = dict(options)
        if '-h' in options:
            usage()
        elif '-V' in options:
            print('%s-%s' % (
                QtGui.QApplication.applicationName(),
                QtGui.QApplication.applicationVersion(),
                ))
        else:
            if '-s' in options:
                message = 'stop'
            else:
                message = args[0] if args else None
            name = '%s_server' % QtGui.QApplication.applicationName()
            socket = QtNetwork.QLocalSocket()
            socket.connectToServer(name, QtCore.QIODevice.WriteOnly)
            if socket.waitForConnected(500):
                socket.write(message.encode('utf-8'))
                if not socket.waitForBytesWritten(2000):
                    print('ERROR: could not write to socket: %s' %
                          socket.errorString())
                socket.disconnectFromServer()
            elif socket.error() != QtNetwork.QAbstractSocket.HostNotFoundError:
                print('ERROR: could not connect to server: %s' %
                      socket.errorString())
            elif message is not None:
                print('ERROR: server is not running')
            else:
                app = QtGui.QApplication(sys.argv)
                window = Window(name)
                window.setGeometry(50, 50, 200, 30)
                window.show()
                return app.exec_()
    return 0

if __name__ == '__main__':

    sys.exit(main())

【讨论】:

谢谢楼主的例子,我回家分析一下。 :D 还有一个问题先生,我应该如何向正在运行的应用程序发送命令?通过终端?命令是什么?再次感谢。 @PolanSantiago。使用python demo.py 在控制台中启动脚本。然后在另一个控制台中,运行python demo.py "hello world",这将在标签中显示消息。

以上是关于从另一个 Python 进程更新 Python GUI的主要内容,如果未能解决你的问题,请参考以下文章

python下多进程时全局变量在子进程怎么能更新?遇到从子进程更

如何检查 Python 包中的任何模块是不是从另一个包导入?

从另一个字典更改子字典的键值 - Python

Python中的命名事件

如何从另一个进程/程序将对象添加到 DBus 服务

如何使用子进程模块杀死(或避免)僵尸进程