我从Maya内部启动UI。如果UI尚未关闭,再次运行UI将完全冻结Maya(错误“事件循环已在运行”)
在重新运行脚本之前手动关闭UI将阻止它冻结。但我猜这不太实际。
有没有办法检测我正在尝试运行的用户界面是否已经存在?可能的力量关闭它?
答案 0 :(得分:16)
here给出了几个相当简单的C ++解决方案。
我已将其中一个移植到PyQt,并在下面提供了一个示例脚本。最初的C ++解决方案已分为两类,因为可能不需要消息传递工具。
<强>更新强>:
改进了脚本,以便它使用新式信号并兼用python2和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_())
答案 1 :(得分:9)
如果有人想使用python3运行 @ekhumoro 解决方案,则需要对字符串操作进行一些调整,我将分享我的副本工作 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_())
示例cli调用,假设您的脚本名称为“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"
(这里是第一个参数调用,所以不会发送消息)
python SingleInstanceApp.py
希望它能帮助别人。
答案 2 :(得分:0)
我的解决方法是:
import sys
from PyQt5.QtCore import QLockFile
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMessageBox
from window import MainWindow
if __name__ == "__main__":
try:
app_object = QApplication(sys.argv)
lock_file = QLockFile("app.lock")
if lock_file.tryLock():
window = MainWindow()
window.show()
app_object.exec()
else:
error_message = QMessageBox()
error_message.setIcon(QMessageBox.Warning)
error_message.setWindowTitle("Error")
error_message.setText("The application is already running!")
error_message.setStandardButtons(QMessageBox.Ok)
error_message.exec()
finally:
lock_file.unlock()