Search code examples
pythonpyqt5taskbarpsutil

How to maximize or active a opened application window in TaskBar When the user tries to run it again?


How to view or active a application window exists in task-bar When the user tries to run it again.

For Example: I have already opened MyApp application and that is already existed on task-bar and want to maximize the MyApp ,If I try to open it again via the application icon on the desktop or from the start menu.

I have this script yet:

def process():
    import psutil
    PROCNAME = 'MyApp.exe'
    for proc in psutil.process_iter():
        try:
            if proc.name().lower() == PROCNAME.lower():
                
                return
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
            pass
    MainThred = QApplication([])
    MainGUI = MainWindow()
    MainGUI.show()
    sysExit(MainThred.exec_())
if __name__ == "__main__":
    process()

Solution

  • You describe common pattern known as single instance of application. Your second instance should be aware of first instance and send a signal to first instance to show window and then exit immediately. So you need some form of interprocess communication (IPC). It can be achieved using tcp socket or file handle or shared memory.

    SingleInstance implementation using shared memory:

    from PyQt5.QtCore import QSharedMemory, QTimer, QObject, pyqtSignal
    from PyQt5.QtWidgets import QMessageBox, QWidget, QApplication
    
    class SingleInstanceException(Exception):
        pass
    
    class SharedMemoryReader(QObject):
    
        received = pyqtSignal(bytes)
    
        def __init__(self, key, parent = None):
            super().__init__(parent)
    
            memory = QSharedMemory(key)
            if not memory.create(1, QSharedMemory.ReadWrite):
                raise SingleInstanceException()
            
            self._memory = memory
            memory.lock()
            self.clearMemory()
            memory.unlock()
    
            # timer to poll shared memory for changes
            timer = QTimer()
            timer.timeout.connect(self.onTimeOut)
            timer.start(500)
            self._timer = timer
    
        def clearMemory(self):
            self._memory.data()[0] = b'0'
            
        def onTimeOut(self):
            memory = self._memory
            memory.lock()
            data = memory.data()[0]
            if data != b'0':
                self.received.emit(data)
                self.clearMemory()
            memory.unlock()
    
    class SharedMemoryWriter(QObject):
    
        def __init__(self, key, parent = None):
            super().__init__(parent)
            memory = QSharedMemory(key)
            self._memory = memory
            
        def write(self, message):
            memory = self._memory
            if not memory.isAttached():
                memory.attach()
            memory.lock()
            memory.data()[0] = message
            memory.unlock()
    
    if __name__ == "__main__":
        app = QApplication([])
    
        # guid to identify your application (some unique string)
        guid = "5c197822-e86a-4547-a4f1-dbb5087b962d"
    
        widget = QWidget()
    
        try:
            # First instance creates shared memory. 
            # If memory exists exception raised and it means that it's not first instance.
            reader = SharedMemoryReader(guid)
            reader.received.connect(lambda: QMessageBox.information(widget,"","Signal from another instance received"))
        except SingleInstanceException:
            # Second instance writes to memory (sends signal to first instance) and exits
            writer = SharedMemoryWriter(guid)
            writer.write(b'1')
            exit(0)
        
        # No exception raised - that means its first instance of application
        # Continue normally
        widget.show()
    
        app.exec_()