Kiarash
Kiarash

Reputation: 8028

pyqt4 - singleapplication - bring up the original window in an attempt to open the app for the second time

I want only one instance of my app to be running at each time. but when the user attempts to open it the second time, I want the first window to be brought to the front (it could be just minimized or minimized to the corner of the taskbar and the user doesn't know how to open it)

I have this code that does the detection job and it doesn't allow the second instance. I have trouble with the part that it has to open the original window. I have commented out some of my attempt.

import sys
from PyQt4 import QtGui, QtCore 
import sys

class SingleApplication(QtGui.QApplication):
    def __init__(self, argv, key):
        QtGui.QApplication.__init__(self, argv)
        self._activationWindow=None
        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().toLocal8Bit().data())
    def isRunning(self):
        return self._running

    def activationWindow(self):
        return self._activationWindow

    def setActivationWindow(self, activationWindow):
        self._activationWindow = activationWindow

    def activateWindow(self):
        if not self._activationWindow:
            return
        self._activationWindow.setWindowState(
            self._activationWindow.windowState() & ~QtCore.Qt.WindowMinimized)
        self._activationWindow.raise_()
        self._activationWindow.activateWindow()

class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.label = QtGui.QLabel(self)
        self.label.setText("Hello")
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(self.label)

if __name__ == '__main__':

    key = 'random _ text'

    app = SingleApplication(sys.argv, key)
    if app.isRunning():
        #app.activateWindow()
        sys.exit(1)

    window = Window()  
    #app.setActivationWindow(window)
    #print app.topLevelWidgets()[0].winId()
    window.show()

    sys.exit(app.exec_())

Upvotes: 3

Views: 860

Answers (2)

Boris Dalstein
Boris Dalstein

Reputation: 7788

You might be interested by the solutions proposed here

For instance, I would try:

app = SingleApplication(sys.argv, key)
if app.isRunning():
    window = app.activationWindow()
    window.showNormal()
    window.raise()
    app.activateWindow()
    sys.exit(1)

window = Window()  
app.setActivationWindow(window)
window.setWindowFlags(Popup)
window.show()

Upvotes: 0

goran
goran

Reputation: 411

I've made this work on Windows using the win32 api (I'm not entirely sure, but there are probably equivalent calls on macos/unix).

Add the following import to your application,

import win32gui

set the window title to a fixed name (instead of doing this, you could store its whndl in the shared memory)

window = Window()  
window.setWindowTitle('Single Application Example')
window.show()

and then change your activateWindow method to something like the following:

def activateWindow(self):
    # needs to look for a named window ...
    whndl = win32gui.FindWindowEx(0, 0, None, "Single Application Example")

    if whndl is 0:
        return #couldn't find the name window ...

    #this requests the window to come to the foreground 
    win32gui.SetForegroundWindow(whndl) 

Upvotes: 1

Related Questions