我怎样才能让我的 PyQt5 应用成为一个实例?
How can I make my PyQt5 app oney one instance?
我想达到的效果:
- 当我从开始菜单 运行 应用程序时,应用程序启动(如果应用程序未 运行ning)。
- 如果一个应用程序已经 运行ning,则不要创建另一个实例,只显示之前的 运行ning 应用程序 window。
我试过的:
- 在目录中创建了一个
.txt file
,在打开和退出 window 时将“running
”和“not running
”写入文件。并在一开始就检查文件内容。例如:
启动应用程序时:1.) 检查文件内容,2.) 如果文件内容是'running
',显示警告并退出应用程序 3.) 如果文件内容是'not running
',写' running
' 进入文件并启动应用程序 4.) 在退出时将 'not running
' 写入文件。
我面临的问题:
感觉这种方法不是实现此目的的正确方法。
如果文件项显示“not running
”,应用会显示警告并退出。虽然我希望它显示 运行ning 个实例。
由于代码中的某些错误,当应用程序退出时,文件项未更新为“not running
”(因为该部分因错误而永远无法到达)
有人可以帮我解决这个问题吗?
您可以使用 win32gui 模块实现类似的功能。要安装它,请输入 CMD pip install pywin32
。现在这是代码:
from win32 import win32gui
import sys
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
top_windows = []
win32gui.EnumWindows(windowEnumerationHandler, top_windows)
for i in top_windows:
if "Program" in i[1]: #CHANGE PROGRAM TO THE NAME OF YOUR WINDOW
win32gui.ShowWindow(i[0],5)
win32gui.SetForegroundWindow(i[0])
sys.exit()
from PyQt5.QtWidgets import QApplication, QWidget
def main():
#YOUR PROGRAM GOES HERE
app = QApplication(sys.argv)
w = QWidget()
w.setGeometry(500, 500, 500, 500)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
基本上,一开始,程序会获取每个打开的名称window。如果 window 名称等于程序名称,则将程序置于最前面并关闭程序。如果没有,则会打开一个新程序。
Stack Overflow get a list of every open window
此解决方案不需要您安装 win32 或任何其他模块,适用于 PyQt5 包本身。
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QSystemSemaphore, QSharedMemory
from ui import window_ui # .py file compiled from .ui file
class LoginWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.ui = window_ui.Ui_MainWindow() # call to init ui
self.ui.setupUi(self)
def launch():
app = QtWidgets.QApplication(sys.argv) # create app instance at top, to able to show QMessageBox is required
window_id = 'pingidapplication'
shared_mem_id = 'pingidsharedmem'
semaphore = QSystemSemaphore(window_id, 1)
semaphore.acquire() # Raise the semaphore, barring other instances to work with shared memory
if sys.platform != 'win32':
# in linux / unix shared memory is not freed when the application terminates abnormally,
# so you need to get rid of the garbage
nix_fix_shared_mem = QSharedMemory(shared_mem_id)
if nix_fix_shared_mem.attach():
nix_fix_shared_mem.detach()
shared_memory = QSharedMemory(shared_mem_id)
if shared_memory.attach(): # attach a copy of the shared memory, if successful, the application is already running
is_running = True
else:
shared_memory.create(1) # allocate a shared memory block of 1 byte
is_running = False
semaphore.release()
if is_running: # if the application is already running, show the warning message
QtWidgets.QMessageBox.warning(None, 'Application already running',
'One instance of the application is already running.')
return
# normal process of creating & launching MainWindow
window = LoginWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
launch()
这个解决方案是我最初从 this website 上发布的 C++ 代码转换而来的。
我想达到的效果:
- 当我从开始菜单 运行 应用程序时,应用程序启动(如果应用程序未 运行ning)。
- 如果一个应用程序已经 运行ning,则不要创建另一个实例,只显示之前的 运行ning 应用程序 window。
我试过的:
- 在目录中创建了一个
.txt file
,在打开和退出 window 时将“running
”和“not running
”写入文件。并在一开始就检查文件内容。例如: 启动应用程序时:1.) 检查文件内容,2.) 如果文件内容是'running
',显示警告并退出应用程序 3.) 如果文件内容是'not running
',写'running
' 进入文件并启动应用程序 4.) 在退出时将 'not running
' 写入文件。
我面临的问题:
感觉这种方法不是实现此目的的正确方法。
如果文件项显示“
not running
”,应用会显示警告并退出。虽然我希望它显示 运行ning 个实例。由于代码中的某些错误,当应用程序退出时,文件项未更新为“
not running
”(因为该部分因错误而永远无法到达)
有人可以帮我解决这个问题吗?
您可以使用 win32gui 模块实现类似的功能。要安装它,请输入 CMD pip install pywin32
。现在这是代码:
from win32 import win32gui
import sys
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
top_windows = []
win32gui.EnumWindows(windowEnumerationHandler, top_windows)
for i in top_windows:
if "Program" in i[1]: #CHANGE PROGRAM TO THE NAME OF YOUR WINDOW
win32gui.ShowWindow(i[0],5)
win32gui.SetForegroundWindow(i[0])
sys.exit()
from PyQt5.QtWidgets import QApplication, QWidget
def main():
#YOUR PROGRAM GOES HERE
app = QApplication(sys.argv)
w = QWidget()
w.setGeometry(500, 500, 500, 500)
w.setWindowTitle('Simple')
w.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
基本上,一开始,程序会获取每个打开的名称window。如果 window 名称等于程序名称,则将程序置于最前面并关闭程序。如果没有,则会打开一个新程序。
Stack Overflow get a list of every open window
此解决方案不需要您安装 win32 或任何其他模块,适用于 PyQt5 包本身。
import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QSystemSemaphore, QSharedMemory
from ui import window_ui # .py file compiled from .ui file
class LoginWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.ui = window_ui.Ui_MainWindow() # call to init ui
self.ui.setupUi(self)
def launch():
app = QtWidgets.QApplication(sys.argv) # create app instance at top, to able to show QMessageBox is required
window_id = 'pingidapplication'
shared_mem_id = 'pingidsharedmem'
semaphore = QSystemSemaphore(window_id, 1)
semaphore.acquire() # Raise the semaphore, barring other instances to work with shared memory
if sys.platform != 'win32':
# in linux / unix shared memory is not freed when the application terminates abnormally,
# so you need to get rid of the garbage
nix_fix_shared_mem = QSharedMemory(shared_mem_id)
if nix_fix_shared_mem.attach():
nix_fix_shared_mem.detach()
shared_memory = QSharedMemory(shared_mem_id)
if shared_memory.attach(): # attach a copy of the shared memory, if successful, the application is already running
is_running = True
else:
shared_memory.create(1) # allocate a shared memory block of 1 byte
is_running = False
semaphore.release()
if is_running: # if the application is already running, show the warning message
QtWidgets.QMessageBox.warning(None, 'Application already running',
'One instance of the application is already running.')
return
# normal process of creating & launching MainWindow
window = LoginWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
launch()
这个解决方案是我最初从 this website 上发布的 C++ 代码转换而来的。