Tkinter + Globalen Hotkey unter Windows

Fragen zu Tkinter.
Antworten
Benutzeravatar
borsTiHD
User
Beiträge: 10
Registriert: Sonntag 29. April 2018, 08:11

Hallo zusammen, :)

erstmal vorweg, ich bin neuling was Python betrifft und hoffe ihr könnt mir helfen. :)
Mein Problem ganz kurz angesprochen, ich suche eine Möglichkeit meine Python Anwendung + Tkinter GUI mit einem unter Windows globalen Hotkey anzusprechen, egal ob die Anwedung den Focus hat oder nicht, oder auch versteckt ist oder nicht.
Soll heißen, auch wenn meine GUI versteckt ist soll sobald der Hotkey gedrückt wird (zb. "STRG+<"), die GUI wieder erscheinen und oder zu der Mausposition wandern. Warum das ganze? Das werde ich weiter unten ausführlicher erklären, da ich versuche ein von mir geschriebenes AutoIT Script in Python umzubauen.

Versucht hab ich schon vieles, wie beispielsweise hier: https://stackoverflow.com/questions/207 ... th-tkinter
Und noch unzählige weitere. Habe daher leider keinen Überblick mehr was ich probiert habe und was nicht.

Mein letzter Versuch war die Einbindung eines Python Moduls namens "keyboard" ( https://github.com/boppreh/keyboard ).
Problem hier war allerdings, dass dieses Modul seinen eigenen loop (keyboard.wait()) brauch um auf den Hotkey zu achten.
Tkinter benötigt auch seinen eigenen loop (mainloop()) soweit ich es verstanden habe, darum hab ich versucht beide loops per theading aktiv zu haben.

Überraschenderweise funktioniert das so halbwegs.
Meine GUI ist da und gleichzeitig reagiert mein Hotkey, egal ob die GUI im Focus ist oder nicht.
Auch wenn ich die GUI über das "X" schließe (egt verstecke ich meine GUI nur), funktioniert der Hotkey.
Leider funktioniert mygui.GUIShow() nicht, sobald ich den Hotkey gedrückt habe.
Kann ich diese Methode nicht ausführen, weil meine mygui.mainloop() über den anderen Thread gestartet wurde?

Damit ich nicht noch einen Roman schreibe und noch mehr verwirre, zeige ich euch einfach mal meinen Quellcode den ich bisher habe.
Weitere erklärung was ich letztendlich machen will, schreibe ich weiter unten.

Code: Alles auswählen

# coding: utf8

# Bibliotheken
import Tkinter as Tk
import keyboard     # https://github.com/boppreh/keyboard
import time
from threading import Thread


##########################################################################################################
# --- MyGUI - Klasse -------------------------------------------------------------------------------
class MyGUI(object):

    def __init__(self, title="", width=50, height=50, x=0, y=0):
        """ Konstruktor der GUI """

        # Erstellt GUI mit namen rootGUI
        self.rootGUI = Tk.Tk()

        # Überträgt übergebene Variablen
        self.width = width
        self.height = height
        self.x = x
        self.y = y

        # Erstellt eine GUI ohne Windows Rahmen und bestimmt dessen Größe/Position
        self.rootGUI.geometry("%dx%d+%d+%d" % (self.width, self.height, self.x, self.y))
        self.rootGUI.wm_overrideredirect(True)

        # Hintergrundfarbe der GUI
        self.rootGUI.configure(background="#36393e")

        # GUI Rahmen wird erstellt
        self.gui_border = Tk.Canvas(self.rootGUI, width=self.width, height=25, bg = '#202225', highlightthickness=0)    # Erstellt den Canvas Bereich
        self.gui_border.place(x=0, y=0, width=self.width, height=25)                                                    # place() kümmert sich um die Plazierung des Rahmens
        self.gui_border.create_text(300, 12, fill="#ffffff", font="Consolas 16 bold", text=title)                       # Erstellt Fenstertitel in dem Canvas für den Rahmen
        self.gui_border.bind("<ButtonPress-1>", self.StartMove)                                                         # Sorgt für das Verschieben des Fensters
        self.gui_border.bind("<ButtonRelease-1>", self.StopMove)                                                        # Sorgt für das Verschieben des Fensters
        self.gui_border.bind("<B1-Motion>", self.OnMotion)                                                              # Sorgt für das Verschieben des Fensters

        # Erstellt "X" zum schließen der GUI
        self.gui_close_label = Tk.Label(self.rootGUI, text="X", font=("Helvetica", 12), fg="#a6a7a8", bg="#202225",)
        self.gui_close_label.place(x=600, y=0)
        self.gui_close_label.bind("<Button-1>", self.GUIHide)

        # Erstellt ein Button zum schließen der GUI
        self.button = Tk.Button(self.rootGUI, text='Quit', command=self.rootGUI.quit)
        self.button.place(x=50, y=50, width=80, height=50)

    # ------------------------------------------------------------------------------------------------------------------

    def StartMove(self, event):
        """ StartMove() Sorgt für das korrekte setzen der Startparameter """
        self.x = event.x
        self.y = event.y

    def StopMove(self, event):
        """ StopMove() Setzt beim stoppen die Klassenwerte für x/y auf None """
        self.x = None
        self.y = None

    def OnMotion(self, event):
        """ OnMotion() Kümmert sich um die Berechnung der neuen Fensterkoordinaten beim ziehen mit der Maus """
        deltax = event.x - self.x                   # Zieht von der Event x Koordinate die GUI x Koordinate ab
        deltay = event.y - self.y                   # Zieht von der Event y Koordinate die GUI y Koordinate ab
        x = self.rootGUI.winfo_x() + deltax         # Berechnet neue x Koordinate
        y = self.rootGUI.winfo_y() + deltay         # Berechnet neue y Koordinate
        self.rootGUI.geometry("+%s+%s" % (x, y))    # Setzt neue GUI Koordinaten

    def GUIHide(self, event):
        """ GUIHide() versteckt die GUI """
        self.rootGUI.withdraw()
        print("GUI wurde versteckt.")

    def GUIShow(self):
        """ GUIShow() zeigt die GUI """
        self.rootGUI.update()
        self.rootGUI.deiconify()
        print("GUI wird angezeigt.")

    def run(self):
        """ run() ist die Hauptschleife der GUI """
        print("GUI Mainloop wird gestartet.")
        self.rootGUI.mainloop()
        # return self.rootGUI

# --- AutoFan GUI - Klasse -------------------------------------------------------------------------------
##########################################################################################################


def sleeper(i):
    print "thread %d sleeps for 5 seconds" % i
    time.sleep(5)
    print "thread %d woke up" % i


def HotkeyPressed():
    print("Hotkey pressed")
    mygui.GUIShow()
    # mygui.update()
    # mygui.deiconify()
    print("Hotkey pressed - exit")


def MyGUIHotkey():
    print("Thread für Hotkey gestartet.")
    keyboard.add_hotkey('ctrl+<', HotkeyPressed)
    keyboard.wait()


def MyGUIThread():
    print("Thread für MyGUI gestartet.")
    mygui.run()


# Main Function
if __name__ == '__main__':

    """
    # Thread test!
    for i in range(10):
        t = Thread(target=sleeper, args=(i,))
        t.start()
    """

    mygui = MyGUI("MyGUI - Python Edition", 620, 500, 100, 100)

    # Erstelle Thread mit Hotkey Funktion
    threadHotkey = Thread(target=MyGUIHotkey)
    threadHotkey.start()

    # Thread für GUI wird erstellt
    threadGUI = Thread(target=MyGUIThread)
    threadGUI.start()

    # mygui = MyGUI("AutoFan v2 - Python Edition", 620, 500, 100, 100).run()

Sooo, hier möchte ich euch noch kurz schildern was ich wirklich vor habe, damit ihr euch was darunter vorstellen könnt.
Müsst aber nicht den ganzen Text lesen.

Ich habe ein AutoIT Script geschrieben, welches im Hintergrund bleibt, auf den Hotkey wartet und dann den User helfen soll, jenachdem was an Daten vorhanden sind, bzw gefunden wurden.
Der User markiert einen beliebigen Text, beispielsweise mit der Maus aus einer Excelartig aufgebauten Anwendung (ein Eventprogramm mit vielen Events drin). Sobald der Hotkey gedrückt wurde, macht das AutoIT Script intern ein "STRG+C" und liest das Clipboard ein.

Anschließend werten verschiedene Funktionen das Clipboard aus und prüfen was an Daten vorhanden sind, bzw gefunden wurden.
Beispielsweise ein Datum wird erkannt, Leitungsführungen werden erkannt, etc etc.
Das ganze habe ich in einzelne Module aufgegliedert.

Jenachdem welche Daten jetzt erkannt wurden im Clipboard, baut das AutoIT Script die verschiedenen Module auf, so damit in der AutoIT GUI "nur noch" die Module angezeigt werden, die mit den im Clipboard vorhandenen Daten etwas anfangen können, bzw weiter verwendet werden können (beispiel: wurde im Clipboard KEIN Datum erkannt, wird dieses Modul nicht angezeigt).

Wurden alle benötigten Module erkannt, baut sich die GUI auf (das heißt auch, das meine GUI nie die gleiche größe besitzt, sondern mal größer mal kleiner ausfallen kann). Zudem gibt es zwei Optionen die der User setzen kann, damit das AutoIT Script, bzw die GUI nach dem Hotkey an der Mausposition erscheint, oder eine feste Fensterposition bekommt (indem die aktuelle Fensterposition, bei setzen der Option gespeichert wird). Eine weitere Option die der User nutzen kann, ist ob das Fenster "on Top" bleibt, also immer über andere Fenster liegt und sich nicht in den Hintergrund schieben lässt.

Das AutoIT Script funktioniert sehr gut und ist mittlerweile sehr umfangreich geworden.
Darum bin ich auch an meine Grenzen gestoßen. Das AutoIT Script reicht von der performance her, aber würde gerne mehr rausholen.
Zudem möchte ich Threading nutzen und mehrere Arbeitsabläufe parallel laufen lassen. Bei AutoIT habe ich das mithilfe von forking versucht, was zwar gut klappt, aber nicht echtes threading ist und auch etwas umständlich in der Nutzung ist. Desweiteren würde ich gerne mit der objektorientierten Programmierung anfangen und AutoIT ist nicht objektorientiert, oder ich weiß nicht wie.

Ich hoffe ich konnte mein Vorhaben verständlich genug formulieren und hoffe ihr könnt mir bei meinem Problem weiterhelfen. :)
Vielen Dank schon mal im Voraus.

Grüße
borsTiHD


PS: Aus gewissen Gründen kann ich leider nur auf Python 2.7.x zurückgreifen.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Zuerstmal: du darfst auf keinen Fall den Tkinter mainloop in einem neuen Thread starten! Das das überhaupt funktioniert ist reiner Zufall. Gerade Windows ist SEHR picky dabei, an welchen thread es Ereignisse ausliefert.

Den Thread kannst du ihr also sparen, und stattdessen mainloop aus dem Haupt-Thread aufrufen.

Zum zweiten funktioniert Keyboard augenscheinlich asynchron, sprich: die Hotkyes kommen per Event loop in den Prozess. Die wait Funktion schläft einfach endlos: https://github.com/boppreh/keyboard/blo ... _init__.py

Also kannst du dir denke ich den zweiten Thread AUCH sparen. Hast du das mal ausprobiert?

Was dann deine eigentlichen Pläne und deren Multi-threaded-ness angeht: da bräuchte ich noch etwas mehr Infos, was du da genau zu erreichen hoffst.
Benutzeravatar
borsTiHD
User
Beiträge: 10
Registriert: Sonntag 29. April 2018, 08:11

Hahaha, wow... ja ich habs grad mal ausprobiert. :D
Jegliches Threadding ist derzeit rausgenommen, bzw auskommentiert.
Ich starte nach meiner Objekterstellung die Funktion ".run()" für mein Mainloop und ".wait()" für keyboard lasse ich komplett weg.
Das funktioniert so... :lol:
Vielen Dank schon mal hierfür.

Den neuen Quellcode poste ich gleich unten.

Und ja, sorry... hatte mir schon gedacht das ich zuviel schreibe und es unübersichtlich wird.

Was habe ich vor:
Sobald die Anwendung gestartet wurde, soll die GUI mit einer Willkommensnachricht (mit paar Infos zum Programm selbst) aufgebaut werden.
Ab diesem Zeitpunkt soll die Anwendung auf den Hotkey warten und macht erstmal nichts.

Sobald der Hotkey gedrückt wird, soll die GUI wenn sie vorher versteckt wurde erscheinen (das möchte ich mithilfe der "mygui.GUIShow()" methode erreichen). Wenn die GUI vorher nicht versteckt war, soll die Position der GUI sich ändern, damit die GUI bei der aktuellen Mausposition erscheint. Soweit bin ich aber noch nicht. Derzeit hängt sich nach dem drücken des Hotkeys meine Anwendung auf.
Also folgender Teil scheint nicht zu funktionieren:

Code: Alles auswählen

def HotkeyPressed():
    print("Hotkey pressed")
    mygui.GUIShow()
    print("Hotkey pressed - exit")

Kompletter Quellcode:

Code: Alles auswählen

# coding: utf8

# Bibliotheken
import Tkinter as Tk
import keyboard     # https://github.com/boppreh/keyboard
import time
from threading import Thread


##########################################################################################################
# --- MyGUI - Klasse -------------------------------------------------------------------------------
class MyGUI(object):

    def __init__(self, title="", width=50, height=50, x=0, y=0):
        """ Konstruktor der GUI """

        # Erstellt GUI mit namen rootGUI
        self.rootGUI = Tk.Tk()

        # Überträgt übergebene Variablen
        self.width = width
        self.height = height
        self.x = x
        self.y = y

        # Erstellt eine GUI ohne Windows Rahmen und bestimmt dessen Größe/Position
        self.rootGUI.geometry("%dx%d+%d+%d" % (self.width, self.height, self.x, self.y))
        self.rootGUI.wm_overrideredirect(True)

        # Hintergrundfarbe der GUI
        self.rootGUI.configure(background="#36393e")

        # GUI Rahmen wird erstellt
        self.gui_border = Tk.Canvas(self.rootGUI, width=self.width, height=25, bg = '#202225', highlightthickness=0)    # Erstellt den Canvas Bereich
        self.gui_border.place(x=0, y=0, width=self.width, height=25)                                                    # place() kümmert sich um die Plazierung des Rahmens
        self.gui_border.create_text(300, 12, fill="#ffffff", font="Consolas 16 bold", text=title)                       # Erstellt Fenstertitel in dem Canvas für den Rahmen
        self.gui_border.bind("<ButtonPress-1>", self.StartMove)                                                         # Sorgt für das Verschieben des Fensters
        self.gui_border.bind("<ButtonRelease-1>", self.StopMove)                                                        # Sorgt für das Verschieben des Fensters
        self.gui_border.bind("<B1-Motion>", self.OnMotion)                                                              # Sorgt für das Verschieben des Fensters

        # Erstellt "X" zum schließen der GUI
        self.gui_close_label = Tk.Label(self.rootGUI, text="X", font=("Helvetica", 12), fg="#a6a7a8", bg="#202225",)
        self.gui_close_label.place(x=600, y=0)
        self.gui_close_label.bind("<Button-1>", self.GUIHide)

        # Erstellt ein Button zum schließen der GUI
        self.button = Tk.Button(self.rootGUI, text='Quit', command=self.rootGUI.quit)
        self.button.place(x=50, y=50, width=80, height=50)

    # ------------------------------------------------------------------------------------------------------------------

    def StartMove(self, event):
        """ StartMove() Sorgt für das korrekte setzen der Startparameter """
        self.x = event.x
        self.y = event.y

    def StopMove(self, event):
        """ StopMove() Setzt beim stoppen die Klassenwerte für x/y auf None """
        self.x = None
        self.y = None

    def OnMotion(self, event):
        """ OnMotion() Kümmert sich um die Berechnung der neuen Fensterkoordinaten beim ziehen mit der Maus """
        deltax = event.x - self.x                   # Zieht von der Event x Koordinate die GUI x Koordinate ab
        deltay = event.y - self.y                   # Zieht von der Event y Koordinate die GUI y Koordinate ab
        x = self.rootGUI.winfo_x() + deltax         # Berechnet neue x Koordinate
        y = self.rootGUI.winfo_y() + deltay         # Berechnet neue y Koordinate
        self.rootGUI.geometry("+%s+%s" % (x, y))    # Setzt neue GUI Koordinaten

    def GUIHide(self, event):
        """ GUIHide() versteckt die GUI """
        self.rootGUI.withdraw()
        print("GUI wurde versteckt.")

    def GUIShow(self):
        """ GUIShow() zeigt die GUI """
        self.rootGUI.update()
        self.rootGUI.deiconify()
        print("GUI wird angezeigt.")

    def run(self):
        """ run() ist die Hauptschleife der GUI """
        print("GUI Mainloop wird gestartet.")
        self.rootGUI.mainloop()
        # return self.rootGUI

# --- MyGUI  - Klasse -------------------------------------------------------------------------------
##########################################################################################################


def HotkeyPressed():
    print("Hotkey pressed")
    mygui.GUIShow()
    # mygui.update()
    # mygui.deiconify()
    print("Hotkey pressed - exit")


# Main Function
if __name__ == '__main__':

    keyboard.add_hotkey('ctrl+<', HotkeyPressed)

    mygui = MyGUI("AutoFan v2 - Python Edition", 620, 500, 100, 100)
    mygui.run()

    # mygui = MyGUI("AutoFan v2 - Python Edition", 620, 500, 100, 100).run()

€dit: Achso, weil du wissen wolltest was ich mit dem Threadding erreichen möchte.
Mein AutoIT Script sucht anhand mehrerer RegularExp aus den markierten Texten Netzelemente raus.
Diese Netzelemente möchte ich später über eine Web API anpingen und per CLI auslesen lassen (macht mir die API) und die Rückgabe, die ich per JSON bekomme in der GUI anzeigen lassen.
Das ganze dann parallel für mehrere Netzelemente und nicht hintereinander. :)
Benutzeravatar
borsTiHD
User
Beiträge: 10
Registriert: Sonntag 29. April 2018, 08:11

Hi, sorry wegen dem Doppelpost, aber ich konnte nicht mehr editieren?!
Ich bin jetzt auf Python 3 mal interessehalber umgestiegen, hab den Import auf tkinter (kleingeschrieben) geändert und siehe da, meine Funktion funktioniert mit "mygui.GUIShow()".

Sobald der Hotkey gedrückt wird, öffnet sich meine GUI an der gleichen stelle an der ich sie zuvor "versteckt" hatte.

Jetzt stehe ich nur vor dem Problem das ich egt auf Python 2 angewiesen bin, wurde aber heute durch einen Kollegen auf "pyinstaller" hingewiesen. Meine Lösung wäre also einfach aus meinem Projekt eine standalone *.exe zu bauen. Damit hätte ich das Problem auch umgangen und der User kann zudem eine bekannte "exe" öffnen, wäre wunderbar.

Eine Frage hätte ich aber noch.
Und zwar um das ganze zu verstehen... warum konnte, nachdem mein Hotkey die Funktion "HotkeyPressed()" ausgelöst hat, diese Funktion "mygui.GUIShow()" nicht ausführen und ist abgestürzt, bzw eher hat sich aufgehangen und reagierte nicht mehr?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Keine Ahnung warum das kracht oder nicht geht. Dazu müsste man stack traces sehen bzw ganz generell logging einbauen.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi borsTIHD

Hast du es auch einmal mit dem Modul pynput probiert?
https://pypi.org/project/pynput/
Dieses Modul funktioniert auch unter Linux ohne das Skript mit dem sudo-Befehl starten zu müssen.
Das Modul funktioniert unter Python 3.xx & Python 2.xx

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
borsTiHD
User
Beiträge: 10
Registriert: Sonntag 29. April 2018, 08:11

__deets__ hat geschrieben:Keine Ahnung warum das kracht oder nicht geht. Dazu müsste man stack traces sehen bzw ganz generell logging einbauen.
Ah ok, nicht schlimm, dann stempel ich es einfach mal ab und ignoriere es.
Mir gings nur darum, das ich noch nie intensiv mit Klassen gearbeitet hatte und dachte ich hätte hier einen groben Fehler gemacht.
Aber... bezüglich logging einbauen. Hättest du da Stichworte die ich in Verbindung mit Python recherchieren könnte?
Weil mein "logging" würde sonst aus simplen "prints" bestehen, wie bereits getan. :D
wuf hat geschrieben:Hi borsTIHD

Hast du es auch einmal mit dem Modul pynput probiert?
https://pypi.org/project/pynput/
Dieses Modul funktioniert auch unter Linux ohne das Skript mit dem sudo-Befehl starten zu müssen.
Das Modul funktioniert unter Python 3.xx & Python 2.xx

Gruss wuf :wink:
Oh das werde ich mir auch mal anschauen.
Wie gessagt läuft das Programm letzendlich unter Windows, aber damit kommt pynput ja scheinbar auch zurecht.
Ich werds ausprobieren, ist vlt besser für mich. :)

Jedenfalls schon mal vielen Dank euch Beiden. :wink:


€dit:
Interessehalber noch eine Frage.
Weil ich mir pynput grad anschaue, dort gitb es einen Eventlistener (listener.join()) der auf die Events achtet.
In der Beschreibung dazu steht, das dieser listener in einem separaten Thread läuft.
Heißt das, dass die Bibliothek "keyboard" die ich derzeit nutze nicht auch in irgendeiner Form einen Eventlistener besitzt?
Könnte es sein das der dann auch in einem separaten Thread läuft? Weil sonst würde er ja alles blockieren nehme ich an.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi borsTiHD

Hier ein Experimentierskript (Ausprobiert unter Windows10 & Ubuntu 18.04):

Code: Alles auswählen

# -*- coding: utf-8 -*-

import threading
from pynput import keyboard

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
    import Queue as qu
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk
    import queue as qu

APP_TITLE = "Update Label Display"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 200
UPDATE_TIME = 500 # Milliseconds

QUEUE_SIZE = 10
POLLING_TIME = 100   # Milliseconds


class AppThread(threading.Thread):
    
    def __init__(self, queue=None):
        self.queue = queue
        self.key = None
        self.count = 0
        
        threading.Thread.__init__(self)
        self.start()

    def run(self):
        # Collect events until released
        with keyboard.Listener(
                on_press=self.on_press,
                on_release=self.on_release) as listener:
            listener.join()

    def on_press(self, key):
        try:
            print('alphanumeric key {0} pressed'.format(
                key.char))
            self.update_queue(key.char)
        except AttributeError:
            print('special key {0} pressed'.format(
                key))
            
    def on_release(self, key):
        return
        # print('{0} released'.format(
            # key))
        # if key == keyboard.Key.esc:
            # # Stop listener
            # return False
        
    def update_queue(self, count):
        self.queue.put(count)
        self.queue.join()
    
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        self.master.protocol("WM_DELETE_WINDOW", self.close)
        tk.Frame.__init__(self, master)
        
        self.app_key_listener = None
        
        self.control_frame = tk.Frame(self)
        self.control_frame.pack(expand=True)
        
        tk.Label(self.control_frame, text="Tasten-Char:").pack(fill='x', pady=(0,1))
        
        self.var = tk.StringVar()
        tk.Label(self.control_frame, relief='sunken', bg='white', width=10,
            textvariable=self.var).pack(fill='x', pady=(0,10))
        
        tk.Button(self.control_frame, text="Starte pynput Thread",
            command=self.start_listener).pack(fill='x')

        self.queue = qu.Queue(QUEUE_SIZE)
        self.queue_polling()
 
    def start_listener(self):
        if self.app_key_listener == None:
            self.app_key_listener = AppThread(self.queue)
        else:
            if not self.app_thread.isAlive():
                self.app_key_listener = AppThread(self.queue)
       
    def queue_polling(self):
        if self.queue.qsize():
            try:
                data = self.queue.get()
                self.var.set(str(data))
                
                if data == "H":
                    # Verstecke Hauptfenster
                    self.master.withdraw()
                if data == "S":
                    # Zeige Hauptfenster
                    self.master.deiconify()
                    
                self.queue.task_done()
            except qu.Empty:
                pass
        
        self.after(POLLING_TIME, self.queue_polling)
                
    def close(self):
        print("Application-Shutdown")
        if self.app_key_listener != None:
            self.app_key_listener.join(0.1)
        self.master.destroy()
    
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
borsTiHD
User
Beiträge: 10
Registriert: Sonntag 29. April 2018, 08:11

Hey vielen vielen Dank dafür. :D
Ich habs kurz überflogen und ich denke daraus kann ich auch einiges über Klassen untereinander lernen.
Werde ich morgen in Ruhe ausprobieren.
Antworten