2012-01-09 25 views
7

私はMayaからUIを開始しています。 UIが閉じられていない場合、UIを再実行すると、Mayaが完全にフリーズされます(エラー "イベントループはすでに実行中です")。PyQt - 既に実行中の場合、UIを検出して閉じる方法は?

スクリプトを再実行する前にUIを手動で閉じると、フリーズしません。しかし、それは本当に実用的ではないと思います。

実行しようとしているUIが既に存在するかどうかを検出する方法はありますか?そして可能な力はそれを閉じますか?

+0

おそらく、http://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection –

答えて

15

hereには、かなり単純なC++ソリューションがいくつかあります。

私はPyQtにそのうちの1つを移植し、以下のサンプルスクリプトを提供しました。メッセージング機能が不要なため、元のC++ソリューションは2つのクラスに分割されています。

UPDATE

それは新しいスタイルの信号を使用し、python2とのpython3の両方で動作するようにスクリプトを改善しました。それはのpython 3を働いていたところ

# only needed for python2 
import sip 
sip.setapi('QString', 2) 

from PyQt4 import QtGui, QtCore, QtNetwork 

class SingleApplication(QtGui.QApplication): 
    messageAvailable = QtCore.pyqtSignal(object) 

    def __init__(self, argv, key): 
     QtGui.QApplication.__init__(self, argv) 
     self._memory = QtCore.QSharedMemory(self) 
     self._memory.setKey(key) 
     if self._memory.attach(): 
      self._running = True 
     else: 
      self._running = False 
      if not self._memory.create(1): 
       raise RuntimeError(self._memory.errorString()) 

    def isRunning(self): 
     return self._running 

class SingleApplicationWithMessaging(SingleApplication): 
    def __init__(self, argv, key): 
     SingleApplication.__init__(self, argv, key) 
     self._key = key 
     self._timeout = 1000 
     self._server = QtNetwork.QLocalServer(self) 
     if not self.isRunning(): 
      self._server.newConnection.connect(self.handleMessage) 
      self._server.listen(self._key) 

    def handleMessage(self): 
     socket = self._server.nextPendingConnection() 
     if socket.waitForReadyRead(self._timeout): 
      self.messageAvailable.emit(
       socket.readAll().data().decode('utf-8')) 
      socket.disconnectFromServer() 
     else: 
      QtCore.qDebug(socket.errorString()) 

    def sendMessage(self, message): 
     if self.isRunning(): 
      socket = QtNetwork.QLocalSocket(self) 
      socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly) 
      if not socket.waitForConnected(self._timeout): 
       print(socket.errorString()) 
       return False 
      if not isinstance(message, bytes): 
       message = message.encode('utf-8') 
      socket.write(message) 
      if not socket.waitForBytesWritten(self._timeout): 
       print(socket.errorString()) 
       return False 
      socket.disconnectFromServer() 
      return True 
     return False 

class Window(QtGui.QWidget): 
    def __init__(self): 
     QtGui.QWidget.__init__(self) 
     self.edit = QtGui.QLineEdit(self) 
     self.edit.setMinimumWidth(300) 
     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.edit) 

    def handleMessage(self, message): 
     self.edit.setText(message) 

if __name__ == '__main__': 

    import sys 

    key = 'app-name' 

    # send commandline args as message 
    if len(sys.argv) > 1: 
     app = SingleApplicationWithMessaging(sys.argv, key) 
     if app.isRunning(): 
      print('app is already running') 
      app.sendMessage(' '.join(sys.argv[1:])) 
      sys.exit(1) 
    else: 
     app = SingleApplication(sys.argv, key) 
     if app.isRunning(): 
      print('app is already running') 
      sys.exit(1) 

    window = Window() 
    app.messageAvailable.connect(window.handleMessage) 
    window.show() 

    sys.exit(app.exec_()) 
+0

のメッセージを実行すると、このエラーが発生します: 'QLocalSocket :: connectToServer:接続が拒否されました'任意のアイデアをどのように修正するのですか? – Jeena

+0

@ Jeena。まだPyQt-4.10を使ってLinux上で働いています。 – ekhumoro

+0

ああ、それはちょうどいくつかのランダムな奇妙さだった、今夜私のコンピュータの再起動後、それはちょうど良い今、戻ってくれてありがとう! – Jeena

8

場合、誰かが私は私のコピーを共有しましょう、そこのは、文字列操作にいくつかの調整をする必要があるのpython3と@ekhumoroソリューションを実行したい場合。

python SingleInstanceApp.py 1 
python SingleInstanceApp.py 1 "test" 
python SingleInstanceApp.py 1 "foo bar baz" 
python SingleInstanceApp.py 1 "utf8 test FOO ßÄÖÜ ßäöü łąćźżóń ŁĄĆŹŻÓŃ etc" 

(こことは、最初のパラメータwihout呼び出しなので、メッセージは、単に送信されません):

import sys 

from PyQt4 import QtGui, QtCore, QtNetwork 

class SingleApplication(QtGui.QApplication): 
    def __init__(self, argv, key): 
     QtGui.QApplication.__init__(self, argv) 
     self._memory = QtCore.QSharedMemory(self) 
     self._memory.setKey(key) 
     if self._memory.attach(): 
      self._running = True 
     else: 
      self._running = False 
      if not self._memory.create(1): 
       raise RuntimeError(self._memory.errorString()) 

    def isRunning(self): 
     return self._running 

class SingleApplicationWithMessaging(SingleApplication): 
    def __init__(self, argv, key): 
     SingleApplication.__init__(self, argv, key) 
     self._key = key 
     self._timeout = 1000 
     self._server = QtNetwork.QLocalServer(self) 

     if not self.isRunning(): 
      self._server.newConnection.connect(self.handleMessage) 
      self._server.listen(self._key) 

    def handleMessage(self): 
     socket = self._server.nextPendingConnection() 
     if socket.waitForReadyRead(self._timeout): 
      self.emit(QtCore.SIGNAL('messageAvailable'), bytes(socket.readAll().data()).decode('utf-8')) 
      socket.disconnectFromServer() 
     else: 
      QtCore.qDebug(socket.errorString()) 

    def sendMessage(self, message): 
     if self.isRunning(): 
      socket = QtNetwork.QLocalSocket(self) 
      socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly) 
      if not socket.waitForConnected(self._timeout): 
       print(socket.errorString()) 
       return False 
      socket.write(str(message).encode('utf-8')) 
      if not socket.waitForBytesWritten(self._timeout): 
       print(socket.errorString()) 
       return False 
      socket.disconnectFromServer() 
      return True 
     return False 

class Window(QtGui.QWidget): 
    def __init__(self): 
     QtGui.QWidget.__init__(self) 
     self.edit = QtGui.QLineEdit(self) 
     self.edit.setMinimumWidth(300) 
     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.edit) 

    def handleMessage(self, message): 
     self.edit.setText(message) 

if __name__ == '__main__': 

    key = 'foobar' 

    # if parameter no. 1 was set then we'll use messaging between app instances 
    if len(sys.argv) > 1: 
     app = SingleApplicationWithMessaging(sys.argv, key) 
     if app.isRunning(): 
      msg = '' 
      # checking if custom message was passed as cli argument 
      if len(sys.argv) > 2: 
       msg = sys.argv[2] 
      else: 
       msg = 'APP ALREADY RUNNING' 
      app.sendMessage(msg) 
      print("app is already running, sent following message: \n\"{0}\"".format(msg)) 
      sys.exit(1) 
    else: 
     app = SingleApplication(sys.argv, key) 
     if app.isRunning(): 
      print('app is already running, no message has been sent') 
      sys.exit(1) 

    window = Window() 
    app.connect(app, QtCore.SIGNAL('messageAvailable'), window.handleMessage) 
    window.show() 

    sys.exit(app.exec_()) 

例は、スクリプト名が "SingleInstanceApp.py" であると仮定すると、通話をcliを

python SingleInstanceApp.py

誰かを助けることを望みます。

関連する問題