【问题标题】:QtSingleApplication for PySide or PyQtPySide 或 PyQt 的 QtSingleApplication
【发布时间】:2012-09-24 14:37:24
【问题描述】:

是否有来自 Qt Solutions 的 C++ 类 QtSingleApplication 的 Python 版本?

QtSingleApplication 用于确保永远不会有多个应用程序实例同时运行。

【问题讨论】:

    标签: python qt pyqt pyside


    【解决方案1】:

    这是我自己的实现。 它已经过 Python 2.7 和 PySide 1.1 的测试。

    它具有与C++ version of QtSingleApplication 基本相同的界面。主要区别在于您必须向构造函数提供应用程序唯一 ID。 (默认情况下,C++ 版本使用可执行文件的路径作为唯一 ID;这在此处不起作用,因为可执行文件很可能是 python.exe。)

    from PySide.QtCore import *
    from PySide.QtGui import *
    from PySide.QtNetwork import *
    
    class QtSingleApplication(QApplication):
    
        messageReceived = Signal(unicode)
    
        def __init__(self, id, *argv):
    
            super(QtSingleApplication, self).__init__(*argv)
            self._id = id
            self._activationWindow = None
            self._activateOnMessage = False
    
            # Is there another instance running?
            self._outSocket = QLocalSocket()
            self._outSocket.connectToServer(self._id)
            self._isRunning = self._outSocket.waitForConnected()
    
            if self._isRunning:
                # Yes, there is.
                self._outStream = QTextStream(self._outSocket)
                self._outStream.setCodec('UTF-8')
            else:
                # No, there isn't.
                self._outSocket = None
                self._outStream = None
                self._inSocket = None
                self._inStream = None
                self._server = QLocalServer()
                self._server.listen(self._id)
                self._server.newConnection.connect(self._onNewConnection)
    
        def isRunning(self):
            return self._isRunning
    
        def id(self):
            return self._id
    
        def activationWindow(self):
            return self._activationWindow
    
        def setActivationWindow(self, activationWindow, activateOnMessage = True):
            self._activationWindow = activationWindow
            self._activateOnMessage = activateOnMessage
    
        def activateWindow(self):
            if not self._activationWindow:
                return
            self._activationWindow.setWindowState(
                self._activationWindow.windowState() & ~Qt.WindowMinimized)
            self._activationWindow.raise_()
            self._activationWindow.activateWindow()
    
        def sendMessage(self, msg):
            if not self._outStream:
                return False
            self._outStream << msg << '\n'
            self._outStream.flush()
            return self._outSocket.waitForBytesWritten()
    
        def _onNewConnection(self):
            if self._inSocket:
                self._inSocket.readyRead.disconnect(self._onReadyRead)
            self._inSocket = self._server.nextPendingConnection()
            if not self._inSocket:
                return
            self._inStream = QTextStream(self._inSocket)
            self._inStream.setCodec('UTF-8')
            self._inSocket.readyRead.connect(self._onReadyRead)
            if self._activateOnMessage:
                self.activateWindow()
    
        def _onReadyRead(self):
            while True:
                msg = self._inStream.readLine()
                if not msg: break
                self.messageReceived.emit(msg)
    

    这是一个简单的测试程序:

    import sys
    from PySide.QtGui import *
    from QtSingleApplication import QtSingleApplication
    
    appGuid = 'F3FF80BA-BA05-4277-8063-82A6DB9245A2'
    app = QtSingleApplication(appGuid, sys.argv)
    if app.isRunning(): sys.exit(0)
    
    w = QWidget()
    w.show()
    app.setActivationWindow(w)
    sys.exit(app.exec_())
    

    【讨论】:

    • 为什么不使用脚本文件名/path/to/script.py 而不是UUID?
    • @Hugo:如果您正在运行冷冻鸡蛋或 py2exe 或 PyInstaller 可执行文件,这是否有效?
    • 嗨@user763305,可以在BSD许可或类似许可下使用它吗?
    • @Thomas K:随意使用 2-clause BSD 许可下的代码,opensource.org/licenses/BSD-2-Clause
    • @DoTheEvo 看看QtSingleApplication docs,尤其是sendMessage 插槽和messageReceived 信号。
    【解决方案2】:

    你可以看看这个blog entry。它适用于 Pyside,但我想它也适用于 PyQt4。

    【讨论】:

    • 那个 Python 类的接口与 C++ 类的接口完全不同。特别是,你必须给构造函数一个对主窗口的引用,然后构造函数将在主窗口上异步调用 show()。
    • 好吧,我并不是说这是完美的、确定的解决方案。这是一个用户实现的解决方案,我想保留 C++ 接口不是作者的优先事项。相反,他似乎更喜欢添加一些功能,以便参数可以从以后的调用传递到第一个调用。
    • 使用原始 C++ 接口通过 sendMessage 方法和 messageReceived 信号将参数从后面的调用传递给第一个调用是可能的。
    • 那么我想我会使用您的实现,因为它似乎设计得更好。正如我所说,我猜作者有他自己的优先事项,显然他们和你的不一样:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    相关资源
    最近更新 更多