我怎样才能让我的 PyQt5 应用成为一个实例?

How can I make my PyQt5 app oney one instance?

我想达到的效果:

我试过的:

我面临的问题:

有人可以帮我解决这个问题吗?

您可以使用 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 名称等于程序名称,则将程序置于最前面并关闭程序。如果没有,则会打开一个新程序。

PyWin32 link

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++ 代码转换而来的。