2012-01-09 29 views
7

Tôi đang bắt đầu giao diện người dùng từ bên trong Maya. Nếu giao diện người dùng không bị đóng, việc chạy lại giao diện người dùng sẽ đóng băng hoàn toàn Maya (với lỗi "Vòng lặp sự kiện đã chạy")PyQt - cách phát hiện và đóng giao diện người dùng nếu nó đang chạy?

Đóng thủ công giao diện người dùng trước khi chạy lại tập lệnh sẽ ngăn không cho đóng băng. Nhưng tôi đoán điều đó không thực sự thực tế.

Có cách nào để phát hiện xem UI tôi đang cố gắng chạy có tồn tại không? Và lực lượng có thể đóng nó?

+0

có thể là bản sao của http://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection –

Trả lời

15

Có một vài giải pháp C++ khá đơn giản được đưa ra here.

Tôi đã chuyển một trong số chúng vào PyQt và đã cung cấp tập lệnh mẫu bên dưới. Giải pháp C++ gốc đã được chia thành hai lớp, vì cơ sở nhắn tin có thể không cần thiết.

CẬP NHẬT:

Cải thiện kịch bản để nó sử dụng tín hiệu kiểu mới và làm việc với cả hai python2 và python3.

# 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

Nếu tôi chạy ứng dụng có tính năng nhắn tin, tôi luôn nhận được lỗi này : 'QLocalSocket :: connectToServer: Kết nối từ chối' bất kỳ ý tưởng làm thế nào để sửa chữa nó? – Jeena

+0

@Jeena. Vẫn đang làm việc cho tôi trên Linux với PyQt-4.10. – ekhumoro

+0

Oh sau đó nó chỉ là một số kỳ lạ ngẫu nhiên, sau khi khởi động lại máy tính của tôi tối nay nó có vẻ hoạt động tốt ngay bây giờ, cảm ơn bạn đã trở lại mặc dù! – Jeena

8

Trong trường hợp nếu ai đó muốn chạy @ekhumoro giải pháp với python3 có của cần phải thực hiện vài điều chỉnh để hoạt động chuỗi, tôi sẽ chia sẻ bản sao của tôi nơi nó được làm việc python 3.

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_()) 

Ví dụ cli cuộc gọi, giả định rằng tên kịch bản của bạn là "SingleInstanceApp.py":

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

(và đây là cuộc gọi wihout tham số đầu tiên, vì vậy thông điệp đơn giản là sẽ không được gửi)

python SingleInstanceApp.py

Hy vọng rằng nó sẽ giúp ai đó.

Các vấn đề liên quan