Tkinter wie zweites frame aufrufen

Fragen zu Tkinter.
Antworten
szhwdr
User
Beiträge: 11
Registriert: Samstag 22. März 2008, 12:40

Samstag 14. Juni 2008, 15:44

Hallo erstmals

Ich verzweifle an einem einfachen Problem stell ich mir vor:
Ich habe ein Programm geschrieben das via Menu andere Fenster öffnet und funktionen ausführt. Das funtioniert auch. Aber nur einmal, pro Programmstart. Dies weil ich den Fehler mache und das zweite Fenster via import aufrufe. und so ist es logisch das ich es nur einmal aufrufen kann, weil import nur einmal aufgerufen wird. Aber wie mache ich den Aufruf richtig? Wie kann ich eine Klasse in einem anderen File aufrufen ohne die Klasse vorerst zu importieren. Wenn ich sie zuobertst im Hauptframe importiere wird ja das zweite File sofort aufgerufen, dabei will ich es ja erst via Menueintrag aufrufen. Zudem wenn ich das zweite File schliesse wird auch das hauptfenster geschlossen.

erstes file:

Code: Alles auswählen

from Tkinter import *

class Hauptframe():
    root = Tk()
    menueFrame = Frame(root)
    menubar = Menu(menueFrame)
    root.config(menu=menubar)
    filemenue = Menu (menubar, tearoff=0)
    extramenu = Menu(menubar, tearoff=0)
    filemenue.add_command(label='Beenden', underline=0, command=root.quit)
    menubar.add_cascade(label="File", underline='0',menu=filemenue)
    menubar.add_cascade(label="Extras",underline='0',menu=extramenu)
    root.mainloop()

zweites file:

from Tkinter import *

class ZweitesFrame():
    app = Tk()
    neuLB = Label(app, text='test')
    neuLB.grid()
    app.mainloop()

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

Samstag 14. Juni 2008, 18:34

Schau doch noch mal ein wenig ins Tutorial und dann in ein vernünftiges OOP-Tutorial. Ganz offensichtlich hast die das Prinzip von Klassen noch überhaupt nicht begriffen. Und wenn du GUIs erzeugen willst, dann kommst du da nicht drum herum.

Was ich ganz seltsam finde ist, dass das Beispiel überhaupt funktionieren sollte. Immerhin wird zwei mal die mainloop gestartet, was aber nicht gehen dürfte.
szhwdr
User
Beiträge: 11
Registriert: Samstag 22. März 2008, 12:40

Sonntag 15. Juni 2008, 06:58

Ich war der Meinung das ich nach etlichem suchen, lesin im Internet und auch von Büchern oop soweit verstehen soll, was auch gut klappt bei anderen classen die kein zweites frame benötigen, sondern nur funktionen ausführen, oder so. Aber mir ist nicht klar wie ich ein zweites frame mehrfach aufrufen kann. Ich habe den Beispielcode nun fertig ergänzt, war noch nicht richtig, nun ist er so aber läuft nicht. Um eine Instanz der Klasse anzulegen muss der Name bekannt sein, dazu muss ich doch die Klasse importieren,oder? Aber durch den Befehl import wird das Frame bereits ausgeführt. Was mus ich ändern am evtl. 2 Frame damit dies funktioniert. Ich hoffe ich habe mich einigermassen verständlich ausgedrückt.
gruss
Roel

Code: Alles auswählen

from Tkinter import *
from zweitesFrame import ZweitesFrame

class Hauptframe():
    def __init__(self, master):
        menueFrame = Frame(master)
        menubar = Menu(menueFrame)
        root.config(menu=menubar)
        filemenue = Menu (menubar, tearoff=0)
        extramenu = Menu(menubar, tearoff=0)
        filemenue.add_command(label='Beenden', underline=0, command=root.quit)
        menubar.add_cascade(label="File", underline='0',menu=filemenue)
        menubar.add_cascade(label="Extras",underline='0',menu=extramenu)
        extramenu.add_command(label="2 Frame aufrufen", command=self.aufrufen)
      
    
    def aufrufen(self):
       
        app1 = ZweitesFrame().app
        
 
root = Tk()       
frame1 = Hauptframe(root)
root.mainloop()
szhwdr
User
Beiträge: 11
Registriert: Samstag 22. März 2008, 12:40

Sonntag 15. Juni 2008, 11:20

Ich habe nun eine gangbare Lösung gefunden. Aber ich habe schon öfters im Forum gelesen man soll keine zwei mainloops haben. Aber wie soll ich es anders machen?
gruss
Roel
1. file:

Code: Alles auswählen

from Tkinter import *
from zweitesFrame import *

class Hauptframe():
    def __init__(self, master):
        menueFrame = Frame(master)
        menubar = Menu(menueFrame)
        root.config(menu=menubar)
        filemenue = Menu (menubar, tearoff=0)
        extramenu = Menu(menubar, tearoff=0)
        filemenue.add_command(label='Beenden', underline=0, command=root.quit)
        menubar.add_cascade(label="File", underline='0',menu=filemenue)
        menubar.add_cascade(label="Extras",underline='0',menu=extramenu)
        extramenu.add_command(label="2 Frame aufrufen", command=self.aufrufen)
      
    
    def aufrufen(self):
        app = Tk()
        app1 = ZweitesFrame(app)
        app.mainloop()
        
 
root = Tk()       
frame1 = Hauptframe(root)
root.mainloop()
2.file:

Code: Alles auswählen

from Tkinter import *

class ZweitesFrame():
    def __init__(self,gugus):
        newFrame = Frame(gugus).grid()
        neuLB = Label(gugus, text='test')
        neuLB.grid()
BlackJack

Sonntag 15. Juni 2008, 12:24

Das ist keine Lösung weil in einem Programm nur ein `Tk`-Exemplar existieren darf. Mehrere `Tk`-Exemplare zur gleichen Zeit können zu den lustigsten Effekten und Abstürzen führen. Zusätzliche Fenster müssen vom Typ `Toplevel` sein.

Damit ist die Benennung Deiner Klassen irreführend, da es sich gar nicht um `Frame`\s handelt. Ein `Frame` ist ein Widget, das man in einem `Toplevel`- oder `Tk`-Exemplar platzieren kann.

Widgets sollten sich nicht selbst platzieren, das macht keines der Standardwidgets und was zum Henker ist `gugus` für eine Name!?

Last but not least: Sternchen-Importe sind Böse™.
Benutzeravatar
wuf
User
Beiträge: 1497
Registriert: Sonntag 8. Juni 2003, 09:50

Sonntag 15. Juni 2008, 19:31

Hallo szhwdr

Wie schon BlackJack erwähnt hat sind bei Tkinter Frames und Fenster nicht das gleiche. Hier habe ich einmal ein kleines Testprogramm erstellt das Instanzen einer eigenen Frame-Klasse die von der Tkinter-Frame-Klasse erbt, erzeugt. Die Frames können nur in einem Haupfenster angelegt werden.

Code: Alles auswählen

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

"""
Funktion: Erzeugt eine eigene Frame-Klasse
          durch erben aus der Tkinter-Frame-Klasse
          Dieses Beispiel wurde auf Linux
          SuSE 10.0 getestet.
"""
import sys
import Tkinter as tk

class MyFrame(tk.Frame):
    """Eigene Frame-Klasse"""

    #~~ Konstruktor für MyFrame-Klasse
    def __init__(self,parent,
            xpos   = 0,
            ypos   = 0,
            width  = 100,
            height = 100,
            border = 1,
            relief = 'raised',
            highlightthicknes = 1,
            highlightbackground = 'gray50'
            ):

        #~~ Initialisierung der geerbten Tk-Frame-Klasse
        tk.Frame.__init__(self,parent,
            border = border,
            relief = relief,
            highlightthicknes = highlightthicknes,
            highlightbackground = highlightbackground
            )
        self.place(x=xpos,y=ypos,width=width,height=height)


#~~ Lade den Dateiname dieses Skriptes
script_name = sys.argv[0]

#~~ Konstanten für die Abmessungen des Hauptfensters
MAIN_WIN_XPOS   = 0
MAIN_WIN_YPOS   = 0
MAIN_WIN_WIDTH  = 320
MAIN_WIN_HEIGHT = 320

#--- Erstelle ein Tk-Hauptfenster ----
root = tk.Tk()
root.geometry("%dx%d+%d+%d" % (
    MAIN_WIN_WIDTH,
    MAIN_WIN_HEIGHT,
    MAIN_WIN_XPOS,
    MAIN_WIN_YPOS)
    )
root['bg'] = 'steelblue2'
script_name = 'Frame-Instanzen'
root.title(script_name)

my_frame_object_list = []

xpos   = 10
ypos   = 10
width  = 150
height = 150
border = 2

number_of_frames = 20

#~~ Erzeuge 20 Frames-Instanzen
for frame_nr in xrange(number_of_frames):
    #~~ Erzeuge eine Instanz der eigenen Frame-Klasse
    my_frame_object = MyFrame(root,xpos,ypos,width,height,border)

    #~~ Speichere die Instanz-Referenz (Objekt-Referenz)
    #   in einer Liste
    my_frame_object_list.append(my_frame_object)

    xpos += 10
    ypos += 10

#~~ Lade die Objekt-Referenz für das fünfte Frame
my_frame_object = my_frame_object_list[4]

#~~ Ändere die Farb-Eigenschaft des Frames
my_frame_object.configure(background='yellow')

#~~ Hebe das fünfte Frame über alle anderen
my_frame_object.tkraise()

root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1497
Registriert: Sonntag 8. Juni 2003, 09:50

Sonntag 15. Juni 2008, 19:42

Hallo szhwdr

Hier ist die Fortsetzung für die Erzeugung von Fenstern abgeleite von der Tkinter-Toplevel-Klasse. Es wird immer ein Hauptfenster benötigt um weiter Kinderfenster (Toplevel-Fenster)-Instanzen zu erzeugen. Die Kinder sind echte Fenster-Instanzen und werden auf dem Desktop und nicht im Haupfenster abgelegt. Sind also wie jedes ander verfügbare Fenster individuell manipulierbar.

Code: Alles auswählen

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

"""
Funktion: Erzeugt eine eigene Toplevel-Fenster-Klasse
          durch erben von der Tkinter-Toplevel-Klasse
          Dieses Beispiel wurde getestet auf:
          Linux SuSE 10.0 getestet.
"""
import sys
import Tkinter as tk

class MyWindow(tk.Toplevel):
    """Eigene Toplevel-Fenster-Klasse"""

    #~~ Konstruktor für MyWindow-Klasse
    def __init__(self,parent,
            xpos   = 0,
            ypos   = 0,
            width  = 100,
            height = 100,
            ):

        #~~ Initialisierung der geerbten Tk-Toplevel-Klasse
        tk.Toplevel.__init__(self
            )

        self.geometry("%dx%d+%d+%d" % (
            width,
            height,
            xpos,
            ypos)
            )


def create_toplevel_windows():
    """Erzeugt Toplevel-Fenster-Instanzen der MyWindow-Klasse"""

    global my_window_object_list

    xpos   = 30
    ypos   = 30
    width  = 200
    height = 200

    number_of_windows = 15

    #~~ Erzeuge 15 noch nicht sichtbare Toplevel-Fenster
    for window_nr in xrange(number_of_windows):
        #~~ Erzeuge eine Instanz der eigenen Window-Klasse
        my_window_object = MyWindow(root,xpos,ypos,width,height)
        my_window_object.title('Fenster-'+str(window_nr+1))
        my_window_object.withdraw()

        #~~ Speichere die Instanz-Referenz (Objekt-Referenz)
        #   in einer Liste
        my_window_object_list.append(my_window_object)

        xpos += 10
        ypos += 10

        #~~ Ermöglicht dem Window-Manager eigene
        #   Prozessabläufe auszuführen
        my_window_object.update_idletasks()

    #~~ Mache alle Fenster sichtbar
    for win_obj in my_window_object_list:
        win_obj.deiconify()

    #~~ Selektiere das Toplevel-Fenster 5 (Index = 5-1 =4)
    my_window_object = my_window_object_list[4]
    #~~ Ändere die Fenster-Farbe auf gelb
    my_window_object.configure(background='yellow')
    #~~ Setze den Fokus auf das Fenster 5
    my_window_object.focus_set()
    #~~ Hebe das Fenster-5 auf die oberste Ebene
    my_window_object.lift()

#~~ Lade den Dateiname dieses Skriptes
script_name = sys.argv[0]

#~~ Konstanten für die Abmessungen des Hauptfensters
MAIN_WIN_XPOS   = 0
MAIN_WIN_YPOS   = 0
MAIN_WIN_WIDTH  = 320
MAIN_WIN_HEIGHT = 320

#--- Erstelle ein Tk-Hauptfenster ----
root = tk.Tk()
root.geometry("%dx%d+%d+%d" % (
    MAIN_WIN_WIDTH,
    MAIN_WIN_HEIGHT,
    MAIN_WIN_XPOS,
    MAIN_WIN_YPOS)
    )
root['bg'] = 'steelblue2'
script_name = 'Toplevel-Instanzen'
root.title(script_name)

root.update_idletasks()

#~~Liste für die Fenster-Objekte-Referenzen
my_window_object_list = []

#~~ Zeitkonstante in [ms] für die Verzögerung
DELAY_TIME = 50

#~~ Erzeuge die Toplevel-Fenster leicht verzögert
#   damit die Methode root.mainlopp() vorher auf-
#   gerufen wird und somit das Hauptfenster vor
#   den Toplevel-Fenster-Instanzen generiert werden
root.after(DELAY_TIME,create_toplevel_windows)

root.mainloop()
[quote]

Gruss wuf  :wink: [/quote]
Take it easy Mates!
szhwdr
User
Beiträge: 11
Registriert: Samstag 22. März 2008, 12:40

Sonntag 15. Juni 2008, 21:55

Vielen Dank fuer eure Antwort. Werde das mal so ausprobieren.
gruss
Roel
Antworten