Saul Han
Saul Han

Reputation: 69

How to tell tkinter application to run only one instance?

I made a Python GUI application using tkinter. The problem I have is that you can run as many instances as you want. But I only want one instance to be running, if the application is already running and I click again EXE or shortcut, instead it should bring existing running application to the focus.

Upvotes: 4

Views: 1377

Answers (4)

JRiggles
JRiggles

Reputation: 6820

Forgive the necromancy. For folks coming from a search engine looking for a way to do this within the StdLib, I have a similar solution to @tgikal that doesn't require win32gui:

from ctypes import WinDLL
import sys


APP_NAME = 'My app name'  # this isn't totally necessary, it's just for readability


def instance_check():
    U32DLL = WinDLL('user32')
    # get the handle of any window matching 'APP_NAME'
    hwnd = U32DLL.FindWindowW(None, APP_NAME)
    if hwnd:  # if a matching window exists...
        # focus the existing window
        U32DLL.ShowWindow(hwnd, 5)
        U32DLL.SetForegroundWindow(hwnd)
        # bail
        sys.exit(0)
    return True


def main():
    if instance_check():  # if no other instance is found...
        root = Root()  # instantiate your tk app
        root.mainloop()  # run as usual
    # etc.

if __name__ == '__main__':
    main()

The idea is that this will check for a running instance of your app by name, focus it if it's found, then exit the current interpreter before the second instance is started.

Oh, and if like me you're curious about that magic number 5 in ShowWindow, see the MDN docs here. The TL;DR is that the number is the nCmdShow argument and 5 means:

Activates the window and displays it in its current size and position

I hope this helps!

Upvotes: 2

tgikal
tgikal

Reputation: 1680

I actually have a windows application that does this using pywin32.

It looks for the application name, if it exists, it brings it to the front and closes the extra program.

version = "Program Name"

import win32gui
import sys

# Checks if there is a currently running program
# If there is, brings up that program
hwnd = win32gui.FindWindow(None, version)
if hwnd:
    win32gui.ShowWindow(hwnd, 5)
    win32gui.SetForegroundWindow(hwnd)
    sys.exit(0)

Upvotes: 2

Bryan Oakley
Bryan Oakley

Reputation: 386240

A simple cross-platform trick is to write the process id (pid) of the first instance to a file in a known location (eg: my_program.pid in the system temporary directory). Each time you start up, check to see if that file exists. If it exists, read the pid and check if the process is running. If the process is still running, exit. If not, keep running and write your process id to the file. When the program that wrote the file exits, it should delete the file.

There are possible race conditions (eg: the running program could quit in the brief moment after checking but before your program decides to quit), but unless you're building a commercial-grade application, this is usually good enough.

Upvotes: 2

Jeremiah Rose
Jeremiah Rose

Reputation: 4132

I would use a lock file with e.g the filelock library. Create an arbitrary file: if the file is unlocked, launch the GUI and lock the file. If the file is locked, just exit.

Upvotes: 2

Related Questions