after() Funktion nur einmal möglich?

Fragen zu Tkinter.
jake-the-snake

Abend Forum

Ich habe folgendes Gerüst:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from tkinter import *
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText

def short_message():
    messagebox.askyesno("System-Meldung", "Programm aktiv - Bitte warten...")
    print ("Funktion short_message ausgeführt!")

# Fenster-Titel
root = Tk(className=" Hauptfenster")
root.resizable(FALSE,FALSE)
root.attributes("-topmost", 1)
root.wm_attributes('-type', 'splash')

def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()

    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))
    
center_window(800, 480)

# Titel Schrift ueber Programm-Fenster 
zeroLabel = Label(root, text=">> Hauptfenster mit Aktivität <<", font=("TimesNewRoman", 10), bg=('#999999'))
zeroLabel.place(x=305,y=28)

root.after(2000, short_message)

root.mainloop()
Normalerweise sollte das Programm bis zum Fensteraufbau "root = Tk(className=" Hauptfenster")" durchlaufen. Wenn die Ablaufroutine auf "root.after(2000, short_message)" trifft, wird meine Funktion " short_message" aufgerufen und ausgeführt. Nach dem Klicken (ja oder nein ist erst mal Wurst), sollte doch der Programmablauf wieder in den mainloop springen. Dann sollte bei einem erneuten Durchlauf doch wieder "root.after(2000, short_message)" aufgerufen werden??? Zeile 13 bis 36 müsste doch endlos aktiv sein???

Fakt ist, dass die after()-Anweisung im mainloop nur einmal wirkt.

Warum?

Gruss jts
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Weil das eben so ist. after scheduled - wie in der Dokumentation auch klar beschrieben - nur einmal, und man muss re-schedulen (gerne auch im callback selbst):

http://effbot.org/tkinterbook/widget.ht ... ter-method
"""
after(delay_ms, callback=None, *args) [#]
Registers an alarm callback that is called after a given time.

This method registers a callback function that will be called after a given number of milliseconds. Tkinter only guarantees that the callback will not be called earlier than that; if the system is busy, the actual delay may be much longer.

The callback is only called once for each call to this method. To keep calling the callback, you need to reregister the callback inside itself:
"""
jake-the-snake

Abend _deets_

Ich habe die definierte Funktion durch die selbe Zeile wie in der mainloop ergänzt::

Code: Alles auswählen

def short_message():
    messagebox.askyesno("System-Meldung", "Programm aktiv - Bitte warten...")
    print ("Funktion short_message ausgeführt!")
    root.after(2000, short_message)
Jetzt fragt er immer wieder. Das heißt die messagebox fragt immer wieder nach. Soweit so gut. In wie weit mir das jetzt weiterhilft - mal schauen...

Also es geht mit der Ergänzung oben.

Gruss jts
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na, wenn du programmierst, das alle 2 Sekunden eine MessageBox aufgeht, dann geht eben alles zwei Sekunden eine Messagebox auf. Ob das sinnvoll ist, kannst ja nur du beurteilen.
jake-the-snake

Hallo

Ich bin immer noch am Überlegen, wie der eigensinnige Programmablauf von der GUI beeinflusst werden kann.
Soweit ich das begreife, ist die GUI eine Endlosschleife. Sie bricht nur bei Ereignissen ab. Zum Beispiel wenn eine Funktion "app = App(root)" oder eben "after()" aufgerufen wird.

Also hat man, wie jetzt bei mir, oben einen Programmteil (nennen wir den mal Block A), und unten eine Endlosschleife, die tk-GUI-Fenstergeschichte (hier mal als Block B betitelt). Veränderungen in dem angezeigten Fenster sind nur dann möglich, wenn sie vollendet vorliegen und das Programm sich im Block B - der Endlosschleife - befindet.

Sollte sich jetzt das Python-Programm im Block A befinden, wo es in einer Rechenroutine oder Schleife steckt, dessen Ausführung eine gewisse Zeit benötigt, ist das Python-Programm also nicht in dem unteren Block B. Das heißt, dass auch, solange gerechnet wird, keine Änderungen an der Anzeige, bzw. dem Fensterinhalt getätigt werden können. Das ist ein Problem!

Bei langen Schleifendurchläufen könnte man dem Programm durchaus sagen: Setze alle bsp. 50 Durchläufe ein Signal ab, oder ändere irgendetwas an der Grafik. Leider ist man Programmtechnisch an der Stelle ja im Block A -> Und da kann man grafisch nichts ändern... schwierig - das ganze...

Gruss jts
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Auch wenn's etwas holperig ausgedrueckt ist, klingt das ganz richtig. Die Hauptschleife muss betreten werden, um die Ereignisbehandlung auszuloesen. Ereignisse sind natuerlich Benutzerinteraktionen, aber auch Timer oder zB Netzwerk-Kommunikation respektive genreller IO.

Wenn man nun laengere Aufgaben erledigen will, hat man vier Moeglichkeiten:

1) es einfach tun. Die GUI blockiert, und das ist doof. Windows sagt dann ggf. sogar so etwas wie "das Programm reagiert nicht mehr, soll ich es beenden?"
2) die Aufgabe in kleine Happen zerteilen, die man aus einem Timer heraus immer wieder ausfuehrt. Das ist etwas muehselig, weil man sehr aufpassen muss, wie man das anstellt, und sich schnell verprogrammiert, womit man dann wieder bei 1 landet.
3) man treibt den Event-Loop selbst. Das ist allerdings in Tkinter nicht vorgesehen, und hat den Nachteil, das die langwierige Berechnung zwangsweise verknuepft ist mit der Idee, das es eben eine GUI gibt. Ausserdem *kann* man auch da in die Falle von 2 tappen, und ist wieder bei 1...
4) es bleibt die einzig verlaessliche: einen neuen Thread starten, und in dem Thread die Berechnung durchfuehren. Dann kann die lang anhaltende Berechnung ungestoert bzw. ohne zu stoeren ablaufen. AAAABER: hier muss man aufpassen, das man *NICHT* aus dem Hintergrundthread GUI-Objekte manipuliert: das moegen GUIS ueberhautp nicht. Das heisst, das man das ueblicherweise mit zb einer Ergebnis-Queue verknuepft, die man im Event-Loop mit after periodisch checkt, und dann entsprechend reagiert (zB Button aktivieren/de-aktivieren, Fortschritt anzeigen, etc....)

Zu tkinter und Queues findet sich hier im Forum tonnenweise Beispielcode, gerne zB von BlackJack.
jake-the-snake

Abend nochmal

OK. Da habe ich eine Menge Input bekommen. Wird eine Zeit brauchen, das durch zu gehen. Vielen Dank für die Infos. Jetzt habe ich mal eine grobe Marschrichtung :wink:

zu 1) Macht Linux - Gott sei Dank - nicht!

zu 2) Wäre eine Option. Müsste da halt wissen, wie ich von Block A in die mainloop eintrete und wieder zurück kehre.

zu 3) Was meinst du mit selber treiben?

zu 4) An eine Auslagerung des rechenintensiven Programmteiles hatte ich auch schon gedacht. Doch wie so was von statten geht weiss ich nicht. Als extra Programm? Dann müsste ich ja auch eine Art pipe "|" legen, die die Programminfos vom ausgelagerten Teil dem Hauptprogramm zu schiebt :wink:

Wie gesagt, ich geh eine paar Runden im Forum "schnüffeln"...

Bis die Tage...

Gruss jts
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@jake-the-snake: __deets__ hat die Punkte 1 bis 3 nur dazugeschrieben, dass, falls Du über solche „Lösungen“ stolperst, nicht denkst, sie wären gut; damit brauchst Du Dich also nicht beschäftigen. Bei Punkt 4 steht doch schon, dass Du Threads benutzen sollst, alternativ multiprocessing, wobei für beides Queues existieren, um Programminfos hin und her zu schieben.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi jake-the-snake

Habe leider nicht ganz verstanden was das Problem ist. Habe in deinem Skript einen Zähler 'count_up' eingebaut, welcher auch während der Messagebox-Aktion weiterläuft. Hier das modifizierte Skript:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
 
from tkinter import *
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText
 
def short_message():
    root.after(2000, show_message)

def show_message():
    messagebox.askyesno("System-Meldung", "Programm aktiv - Bitte warten...")
    print ("Funktion short_message ausgeführt!")
    
def count_up(counter=0):
    print(counter)
    counter += 1
    root.after(5, count_up, counter)
        
# Fenster-Titel
root = Tk(className=" Hauptfenster")
root.resizable(FALSE,FALSE)
root.attributes("-topmost", 1)
root.wm_attributes('-type', 'splash')

def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
 
    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))
   
center_window(800, 480)
 
# Titel Schrift ueber Programm-Fenster
zeroLabel = Label(root, text=">> Hauptfenster mit Aktivität <<", font=("TimesNewRoman", 10), bg=('#999999'))
zeroLabel.place(x=305,y=28)

short_message()
count_up()
 
root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
jake-the-snake

Hallo wuf

Zwar nicht das Problem, an dem ich gerade herum knübel, aber dennoch interessant!
Die Messagebox müsste eigentlich die Programmausführung solange unterbrechen, bis ein Button gedrückt wurde.
Aber der Reihe nach:

Dein Programm läuft herunter bis es in der Mainloop auf "short_message()" trifft. Dann müsste es theoretisch oben in Zeile 8 weiter gehen.
Da wird 2 sec gewartet und zur Funktion "show_message" gesprungen.

Was jetzt passiert erschließt sich mir noch nicht ganz. Meine beiden Theorien:

1)
Nachdem zu "show_message" gesprungen wurde, gilt die Funktion "short_message()" als abgearbeitet und das Programm läuft unten in der Mainloop
mit der Aktion "count_up()" weiter? Das kann allerdings nicht sein, da von Anfang an gezählt wird.

2)
Startet die Mainloop etwa beide Funktionsaufrufe gleichzeitig? Also "short_message()" und "count_up()"?

Was passiert hier - Warum und wie funktioniert der Ablauf hier?

Gruss jts
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@jake-the-snake: Du hast die Funktionsweise von `after` noch nicht verstanden. Da wird nirgends gewartet, sondern es wird ein Timer gestartet, der nach einer bestimmten Zeit ein Event auslöst. Deine Vorstellung von Springen ist bei einem GUI-Programm auch nicht ganz richtig. Denke eher an Event-Abarbeitung.
jake-the-snake

Hallo Sirius3

Aha, dann ist also Variante 1 meiner Erklärung richtig und kann doch so sein, da ja der timer gestartet wurde.

Gruss jts
jake-the-snake

Abend Forum

Ich poste das nun nochmal hier herein, weil es eventuell doch mit after zu tun hat:

Gegeben ist eine class App mit einem Knopf (Der heißt Verschlüsseln)

Außerdem eine Tk-Fensterloop.

Drückt man auf den Knopf, soll nicht die Verschlüsselungsroutine anlaufen, sondern nur ein Info-Fenster erscheinen (Funktion: write_precoding)
Gleichzeitig wird eine Variable (codeprocess) auf "yes" gestellt. Danach sollte das Programm wieder in den Mainloop eintreten.

In der Mainloop wird geschaut, ob die Variable codeprocess auf "yes" steht. Wenn ja soll die Funktion : write_coding ausgeführt werden.
Am Ende von write_coding muss das Label von write_precoding wieder weg, und die Variable precoding wieder auf "no" gesetzt werden.

Soweit bin ich bis jetzt gekommen:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from tkinter import *

codeprocess = "no"

# Einleitung der App-Knoepfe / Hier gibt es jetzt nur einen zum Test
class App:
  
    def __init__(self, master):
        frame = Frame(master)
        frame.place(width=120, height=320, x=340, y=170)
        
       
        # Pre-Code-Button
        self.precoding = Button(frame, 
                         text="Verschlüsseln ►", fg="red", pady=5, padx=5,
                         command=self.write_precoding)
        self.precoding.pack()

####################
# Codierungs-Block #
####################

    def write_precoding(self):
        # Prozess-Meldung
        fourLabel = Label(root, text="Bitte warten...", font=("TimesNewRoman", 20), borderwidth=2, relief=("groove"), background=("#ff5a5a"), width=36, anchor=("center"))
        fourLabel.place(x=150,y=165)
        codeprocess = "yes"
        print("precoding Ansprung hat geklappt...")
        root.after(1000, write_coding)

    def write_coding(self):
        print("Beginn des Codierungsblock")

####################
# Mainloop - Block #
####################

# Fenster-Titel
root = Tk(className=" Fenstername Blablabla")
root.resizable(FALSE,FALSE)
root.attributes("-topmost", 1)
root.wm_attributes('-type', 'splash')

# Knoepfe-App-Ende
app = App(root)

def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()

    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))
    
center_window(800, 480)


if codeprocess == "yes":
    
    codeprocess = "no"
    print("if-Block mainloop erreicht") 

root.mainloop()
Das Testprogramm läuft bis Zeile 32. Aber es will die Funktion bzw. Sprungmarke "def write_coding(self):" nicht akzeptieren und behauptet die Funktion wäre nicht definiert - was sie aber doch ist? Oder ich bin blind...

Im Grunde brauche ich zwei Funktionen hintereinander, die aber nur durch einen Button-Klick stattfinden sollen. Zu allem Übel soll nach der ersten Anzeigefunktion noch mal kurz der mainloop konsultiert werden, bevor es mit der zweiten Funktion weiter geht...

Ich hol mir jetzt einen Kaffee... mein Schädel ist am Qualmen...

Gruss jts
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@jake-the-snake: solange Du noch an Sprungmarken denkst, wird das nichts. »write_coding« wird nirgends definiert, weil es nur ein »write_coding« als Methode der Klasse »App« gibt. Die Variable »codeprocess« macht keinen Sinn, ebenso Zeilen 63ff; hier hast Du ereignisbasierte GUI-Programmierung immer noch nicht verstanden.

Daneben solltest Du immer noch keine *-Importe benutzen und die Kommentare mit den vielen ##### zeigen, dass Du als erstes Lernen solltest, was Funktionen sind, dann was Klassen sind, bevor Du dich weiter mit GUIs beschäftigen kannst.
jake-the-snake

Hallo zusammen
Die Variable »codeprocess« macht keinen Sinn, ebenso Zeilen 63ff; hier hast Du ereignisbasierte GUI-Programmierung immer noch nicht verstanden.
Ja, da war ich auch noch nicht fertig. Das mit der Funktion ist jetzt klar. Die Funktion write_coding war Teil der Class App. Deshalb hat Python gemekert.
Ich habe es jetzt raus geschoben, in einen eigenen Block.

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from tkinter import *

global codeprocess
codeprocess = ""

# Einleitung der App-Knoepfe / Hier gibt es jetzt nur einen zum Test
class App:
  
    def __init__(self, master):
        frame = Frame(master)
        frame.place(width=120, height=320, x=340, y=170)
        
       
        # Pre-Code-Button
        self.precoding = Button(frame, 
                         text="Verschlüsseln ►", fg="red", pady=5, padx=5,
                         command=self.write_precoding)
        self.precoding.pack()

####################
# Codierungs-Block #
####################

    def write_precoding(self):
        # Prozess-Meldung
        fourLabel = Label(root, text="Bitte warten...", font=("TimesNewRoman", 20), borderwidth=2, relief=("groove"), background=("#ff5a5a"), width=36, anchor=("center"))
        fourLabel.place(x=150,y=165)
        codeprocess = "yes"
        print("precoding Ansprung hat geklappt...", codeprocess)

def write_coding(self):
    i = 0
    while i <= 10000000:
        i = i + 1
    print("Beginn des Codierungsblock")

####################
# Mainloop - Block #
####################

# Fenster-Titel
root = Tk(className=" Fenstername Blablabla")
root.resizable(FALSE,FALSE)
root.attributes("-topmost", 1)
root.wm_attributes('-type', 'splash')

# Knoepfe-App-Ende
app = App(root)

def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()

    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))
    
center_window(800, 480)

if codeprocess == "yes":
    print("if-Block mainloop erreicht")
    codeprocess = "no" 
    write_coding(self)

root.mainloop()
Das Programm läuft bis Zeile 32. Dort wird die Variable (jetzt global) auch umgestellt (habe mir die extra ausgeben lassen).
Eigentlich sollte es jetzt unten in der Mainloop, Zeile 65 weiter gehen. Aus irgend einem, mir noch nicht klaren Grund, tut es das aber nicht.

In einem Anderen Programm habe ich auch einen if-Block in der Mainloop, und der funktioniert. Wo ist das Problem?

Gruss jts
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@jake-the-snake: Du hast eine falsche Vorstellung davon, wie ein Programm abläuft. Was passiert alles, bevor die Methode write_precoding aufgerufen wird, Du also zu Zeile 32 kommst? Zum Glück weißt Du nicht, wie man globale Variablen benutzt, sonst wüßtest Du wahrscheinlich nur, wie man sie falsch benutzt; codeprocess kann so nicht verwendet werden, wie Du es Dir denkst und wenn Du es richtig löst, wirst Du codeprocess nicht brauchen. Hast Du einen Debugger, wo Du mal Schritt für Schritt Dein Programm durchgehen kannst?
jake-the-snake

Hallo Sirius3

Ich habe hier von Ubuntu den gedit und den auf python3-Modus eingestellt.

Zum Ablauf:
Das Programm läuft von oben nach unten durch und startet dann mit der Mainloop.
Nur Ereignisse können den Programmzeiger aus der Mainloop holen. Es läuft ja auch alles bis Zeile 32, wenn man den Button drückt.
Nur, nachdem der Block write_precoding(self) abgearbeitet wurde, müsste doch der Programmzeiger wieder in die Mainloop springen.
Tut er aber nicht. Habe auch schon ein "return" unter den write_precoding(self)-Block gesetzt. Geht auch nicht, sowie gedacht.

Aber nach deiner Antwort gibt es eine Lösung, wo die codeprocess-Variable nicht benötigt wird? Hör ich doch so richtig heraus? :)

Gruss jts
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi jake-the-snake

Habe mich heute Morgen noch ein bisschen deinem Problem gewidmet. Hoffe mein Skript hat eine klärende Wirkung:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import textwrap
import tkinter as tk

APP_TITLE = "Verschlüsselung"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 200

        
class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        
        self.codeprocess = "no"
        self.label_var = tk.StringVar()
        
        # Pre-Code-Button
        self.button_precoding = tk.Button(master, text="Verschlüsseln ►", fg="red",
            command=self.write_precoding)
        self.button_precoding.pack(expand=True)

    ####################
    # Codierungs-Block #
    ####################
    def write_precoding(self):
        self.button_precoding.config(state='disabled')
        # Prozess-Meldung
        self.label_var.set("Bitte warten...\nprecoding Ansprung hat geklappt!")
        self.four_label = tk.Label(self.master, textvariable=self.label_var,
            font=("TimesNewRoman", 18), relief="groove", bg='#FFA5A5',padx=5,
            pady=5)
        self.four_label.pack(expand=True)
        self.master.after(3000, self.write_coding)
 
    def write_coding(self):
        self.codeprocess = "yes"
        self.label_var.set("Beginn des Codierungsblock")
        self.master.after(3000, self.end_coding)
        
    def end_coding(self):
        message = '''Der Codierungsblock ist beendet!
        Nun kann der Verschlüsselungsprozess neu gestartet werden.
        WICHTIG: Das Programm kehr nicht zum Mainloop-Block zurück!!!
        Der im Hintergrund laufenden 'mainloop'-Thread wartet nun auf ein neues
        Ereigniss. In unserem Fall wäre dies eine Neuaktivierung des Buttons
        "Verschlüsseln ►"'''
        template = textwrap.dedent(message).rstrip()
        self.four_label.config(bg='#BADA6A')
        self.label_var.set(template)
        self.master.after(8000, self.master.destroy)

                  
####################
# Globale Funktion #
####################
def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()
 
    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))


####################
# Mainloop - Block #
####################
root = tk.Tk()
root.title(APP_TITLE)
root.resizable(False, False)
root.attributes("-topmost", 1)
root.wm_attributes('-type', 'splash')
center_window(800, 480)
    
app = Application(root)

print("Dieser Mainloop-Block wird nur einmal abgearbeitet!!!")
print("Ab Jetzt läuft ein Thread 'mainloop' im Hintergrund weiter")

root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@wuf: der Kommentar ist ein bißchen irreführend. Es gibt keinen Thread 'mainloop', sondern der Main-Loop wurstelt im Vordergrund herum und ruft je nach Event im Vordergrund verschiedene Methoden auf.

@jake-the-snake: wenn eine Methode aus dem Mainloop heraus aufgerufen wurde, dann springt nach Ende der Funktion das Programm wieder in den Mainloop, also in die Funktion, die Du in der letzten Zeile aufgerufen hast.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Sirius3 hat geschrieben:@wuf: der Kommentar ist ein bißchen irreführend.
Du hast recht der ganze Thread hier ist es ein bisschen. :) Habe noch weitere Versuche angestellt. @jake-the-snacke: Habe ein weiteres Skript für Forschungszwecke erstellt. Als Zeitschinderprogramm habe ich die Funktion 'do_maraton_job()' als Zähler integriert. Neu dabei ist auch die tk-Methode 'root.update_idletasks()'.In der Messagebox Funktion 'show_messagebox()'ist eine Eigenbau- und Tk-Variante der Messagebox enthalten. Die Tk-Variante ist aus dokumentiert. Die Eigenbau-Variante wird angezeigt während dem das Zeitschinderprogramm am laufen ist. Wenn man aber die Eigenbau-Variante aus- und die Tk-Variante eindokumentiert wird bei einem Neustart des Skripts das Hauptfenster abgedeckt durch die Tk-Messagebox angezeigt aber das Zeitschinderprogramm fängt erst an zu laufen sobald die Tk-Messsagebox geschlossen wird. In beiden Fällen wird erst nach Ablauf des Zeitschinderprogramm die Methode 'root.mainloop()' ausgeführt.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tkinter as tk
from tkinter import messagebox

APP_TITLE = "Tk Research"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 200

def show_messagebox():
    # Custom-Messagebox
    message_box = tk.Toplevel(root)
    message_box.title("Messagebox")
    tk.Label(message_box, text="Programm aktiv - Bitte warten...",
        padx=20, pady=20).pack(expand=True)
    message_box.transient(root)
    message_box.grab_set()
    return message_box
    # Tk-Messagebox
    #messagebox.askyesno("System-Meldung", "Programm aktiv - Bitte warten...")
    print ("Funktion short_message ausgeführt!")

########################
# Applications - Block #
########################
def do_maraton_job(delay_count):
    while delay_count > 0:
        print(delay_count)
        delay_count -=1
    return 'yes'
 

####################
# Mainloop - Block #
####################
root = tk.Tk()
root.title(APP_TITLE)
root.resizable(False, False)
root.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))

codeprocess = "no"
delay_count = 100000

my_messagebox = show_messagebox()
root.update_idletasks()

codeprocess = do_maraton_job(delay_count)

if codeprocess == "yes":
    my_messagebox.destroy()
    print("if-Block mainloop erreicht")

root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
Antworten