Problem mit Größenanpassung eines Frames

Fragen zu Tkinter.
Antworten
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ich möchte einen Frame an eine bestimmte Stelle auf dem Bildschirm positionieren und ihn dabei dennoch flexibel an eine geänderte Größe des Inhalts anpassen. Ich habe es so probiert:

Code: Alles auswählen

import Tkinter as tk
import tkSimpleDialog

def newtext(ev):
    global lb
    s = tkSimpleDialog.askstring("Eingabefenster","Neuer Text: ")
    if s==None: return
    lb.destroy()
    lb = tk.Label(root,text=s,wraplength=100)
    lb.pack()
    lb.update_idletasks() # nötig?

root = tk.Tk()
lb = tk.Label(root,text="Das ist der Starttext",wraplength=100)
lb.pack()
lb.update_idletasks() # nötig?
root.bind("<Button-1>",newtext)
root.geometry("%dx%d+600+400" %(lb.winfo_width(),lb.winfo_height()))
root.update_idletasks() # nötig?
root.mainloop()
(Das ist ein extra dafür erzeugter Codeschnipsel! Darum auch der Kürze halber ohne Verwendung von Klassen.)

Das Problem scheint in der Verwendung der geometry-Methode zu liegen. Ohne diese klappt es (natürlich), dass das Fenster sich an die Menge des eingegebenen Textes anpasst. Aber dann kann ich ja nicht die Position des Frames festlegen. Ich möchte beides: Größenanpassung und - abhängig von der Größe (diese Berechnung fehlt im Codeschnipsel) - die Position auf
dem Bildschirm manuell festlegen.

Natürlich könnte ich destroy() auf root anwenden und das ganze Fenster neu erzeugen, aber ich verstehe nicht, warum es so wie oben dargestelllt, nicht auch geht.

Wäre toll, wenn jemand einen guten Tipp hat!
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo pütone !!

Code: Alles auswählen

import Tkinter as tk 
import tkSimpleDialog 

def new_text(text): 
    text = tkSimpleDialog.askstring("Eingabefenster","Neuer Text: ") 
    if text==None: 
      return 
    lb.configure(text=text)

root = tk.Tk()
lb = tk.Label(root,text="Das ist der Starttext") 
root.bind("<Button-1>",new_text) 
lb.pack()
root.mainloop()
Ohne global ist es mal besser !

gruß frank
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ohne global ist es mal besser !
Verstehe ich nicht, was daran im Hinblick auf das zu lösende Problem "besser" ist. Klar, sollte man auf "global" nach Möglichkeit verzichten, in der Endform packe ich das ganze auch in eine Klasse, so dass sich das erledigt hat. Aber es löst doch das Problem nicht!

Ich möchte das Fenster größenabhängig positionieren!

Pütone
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo pütone !

Code: Alles auswählen

import Tkinter as tk 
import tkSimpleDialog

def new_text(text): 
    text = tkSimpleDialog.askstring("Eingabefenster","Neuer Text: ") 
    if text==None: 
      return
    weite = 100 
    hoehe = 50
    x = 600
    y = 400
    lb.configure(text=text)
    root.geometry('%dx%d+%d+%d' % (weite, hoehe, x, y))

root = tk.Tk()
lb = tk.Label(root,text="Das ist der Starttext") 
root.bind("<Button-1>",new_text) 
lb.pack()
root.mainloop()

Die Position und Größe mußt du nach deinen Wünschen berechnen.

gruß frank
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Hallo Frank,
Die Position und Größe mußt du nach deinen Wünschen berechnen.
Das ist ja genau das Problem! Mein Wunsch ist es, die Größe abhängig vom gerade enthaltenen Text festzulegen und auf der Grundlage dieser Größe dann die Position (z.B. zentriert auf dem Bildschirm) zu berechnen. All das wäre kein Problem, wenn ich die Größe des Fensterinhaltes ermitteln und den Rest daraus berechnen könnte.
Auch deine zweite Lösung - sorry - löst das Problem eben nicht. Ich brauche in erster Linie die Abmessungen des Labels, dann kann ich den Rest berechnen. Im Prinzip sollte das mit .winfo_width() bzw. .winfo_height() ja auch funktionieren, spätestens nach Aufruf eines .idle_tasks(), tut es aber nicht.

Gibt es wirklich keine Lösung????

Pütone
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo pütone !
Wie wäre es mit len(text) !?

gruß frank
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Hallo Frank,
Wie wäre es mit len(text) !?
Das hilft nicht, ich brauche ja nicht die Zeichenanzahl!

Selbst bei einzeiligem Text (was hier ja nicht vorliegt, darum ja auch die Option wraplength=100) müsste ich daraus zunächst die Breite in Pixeln berechnen, die wiederum vom eingestellten Font abhängig ist.

Diesen Wert sollte lb.winfo_width() ja eigentlich direkt liefern, was es beim allerersten Aufruf (mit dem Starttext) auch tut. Nach Änderung des Textes werden diese Werte aber anscheinend nicht mehr angepasst.

Pütone
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Hallo pütone !

Code: Alles auswählen

import Tkinter as tk 
import tkSimpleDialog

def new_text(text): 
    text = tkSimpleDialog.askstring("Eingabefenster","Neuer Text: ") 
    if text==None: 
      return
    lb.configure(text=text, wraplength=100)
    root.update_idletasks()
    root.geometry('%dx%d+600+400' % (lb.winfo_width(), lb.winfo_height() + 5))
    
root = tk.Tk()
lb = tk.Label(root,text="Das ist der Starttext") 
root.bind("<Button-1>",new_text) 
lb.pack()
root.mainloop()
Und so ?

gruß frank
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Bei mir funktioniert es zumindest so. Du solltest vielleicht die Wraplength deutlich höher einstellen, um den Effekt besser zu sehen. Ansonsten wird das Label ja nicht breiter als 100 Pixel. Schmaler als der Titelbalken wird es auch nicht.
MfG
HWK

Edit: Komisch! Ich habe Wraplength auf 500 eingestellt. Bei Eingabe eines sehr großen Strings ist lb.winfo_width = 501. Nach Eingabe eines kleinen Strings wird bei weiteren Strings lb.winfo_width nicht größer als 115 (Breite des Titelbalkens), obwohl diese Strings z.T. viel breiter sind. Hier einmal Beispielwerte:

Code: Alles auswählen

501 32
270 19
149 19
149 19
30 19
115 19
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

Hallo,

versucht es mal mit

Code: Alles auswählen

lb.configure(text=text, wraplength=None)
jetzt müsste es funktionieren.


Gruss
pyStyler
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Hallo!

Ich bin zwar noch nicht lange dabei und immerhin war ich es auch, der das Ausgangsproblem aufgeworfen hat; es haben sich einige die Mühe gemacht und sich an der Lösung versucht. Aber - auch wenn das jetzt unhöflich ist - einiges verstehe ich nicht und ärgert mich zunehmend:

Warum wird eine angebotene Lösung mit einem anschließenden fragenden Text versehen, ob es funktioniert? Wenn ich jemandem einen Lösungsvorschlag zu machen hätte, würde ich es doch selbst ausprobieren, BEVOR ich es als Lösung anbiete.

Und: Nicht wenige der angebotenen Lösungen hätte man als unbrauchbar erkennen können, wenn man die ursprüngliche Problembeschreibung gelesen hätte.

Auch der letzte Tipp hilft doch nicht: Ich WILL ja die Breite einstellen und nicht ein einzeiliges Label haben! Und im übrigen funktioniert es auch mit wraplength=None nicht - macht doch mal ein paar Versuche!

Das Einzige, was bisher wirklich weiterführt und evtl. Erhellung bringt, sind die Experimente von HWK. Das spricht doch arg dafür, dass hier ein Bug schlummert, denn ich kann das im Prinzip - aber nicht zu 100% - reproduzieren. In einigen Fällen passt sich das Fenster an, dann aber auch wieder nicht. Ein bestimmtes System, etwa einen Zusammenhang zwischen wraplength und Fenstertitelmindestbreite konnte ich aber nicht feststellen.

Pütone
Benutzeravatar
kaytec
User
Beiträge: 608
Registriert: Dienstag 13. Februar 2007, 21:57

Oh - Entschuldigung !

gruß frank
Antworten