Seite 1 von 2

grid und pack mischen

Verfasst: Dienstag 28. Oktober 2014, 23:59
von sedi
Hallo zusammen,

ich habe nun eine etwas aufwändigere GUI zu bauen und hatte dabei Schwierigkeiten mit den Geometriemanagern.

Wann und wie lassen sich die beiden mischen? Ich habe im Netz natürlich darüber gelesen und überwiegend war die Rede sie nicht zu mischen - manche sagen aber, dass dies problemlos möglich ist. Meine ersten Gehversuche waren erst mal erfolgreich (siehe Beispiel unten). Das umfangreichere Beispiel versagte dann. Wann also lassen sich die Manager mischen? Wisst ihr dazu irgendeine Quelle, die das genau beschreibt?

Das nachfolgende, einfache Beispiel funktioniert

Code: Alles auswählen

import logging
Logger = logging.getLogger("root")


class Page(tk.Frame):
    def __init__(self, master, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)
        
        self.headline = ""
        
        self.toppackframe = tk.Frame(self)
        self.toppackframe.pack(side=tk.TOP)
        
        self.contentgrid = tk.Frame(self)
        self.pack()
        
        self.bottompackframe = tk.Frame(self)
        self.bottompackframe.pack(side=tk.BOTTOM)
        Logger.debug("init done")
    
    def setup_header(self, headline=""):
        Logger.debug("setup_header startet [headline=%s]", headline)
        
        if headline:
            self.headline = headline
            tk.Label(self.toppackframe,
                     text=self.headline).pack(side=tk.TOP)
    
        Logger.debug("setup_header fertig")
        
    def setup_bottom(self):
        Logger.debug("setup_bottom startet")
        
        self.back = tk.Button(self.bottompackframe,
                              text="<< Back")
        self.cancel = tk.Button(self.bottompackframe,
                              text="Cancel")
        self.forward = tk.Button(self.bottompackframe,
                              text="Next >>")
        self.back.pack(side=tk.RIGHT)
        self.cancel.pack(side=tk.RIGHT)
        self.forward.pack(side=tk.RIGHT)
        
        Logger.debug("setup_header fertig")

    def setup(self, headline=""):
        Logger.debug("setup startet [headline=%s]", headline)
        
        self.setup_header(headline)
        self.setup_bottom()
        
        Logger.debug("setup_header fetig")
        

class MyPage(Page):
    def __init__(self, master, **kwargs):
        Page.__init__(self, master, **kwargs)
    
    def setup_content(self, sectionheader=""):
        Logger.debug("setup_content [sectionheader=%s]",
                     sectionheader)
        if sectionheader:
            Logger.debug("fuege Headerlabel ein")
            lbl = tk.Label(self.contentgrid, text=sectionheader)
            lbl.grid(column=0, row=0, columnspan=10)
        
        zeilen = range(10)
        spalten = range(10)
        for zeile in zeilen:
            for spalte in spalten:
                zelle = "Zelle (%s,%s)" % (spalte, zeile)
                l = tk.Label(self.contentgrid, text=zelle)
                l.grid(column=spalte, row=zeile+1)
                Logger.debug("%s eingefuegt", zelle)

        Logger.debug("setup_content fertig")
    
    def setup(self, headline="", sectionheader=""):
        Logger.debug("setup startet [headline=%s, sectionheader=%s]",
                     headline, sectionheader)
        self.setup_header(headline)
        self.setup_content(sectionheader)
        self.setup_bottom()
        Logger.debug("setup fertig")



def example():
    Logger.debug(" ######### START ##############")
    app=tk.Tk()

    page = MyPage(app)
    page.setup("Titel", "Sektion")
    page.pack()

    app.mainloop()


if __name__ == "__main__":
    logging.basicConfig(format="[%(lineno)4d:%(name)s:%(funcName)s]" + \
    " %(message)s", level=10)
    example()

Re: grid und pack mischen

Verfasst: Mittwoch 29. Oktober 2014, 00:05
von BlackJack
@sedi: Man sollte die gar nicht mischen. Wer empfiehlt denn so etwas? Das Ergebnis ist bestenfalls schwer vorhersehbar und im schlechtesten Fall hängt sich das Programm auf weil sich die beiden Manager nicht einig werden können wie das Ergebnis aussehen soll. Aus dem gleichen Grund sollte man bei `pack()` immer nur eine Richtung verwenden.

Edit: Ergänzend dazu aus einem Bugtracker-Beitrag: „In TCL/Tk 8.6b2 and later there is a change: more strict approach to geometry
managers. From now on "mixing" pack and grid is considered an error.”

Das heisst man wird das in zukünftigen Tk-Versionen direkt als Fehler um die Ohren gehauen bekommen wenn man die beiden mischt.

Re: grid und pack mischen

Verfasst: Sonntag 9. November 2014, 20:47
von Ene Uran
Man kann grid() und place() mischen. Man kann auch zwei verschiedene tk.Frame() benuetzen, eins fuer grid() und eins fuer pack().

Re: grid und pack mischen

Verfasst: Sonntag 9. November 2014, 21:10
von BlackJack
@Ene Uran: Man kann sich auch in den Kopf schiessen. In dem Sinne kann man auch `pack()` und `grid()` mischen. Man sollte das halt bloss niemals tun, und wie gesagt in aktuellen Tk-Versionen *kann* man das *nicht* mehr tun. Es führt zu einer Fehlermeldung.

Re: grid und pack mischen

Verfasst: Montag 10. November 2014, 11:09
von sedi
Hallo,

man kann die beiden schon "mischen", wobei mischen dabei mit Vorsicht zu genießen ist:

In ein und demselben Frame darf man keinesfalls mischen, dh. Objekte verwenden die auf

Code: Alles auswählen

pack()
und

Code: Alles auswählen

grid()
zurückgreifen.

Allerdings wurde ich durch eine Seite im Internet (leider weiß ich die Adresse nicht mehr) darauf aufmerksam, dass man Subframes durch verschiedenen Geometriemanager darstellen lassen kann.

Allerdings gab es dabei auch noch Schwierigkeiten - meine Lösung war: Wollte ich zwei Bereiche mit verschiedenene Geometriemanagern
berechnen lassen, dann habe ich SubSubframes verwendet - das läuft problemlos:

Code: Alles auswählen


+-------------------------------+
| Outer Frame (pack)            |
|   +-----------------------+   |
|   | Subframe              |   |
|   |   +---------------+   |   |
|   |   | SubSub (grid) |   |   |
|   |   |               |   |   |
|   |   +---------------+   |   |
|   +-----------------------+   |
|   +-----------------------+   |
|   | Subframe              |   |
|   |   +---------------+   |   |
|   |   | SubSub (pack) |   |   |
|   |   |               |   |   |
|   |   +---------------+   |   |
|   +-----------------------+   |
+-------------------------------+

Re: grid und pack mischen

Verfasst: Montag 10. November 2014, 21:09
von bb1898
Ganz klar ist mir das noch nicht:
- die beiden Subframes werden mit pack() in den Outer Frame eingepasst, richtig?
- in den oberen Subframe wird ein SubSub mit grid() hineingepackt, in den unteren ein anderer SubSub mit pack(), noch richtig?
- und die Steuerelemente in den SubSub-Frames? Oben mit grid(), unten mit pack()?
Es wäre schon ein bisschen hässlich, wenn man so was mit tkinter überhaupt nicht könnte, "die andern können's doch auch!".

Re: grid und pack mischen

Verfasst: Montag 10. November 2014, 21:38
von BlackJack
@bb1898: Man kann in einem Container-Widget nur `pack()` *oder* `grid()` verwenden. Beides kann AFAIK auch kein anderes GUI-Toolkit. Man muss sich immer für *einen* Layoutmanager entscheiden innerhalb eines Containerwidgets. Die Verwirrung bei Tk gegenüber anderen GUI-Toolkits stellt sich ja auch nur weil Layouts in Tk keine eigenständigen Objekte sind sondern die Widgets immer beide Sätze von Methoden haben, egal für welches man sich entscheidet. Bei Qt beispielsweise hat man das Problem erst gar nicht, weil man da ein Layout hinzufügt, und angemeckert wird wenn man noch einen weiteres hinzufügt. Und man fügt Widgets über Methoden auf dem Layout hinzu und nicht über Methoden auf den Widgets selbst.

Re: grid und pack mischen

Verfasst: Dienstag 11. November 2014, 22:08
von bb1898
BlackJack hat geschrieben:Man muss sich immer für *einen* Layoutmanager entscheiden innerhalb eines Containerwidgets. Die Verwirrung bei Tk gegenüber anderen GUI-Toolkits stellt sich ja auch nur weil Layouts in Tk keine eigenständigen Objekte sind sondern die Widgets immer beide Sätze von Methoden haben, egal für welches man sich entscheidet. Bei Qt beispielsweise hat man das Problem erst gar nicht, weil man da ein Layout hinzufügt, und angemeckert wird wenn man noch einen weiteres hinzufügt. Und man fügt Widgets über Methoden auf dem Layout hinzu und nicht über Methoden auf den Widgets selbst.
Stimmt. Aber der Witz ist eben "innerhalb eines Containerwidgets".

Re: grid und pack mischen

Verfasst: Dienstag 18. November 2014, 01:34
von Ene Uran
An jabba the hutt ---
Man kann sich auch in den Kopf schiessen. In dem Sinne kann man auch `pack()` und `grid()` mischen.
Der Vorschlg war: "Man kann place() und grid() mischen."

Re: grid und pack mischen

Verfasst: Dienstag 18. November 2014, 08:48
von BlackJack
@Ene Uran: Das ist ja noch dämlicher als sich in den Kopf zu schiessen. Da können nur verstrahlte drauf kommen… :twisted:

Re: grid und pack mischen

Verfasst: Mittwoch 19. November 2014, 18:38
von Ene Uran

Code: Alles auswählen

import tkinter as tk

root = tk.Tk()

frame1 = tk.Frame(root, bg='brown', width=400, height=200)
frame1.grid()

# you can mix grid() and place()
frame2 = tk.Frame(root, bg='yellow', width=300, height=200)
frame2.place(x=100, y=0)

root.mainloop()

Re: grid und pack mischen

Verfasst: Mittwoch 19. November 2014, 18:54
von BlackJack
Sag ich doch, ist 'ne blöde Idee. Was ja nicht mal am Mischen liegt, sondern das `place()` an sich schon keine gute Idee ist.

Re: grid und pack mischen

Verfasst: Mittwoch 19. November 2014, 19:41
von Ene Uran
Ach du Lieber!

Re: grid und pack mischen

Verfasst: Sonntag 23. November 2014, 18:13
von Michael Schneider
BlackJack hat geschrieben:Sag ich doch, ist 'ne blöde Idee. Was ja nicht mal am Mischen liegt, sondern das `place()` an sich schon keine gute Idee ist.
Was würdest Du denn als vergleichbar einfache Methode vorschlagen, um ein Objekt pixelgenau auf einer grid-Grundstruktur zu platzieren (z.B. um sie dann mit der Maus zu verschieben)?
Wenn die nicht durch place from Grid-Manager getrennt wird, kann man sie in aller Regel nicht so unkompliziert verschieben, ohne dass das Gitter verzerrt wird.

Re: grid und pack mischen

Verfasst: Sonntag 23. November 2014, 19:29
von BlackJack
@Michael Schneider: Gar nichts. Es ein lassen.

Re: grid und pack mischen

Verfasst: Sonntag 23. November 2014, 20:36
von Michael Schneider
Das ist aber keine Lösung für das Problem.

Re: grid und pack mischen

Verfasst: Sonntag 23. November 2014, 21:48
von BlackJack
@Michael Schneider: Welches Problem?

Re: grid und pack mischen

Verfasst: Montag 24. November 2014, 10:59
von Michael Schneider
Jenes, welches ich in meinem letzen Beitrag beschrieb.
Muss ich dafür jetzt ein praktisches Anwendungsbeispiel nennen, weil Du auf dem Standpunkt stehst, dass man Probleme nur betrachten soll, wenn sie sich einem konkret stellen? Das war eine rethorische Frage und soll jetzt nicht vom Thema ablenken.

Es ging um ein Widget, das man mit der Maus über einen Grid-Hintergrund ziehen soll.

Re: grid und pack mischen

Verfasst: Montag 24. November 2014, 12:51
von BlackJack
@Michael Schneider: Probleme die nur theoretisch bestehen sind nun mal keine die man lösen müsste. Natürlich ist `place()` immer die einfachste Lösung für Probleme die so formuliert sind das `place()` die einfachste Lösung ist. So findet man auch ganz viele tolle Anwendungen für ``global`` und `eval()` und ähnliches wovon man die Finger lassen sollte. ;-)

Re: grid und pack mischen

Verfasst: Montag 24. November 2014, 13:15
von Michael Schneider
Lass bitte meine guten Freunde global, eval und alle anderen Als aus dem Spiel. :wink:

Du hast ja nicht ganz unrecht, dass man ein Szenario um einen Problemfall herumdichten kann - obwohl mir gerade nicht einfällt, wofür man global wirklich "braucht", außer um mal eben schnell eine akute Aktion durchzuführen.
Aber das bedeutet noch nicht, dass man etwas ganz sein lässt, nur weil die beste Lösung für ein Problem ein Konzept verwendet, das man persönlich ablehnt. Denn offiziell habe ich auch noch nicht gelesen, dass man place und einen anderen Manager nicht zusammen verwenden sollte oder in Zukunft nicht mehr darf.