objekte dynamisch verteilen

Fragen zu Tkinter.
Antworten
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Hi,

gibt es schon eine Möglichkeit in einem Frame die maximale Breite anzugeben, welche bei zB. pack(side=LEFT) eingehalten wird und das objekt in eine weitere Zeile gepackt wird.

Oder muss ich mir dafür selbst was schreiben, so dass ich die größen aller Elemente zusammenrechne und bei einem fall der übertretung es dan eine zeile umpacke.

mir ist eigentlich egal ob pack() grid() oder place(), würde aber lieber nur pack arbeiten, also

statt Frame
---------------------------------------
| "pack" "pack" "pack" "dies passt nicht mehr", "pack" |
---------------------------------------

Frame1
---------------------------------------
| "pack" "pack" "pack" |
---------------------------------------
Zusätzlicher Frame2
---------------------------------------
| "dies passt nicht mehr", "pack" |
---------------------------------------
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ich nehme, daraus resultierend das keine Antwort bisher kam an, dass es so etwas in der Art noch nie geplant, nie gewollt und schon gar nicht erst gebaut wurde. :|

Edit: Yuhuu, man muss nur etwas provozieren/herausfordern und schon läufts. :twisted:
Zuletzt geändert von Xynon1 am Dienstag 12. Oktober 2010, 21:33, insgesamt 1-mal geändert.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Xynon1

Ich verstehe evt. nicht genau was du meinst. Habe hier einmal etwas ausprobiert:

Code: Alles auswählen

import Tkinter as tk

app_win = tk.Tk()
app_win.geometry('400x300')

frame = tk.Frame(app_win, bg='yellow', width=100, height=50)
frame.pack(side='left')
frame.propagate(False)

frame = tk.Frame(app_win, bg='green', width=100)
frame.pack(side='left', fill='y')
frame.propagate(False)

frame = tk.Frame(app_win, bg='red', width=100, height=50)
frame.pack(side='left', anchor='nw')
frame.propagate(False)

app_win.mainloop()
Gruß wuf :wink:
Take it easy Mates!
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Zum Beispiel möchte ich Labels ungefähr so auf einen Frame packen (ich geh mal von dienem Beispiel aus)

Code: Alles auswählen

import Tkinter as tk

app_win = tk.Tk()
app_win.geometry('400x300')

color = ["yellow", "green", "red"]

frame = tk.Frame(app_win, borderwidth=3, relief="groove", width=100, height=50)
frame.pack()
#frame.propagate(False)

for i in xrange(50):
    lb = tk.Label(frame, bg=color[i%3])
    lb.pack(side="left")

app_win.mainloop()
Allerdings ist das jetzt natürlich größer als eingestellt, dafür nutzt du ja die methode .propagate(False), um eine feste Größe beizubehalten.
So, aber mit der Methode fehlen gut 30 Label und da ist mein Problem.
Diese sollten nun zB. in einem neuen Frame darunter angezeigt werden.

Hier mal manuell eingestellt:

Code: Alles auswählen

import Tkinter as tk

app_win = tk.Tk()
app_win.geometry('400x300')

color = ["yellow", "green", "red"]

for j in xrange(5):
    
    frame = tk.Frame(app_win, borderwidth=3, relief="groove", width=100, height=50)
    frame.pack()
    frame.propagate(False)

    for i in xrange(10):
        lb = tk.Label(frame, bg=color[i%3])
        lb.pack(side="left")

app_win.mainloop()
Der Haken ist nur ich weiß natürlich nicht wie viele Elemente existieren, also dargestellt werden müssen, dennoch sollten sie OHNE Scrollbar sichtbar sein.
Scrollbar sollte nur bei zu knapper Monitor größe in der Vertikalen angezeigt werden.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Xynon1

So wie ich dich verstehe möchtest du in einem Frame mit fest vorgegebener geometrie eine grössere Menge Labels der Reihe nach von links nach rechts platzieren. Sobald ein Label bei seiner Platzierung den rechten Rand des fest eingestellten Frames überlappt dieses Label automatisch ganz auf der linken Seite des Frames in einer zweiten Reihe platzieren. Verstehe ich das richtig?

Elemente sind bei dir Labels?

Gruß wuf :wink:
Take it easy Mates!
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Nein, die Label waren nur als Veranschaulichung, mit Elementen meine ich jedes Objekt was zu Tkinter Widgets gehört.
Also auch alle abgeleiteten Klassenobjekte, vom einfachen Frame, über Label bis hinzu Menubuttons.
Halt jedes Klassenobjekt, zum selber bauen einer solchen Funktion würde ich einfach die winfos nehmen die ja Tk und BaseWidget von Misc abgeleiten und somit ja bei jedem "Element" verfügbar sind.

Abgesehen von den Labels, hast du es aber voll erfasst.
Meine Frage war halt nur ob es sowas schon gibt.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Xynon1 hat geschrieben:Meine Frage war halt nur ob es sowas schon gibt.
Was du suchst, klingt nach dem, was das Flow-Layout in Java/Swing leistet.
Ich kenne zumindest nichts dergleichen für Tkinter und die geringe Resonanz auf diesen Thread ist vielleicht ein Indiz dafür, dass der Bedarf danach auch eher gering ist. Für Tkinter fallen mir dazu nur "schmutzige" und umständliche Lösungen ein, die man nicht wirklich wollen kann, wie z.B. ein Canvas als Hauptframe zu verwenden, die benötigten Widgets zunächst im unsichtbaren Bereich zu platziert, dann die Maße zu ermitteln und dann zu rechnen, wo es hingehört.

Wenn das für dich so wichtig ist, solltest du dich vielleicht bei den anderen GUI-Toolkits einmal umschauen; falls es das da auch nicht gibt, bliebe noch Jython ...
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo numerix

Danke für deine Ergänzungen. Sorry habe nicht von Anfang an verstanden was Xynon1 genau wollte. Habe hier einmal versucht das Skript etwas in Richtung was sich Xynon1 wünscht zu modifizieren:

Code: Alles auswählen

import Tkinter as tk

MAIN_FRAME_WIDTH = 100
MAIN_FRAME_HEIGHT = 100

app_win = tk.Tk()
app_win.geometry('400x300')

color = ["yellow", "green", "red"]

frame = tk.Frame(app_win, borderwidth=3, relief="groove",
    width=MAIN_FRAME_WIDTH, height=MAIN_FRAME_HEIGHT)
frame.pack()
frame.propagate(False)

flex_frame = tk.Frame(frame)
flex_frame.pack(side='top', anchor='nw')

for i in xrange(50):
    lb = tk.Label(flex_frame, bg=color[i%3])
    lb.pack(side="left", anchor='nw')
    flex_frame.update_idletasks()

    flex_frame_width = flex_frame.winfo_reqwidth()
    if flex_frame_width > MAIN_FRAME_WIDTH:
        lb.destroy()
        flex_frame = tk.Frame(frame)
        flex_frame.pack(side='top', anchor='nw')
        lb = tk.Label(flex_frame, bg=color[i%3])
        lb.pack(side="left", anchor='nw')

app_win.mainloop()
I love dirty programming :)

Getestet auf Linux SuSE 11.0

Gruß wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

wuf hat geschrieben:I love dirty programming :)
Naja, verglichen mit dem, was mir zunächst in den Sinn gekommen ist, ist deine Variante von "dirty" doch noch ziemlich weit entfernt ...
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ja, genau sowas, so ausführlich hättest du es gar nicht machen müssen, mir hätten eigentlich die funktionen update_idletasks() und winfo_reqwidth() statt winfo_width() (womit ich es ebend noch vergeblich probiert hatte :cry: )

Aber Danke für deine Mühen. :D
Wäre jetzt nur noch schön wenn man sich das lb.destroy() sparen könnte, aber mir fällt auch nichts besseres ein.

@numerix
Mich erinnert das eher an Container für zB Drag and Drop-Inhalte und zum Teil wollte ich es auch für Bilder nutzen.
und bei solchen Sachen finde ich das doch sehr nützlich.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Antworten