Splash Screen Problem

Fragen zu Tkinter.
Antworten
JulesW
User
Beiträge: 6
Registriert: Montag 19. August 2013, 22:59

Hallo,
ich habe ein äusserst banales Problem mit der Umsetzung eines Ladebildschirms in Python 3.
Und zwar bekomme ich es nicht hin, dass nach dem Anzeigen des Splash Screens die eigentliche Applikation aufgerufen wird. Das die Applikation vorher, gleichzeitig oder nachher, ohne destroy des Splash Screens von statten geht ist kein Problem. Aber ich finde einfach keine passende Lösung für die richtige Umsetzung.
Ich bin in der GUI Programmierung allerdings auch neu (so ziemlich alles andere in Python ist mir ein Begriff :D)

Ich hoffe es hat jemand einen Hinweis! Es kann ja nicht so kompliziert sein, aber weder Google noch Bekannte konnten mich auf die richtige Fährte setzen. hier der Code:

Code: Alles auswählen

#!/usr/bin/env python
### IMPORT ###
import tkinter as tk

### ROOT ###
root = tk.Tk()

### APPLICATION ###
class application(tk.Toplevel):
    def __init__(self, master = root):
        tk.Toplevel.__init__(self, master)
        self.grid()
        self.applicationWidgets()
        
    def applicationWidgets(self):
        self.quitButton = tk.Button(self, text='Quit', command=self.quit)
        self.quitButton.grid()
        
### SPLASH SCREEN ###
class splash_screen(tk.Toplevel):
    def __init__(self, root):
        self.root = root
        self.root.overrideredirect(True)
        ws = self.root.winfo_screenwidth()
        hs = self.root.winfo_screenheight()
        w = 600
        h = 300
        x = (ws/2) - (w/2) 
        y = (hs/2) - (h/2)
        self.root.geometry('%dx%d+%d+%d' % (w, h, x, y))
        self.label = tk.Label(self.root)
        self.label._image = tk.PhotoImage(file='cgtt.gif')
        self.label.configure(image = self.label._image)
        self.label.pack()
        self.root.after(5000, self.root.destroy)
               
### START APPLICATION ###
if __name__ == '__main__':
    splash_screen(root)
    root.mainloop()
Diese Version des Codes zeigt den Splash Screen an und schließt ihn auch, aber offensichtlich fehlt der application()-Aufruf, wo ich einfach nicht weiß wann, wie und wo er eingesetzt werden muss.

MfG JulesW
BlackJack

@JulesW: ”Nach” heisst auf Englisch „after”. Der Methode musst Du etwas aufrufbares übergeben was a) den Splash-Screen schliesst/zerstört (und nicht wie jetzt das Hauptfenster und damit die Hauptschleife beendet) und b) das Anwendungsfenster anzeigt.

Der Style Guide for Python Code scheint Dir (noch) kein Begriff zu sein. ;-)

Und die Kommentare sind ausgesucht sinnfrei. Kommentare sollten dem Leser einen Mehrwert zum Quelltext liefern. Informationen nicht ganz offensichtlich schon vom Quelltext vermittelt werden.
JulesW
User
Beiträge: 6
Registriert: Montag 19. August 2013, 22:59

ja danke :D da hätte man auch drauf kommen können. habe jetzt eine switch Funktion geschrieben.

Code: Alles auswählen

self.after(5000, self.switch())

Code: Alles auswählen

def switch(self):
     application()
     self.destroy()
jetzt habe ich nur noch das Problem, dass er das root tk.TK() anzeigt aber das bekommt man bestimmt ähnlich einfach gelöst ;)

Danke!
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Du führst ``self.switch`` aus und übergibst nicht die Methode an ``after``.
Das Leben ist wie ein Tennisball.
JulesW
User
Beiträge: 6
Registriert: Montag 19. August 2013, 22:59

@EyDu:
Wo soll der Unterschied/Vorteil sein?
BlackJack

@JulesW: Der Unterschied ist das Du `switch()` *sofort* aufrufst und das `after()` keine Wirkung hat, weil dem statt der Methode nun der Wert `None` übergeben wird, was die Sache ziemlich sinnfrei macht. Und der Vorteil wäre, dass es dann auch tatsächlich so funktioniert wie es sollte, also erst nach 5 Sekunden aufgerufen wird, und das `after()` tatsächlich Sinn macht.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi JulesW

Hier etwas zum herumexperimentieren:

Code: Alles auswählen

#!/usr/bin/env python

try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk

class MySplash(tk.Toplevel):

    def __init__(self, main_win, splash_image, callback=None):
        
        self.main_win = main_win
        self.splash_image = splash_image
        self.callback = callback
        
        self.splash_image = tk.PhotoImage(file=splash_image)
        self.width = self.splash_image.width()
        self.height = self.splash_image.height()
        
        tk.Toplevel.__init__(self)
        self.overrideredirect(True)
        self.xpos = (self.main_win.winfo_screenwidth() - self.width) /2
        self.ypos = (self.main_win.winfo_screenheight() - self.height) /2
        self.geometry('{0}x{1}+{2}+{3}'.format(
            self.width, self.height, int(self.xpos), int(self.ypos)))
        
        self.splash_label = tk.Label(self, image=self.splash_image)
        self.splash_label.pack()
        
        self.after(5000, self.close)

    def close(self):
        self.destroy()
        if self.callback: self.callback()
        
class MyApp(tk.Tk):
    
    def __init__(self):    
        tk.Tk.__init__(self)
        self.title('My Application')
        self.protocol("WM_DELETE_WINDOW", self.close)
        self.geometry('300x300+20+20')
        self.withdraw()
        
    def build_app(self):
        self.quitButton = tk.Button(self, text='Quit', command=self.close)
        self.quitButton.pack(expand=True)
        
        self.deiconify()
        
    def run(self):
        MySplash(self, 'splash_image.gif', self.build_app)
        
        self.mainloop()

    def close(self):
        print('Do something before Shutdown')
        self.destroy()
        
if __name__ == '__main__':        
    app = MyApp().run()
Gruß wuf :wink:
Take it easy Mates!
JulesW
User
Beiträge: 6
Registriert: Montag 19. August 2013, 22:59

@wuf:
Vielen dank ;) hat sehr viel aufschluss gegeben, endlich funktioniert alles mit dem splash screen ;)

@all:
Ich habe allerdings noch eine kurze Frage zu den Messageboxen. Wollte eine askokcancel einbauen, es funktioniert allerdings weder mit messagebox.askokcancel ('blub', 'blub') noch mit tkMessageBox .askokcancel('blub', 'blub')
BlackJack

@JulesW: Was heisst „funktioniert nicht”? Fehlermeldung? Welche? Tracebacks bitte 1:1 kopieren. Hast Du das Modul auch importiert?
JulesW
User
Beiträge: 6
Registriert: Montag 19. August 2013, 22:59

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/lib/python3.3/tkinter/__init__.py", line 1478, in __call__
    return self.func(*args)
  File "/home/jules/workspace/cgtt/cgtt.py", line 83, in close
    tkMessageBox.askokcancel('Close', 'Close')
NameError: global name 'tkMessageBox' is not defined
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Die Fehlermeldung ist doch eigentlich deutlich: der Name ``tkMessageBox`` is unbekannt. Du hast also offensichtlich das Modul nicht (richtig) importiert.
Das Leben ist wie ein Tennisball.
BlackJack

@JulesW: Wie kommst Du eigentlich auf `tkMessageBox`? In der Dokumentation steht das nicht. Falls doch solltest Du schauen ob die Dokumentation zu Deiner Python-Version passt. ;-)
JulesW
User
Beiträge: 6
Registriert: Montag 19. August 2013, 22:59

BlackJack hat geschrieben: Wie kommst Du eigentlich auf `tkMessageBox`? In der Dokumentation steht das nicht. Falls doch solltest Du schauen ob die Dokumentation zu Deiner Python-Version passt. ;-)
Ich habe beide Versionen versucht. tkMessageBox und einfach nur messagebox.

Als import muss ich die beiden doch auch angeben oder?! mein import sieht wie folgt aus:

Code: Alles auswählen

try:
    import Tkinter as tk
    import messagebox
except ImportError:
    import tkinter as tk
    import messagebox
mit folgender Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/jules/workspace/cgtt/cgtt.py", line 5, in <module>
    import Tkinter as tk
ImportError: No module named 'Tkinter'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jules/workspace/cgtt/cgtt.py", line 9, in <module>
    import messagebox
ImportError: No module named 'messagebox'
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

http://docs.python.org/3/library/tkinter.html hat geschrieben:tkinter.messagebox
Demnach muss der Import

Code: Alles auswählen

import tkinter.messagebox
#oder
from tkinter import messagebox
heissen.
Antworten