Widgets werden nicht angezeigt

Fragen zu Tkinter.
Locke
User
Beiträge: 3
Registriert: Mittwoch 30. Januar 2008, 15:32

Widgets werden nicht angezeigt

Beitragvon Locke » Mittwoch 30. Januar 2008, 15:39

Huhu liebe Boardgemeinde,

ich bin momentan dabei eine Applikation in Python zu schreiben. Es ist zwar nichts besonderes und dient eigentlich nur dazu die Sprache ein wenig kennenzulernen.

Ich habe folgendes Problem:

Code: Alles auswählen

class Fenster(Frame):

    def __init__(self, master=None):
        Frame.__init__(self, master)
        self.master.geometry("500x460")
        self.grid()
        self.Widgets()

    def Widgets(self):
        self.labelpktz=Label(self, text="Bitte Rohpunktzahl eingeben")
        self.labelpktz.place(x=50, y=55)

...

fenster = Fenster()
fenster.master.title("Application")
fenster.mainloop()


Ich habe jetzt mal nur das erste Label hier reingeschrieben die anderen sind vom Prinzip her auch so aufgebaut. Nur was komisch ist, das Label wird mir nicht angezeigt ... nehme ich allerdings das self bei

Code: Alles auswählen

self.labelpktz=Label(self, text="Bitte Rohpunktzahl eingeben")
(das in der Klammer) funktioniert das ganze nur dann habe ich das problem das ich via command-Befehl die Daten nicht auslesen kann welche z.B. in einer Entrybox stehen und somit ist das ganze dann fuer mich unbrauchbar.

Was allerdings merkwuerdig ist, ich habe ein anderes Programm geschrieben in welchem ich das gleiche Grundmuster wie hier verwendet hab und dort funktioniert alles ohne Probleme ...

Koennte mir von euch jemand sagen wo das Problem liegt?

Vielen Dank im voraus,

mfg Locke
BlackJack

Beitragvon BlackJack » Mittwoch 30. Januar 2008, 16:09

Das Hauptfenster sollte explizit ein `Tkinter.Tk`-Objekt sein. Widgets sollten sich nicht selbst in ihrer `__init__()` "layouten". Ein `grid()` ohne Zellenangabe!?

Und man sollte weder die Fenstergrösse vorgeben, noch `place()` verwenden, wenn man GUIs schreiben will, die nicht nur auf dem eigenen Rechner richtig funktionieren.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Mittwoch 30. Januar 2008, 16:50

Das Hauptfenster sollte explizit ein `Tkinter.Tk`-Objekt sein.


Warum?
Den von Locke verwendenten Ansatz findet man z.B. auch bei Shipman
(http://www.nmt.edu/tcc/help/pubs/tkinter.pdf).

Widgets sollten sich nicht selbst in ihrer `__init__()` "layouten".


Warum nicht? Ebenfalls so bei Shipman (s.o.).

Ein `grid()` ohne Zellenangabe!?


Warum nicht? column und row haben doch default-values. grid() ohne Optionen ist zulässig und völlig in Ordnung.

Und man sollte weder die Fenstergrösse vorgeben


Warum nicht?

------------

Das wirklich entscheidende Problem des Programms von Locke scheint mir darin zu liegen, dass er zwei Geometriemanager gemischt einsetzt und das geht in der Regel nicht gut. Also entweder alles mit place() (was man natürlich grundsätzlich eher nicht tun sollte) oder alles mit grid() - das sollte funktionieren.
BlackJack

Beitragvon BlackJack » Mittwoch 30. Januar 2008, 17:28

`Tk` weil soweit ich weiss nicht auf jeder Plattform garantiert ist, dass dieses Objekt automatisch erzeugt wird.

"Layouten" in der `__init__()` von Widgets nimmt einem die Flexibilität das selber zu tun. Keines der bereits vorhandenen Widgets "layoutet" sich selbst.

`grid()` ohne Zellenangabe mag Default-Werte benutzen, aber welche sind das? Und warum `grid()` wenn es nur dieses eine Objekt gibt. Falls es noch andere gibt, vertragen sich die Default-Werte dann mit den Objekten die schon platziert wurden oder noch werden damit?

Wenn man die Fenstergrösse vorgibt, sollte man wissen wie gross der Inhalt ist. Das weiss man aber nicht, darum sollte man das dem Layout-Manager überlassen.

Und das Problem dürften nicht die Layout-Manager sein, weil das `grid()` den Frame auf dem `Tk`-Fenster setzt und die `place()`-Aufrufe die Labels auf dem Frame. Das sind also zwei verschiedene Container-Widgets.
Locke
User
Beiträge: 3
Registriert: Mittwoch 30. Januar 2008, 15:32

Beitragvon Locke » Mittwoch 30. Januar 2008, 17:32

@pütone:

Danke fuer deine schnelle Antwort und danke das du auch gleich die Tkinter Referenz mit eingebracht hast. Habe mich naemlich an dieser orientiert.

Ich komm bei deiner Analyse jetzt nicht ganz hinterher, sollte ich also auf grid() + pack() umsteigen? Da stellt sich bei mir allerdings die frage wie ich dann die genaue Position eines Objektes definieren kann :)

Mal nebenbei gefragt was ist an place() so schlimm? Ist jetzt nur ne Frage aus reinem Interesse denn mir wurde von nem Kumpel vor Zeiten mal gesagt das ich lieber place() anstelle von pack() benutzen solle weil es angeblich besser sei, deswegen habe ich darauf jetzt vertraut :)

@BlackJack:
Also ich bin eher ein Python-Anfaenger (welches deutlich aus meinem 1. Post hervorgeht) und kann mit deiner Aussage nicht wirklich was anfangen

Du sagtest:
Und man sollte weder die Fenstergrösse vorgeben, noch `place()` verwenden, wenn man GUIs schreiben will, die nicht nur auf dem eigenen Rechner richtig funktionieren.


Kann ich leider nicht ganz nachvollziehen, zumindest das mit der Fenstergroesse nicht, da ich davon ausgehe das jeder normale User mindestens eine Aufloesung von 1024x768 verwendet und Pixel werden von jedem System gleich verarbeitet, warum sollte es dann damit Probleme geben?

Danke fuer eure Hilfe :)

mfg Locke

edit:
zu deinem neuen post @ Blackjack:
Es herrscht Verwirrung in meinem Kopf ;)
btw. ich weiss wie gross der Inhalt ist :D
BlackJack

Beitragvon BlackJack » Mittwoch 30. Januar 2008, 17:48

Die Frage ist nicht, ob das Fenster auf den Bildschirm passt, sondern ob der Inhalt in das Fenster passt. Schriftgrössen sind nicht überall gleich und Bildschirmauflösungen auch nicht. `place()` hat das gleiche Problem. Was bei Dir gut aussieht kann bei anderen zu Elementen führen die übereinander liegen, und damit teilweise unbenutzbar werden, oder zwischen den Elementen sind grössere Lücken.

Wenn man Frames und `pack()` und `grid()` benutzt, sorgt Tk dafür das alles ordentlich angezeigt wird und jedes Element soviel Platz bekommt wie es braucht, nicht mehr und nicht weniger. Und die Fenstergrösse wird auch entsprechend angepasst. Das gilt dann nicht nur für verschiedene Schriftgrössen und Bildschirmauflösungen, sondern auch wenn man mal die Texte auf Buttons oder Labels ändert. So etwas kann bei `place()` eine Menge Änderungen an Elementen in der "Umgebung" nach sich ziehen. Wenn man das Layout Tk überlässt, braucht man nur den Text ändern.

Edit: Zu Deinem Edit: Wenn der Inhalt nicht aus Pixelgrafiken besteht, weisst Du nicht wie gross er ist, weil sich Schriftgrössen und auch Abstände und Grösse von zum Beispiel Rahmen bei `Entry`\s auf anderen Plattformen ändern können.
Locke
User
Beiträge: 3
Registriert: Mittwoch 30. Januar 2008, 15:32

Beitragvon Locke » Mittwoch 30. Januar 2008, 18:00

Hmmm das hab ich nun verstanden, danke fuer diese Erklaerung :)

Wie genau wendet man denn die grid()-Methode an? grid verraet mir ja schon das es sich um ein Gitter handelt, geh ich nu von einem Raster bei der Fotografie aus habe ich insgesamt 3x3 Kaestchen. Ist das bei Python auch so? Ich kann mich dunkel daran erinnern irgendwann mal was gehoert zu haben von 'N, W, E, S' ... (Himmelsrichtungen) mit welchen ich dann bestimmen soll wo sich die Elemente befinden sollen, aber wie genau geht das?

Danke im voraus :)

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

Beitragvon numerix » Mittwoch 30. Januar 2008, 19:47

Ich empfehle das entsprechende Kapitel zu grid() aus Fredrik Lundhs "An Introduction to Tkinter".

http://effbot.org/tkinterbook/grid.htm
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Mittwoch 30. Januar 2008, 19:56

@BlackJack:

`grid()` ohne Zellenangabe mag Default-Werte benutzen, aber welche sind das?


column=0
row = 0 bzw. falls schon Zeilen genutzt sind, die erste ungenutzte Zeile

Und warum `grid()` wenn es nur dieses eine Objekt gibt. Falls es noch andere gibt, vertragen sich die Default-Werte dann mit den Objekten die schon platziert wurden oder noch werden damit?


Warum soll man nicht im Versuchsstadium, wenn es auf anderes ankommt, der Kürze halber einfach .grid() benutzen; ebenso wie .pack(). Auch hier überlässt man ja dem Geometriemanager sozusagen die Hoheit über die Platzierung, sofern man keine entsprechenden Optionen mitgibt.

Für ein gescheites Layout wird man .grid() ebenso wie .pack() kaum ohne Parameter verwenden können.

Wenn man die Fenstergrösse vorgibt, sollte man wissen wie gross der Inhalt ist. Das weiss man aber nicht, darum sollte man das dem Layout-Manager überlassen.


Das verstehe ich nicht. Ich kann doch über .winfo_width() und .winfo_height() die Abmessungen von Widgets und Containern ermitteln und ggf. dann die Größe des Frames anpassen. Oder habe ich jetzt etwas falsch verstanden?
BlackJack

Beitragvon BlackJack » Mittwoch 30. Januar 2008, 20:28

Wenn einem das Spass macht kann man natürlich die Abmessungen von Elementen selbst ermitteln, die Frames entsprechend anpassen, dann deren Container usw. bis zum Fenster. Also das was der Layout-Manager automatisch macht, selbst nochmal implementieren. Dann stell ich aber mal die Frage zurück: Warum?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Mittwoch 30. Januar 2008, 21:09

Dann stell ich aber mal die Frage zurück: Warum?


Beispiel: Ich habe eine kleine Anwendung, die aus einem Frame und ein paar Labels besteht, die alle nahtlos untereinander stehen, so dass sich für den Anwender die Darstellung eines mehrzeiligen Texts in verschiedenen Farben und Fonts ergibt. Der Benutzer hat die Möglichkeit, über einen Mausklick eine Eingabezeile (als Top-Level-Element) zu öffnen, und dort einen Text einzugeben, der anschließend einen Teil des vorher angezeigten Textes verändert; da die Textlänge sich unterscheiden kann, ergeben sich daraus neue Abmessungen für einzelne Labels und auch den umgebenden (Haupt-)Frame.

Soweit alles gut. ABER: Ich möchte, dass dieser Frame IMMER zentriert auf dem Bildschirm erscheint - auch nach Textänderungen. Da ich keine Methode oder Option "center()" o.ä. gefunden habe, die einen Top-Level-Frame auf dem Bildschirm zentriert, muss ich das manuell machen. Ist ja im Prinzip auch kein Problem, da sich die Bildschirmauflösung ermitteln lässt und - bei Kenntnis des Abmessunen des Frames - die entsprechenden Positonierungskoordinaten ebenfalls berechnen lassen.

Wenn ich es weiter richtig sehe, dann steht zur Positionierung auf dem Bildschirm aber nur die geometry()-Methode zur Verfügung, die ZWINGEND nicht nur die Angabe z.B. der linken oberen Ecke des zu positionierenden Frames verlangt, sondern eben auch seine Abmessunge. Die muss ich dafür kennen. ABER: Die Ermittlung dieser Abmessungen mittels .winfo_width() bzw. .winfo_height() schlägt fehl - selbst nach einem vorherigen Aufruf von .idle_tasks(), um die Darstellung vor dem Abfragen der Abmessungen auch tatsächlich auf dem neuesten Stand zu haben.

Vielleicht hast du dafür eine Lösung - das wäre super!
lunar

Beitragvon lunar » Mittwoch 30. Januar 2008, 21:53

pütone hat geschrieben:Beispiel: Ich habe eine kleine Anwendung, die aus einem Frame und ein paar Labels besteht, die alle nahtlos untereinander stehen, so dass sich für den Anwender die Darstellung eines mehrzeiligen Texts in verschiedenen Farben und Fonts ergibt.

Mehrere Labels untereinander, um letztendlich nur eine Art HTML-Viewer oder Highlighting-Widget zu implementieren? Entweder habe ich deine GUI fundamental missverstanden, oder Tk ist schlimmer als ich dachte...

ABER: Ich möchte, dass dieser Frame IMMER zentriert auf dem Bildschirm erscheint - auch nach Textänderungen.

Will das dein User auch? Der durchschnittliche User ist nämlich im Allgemeinen in der Lage, seinen Desktop selbstständig zu organisieren, und mag nicht erfreut darüber sein, dass eine Anwendung im eine Organisation aufzwingen möchte.

Aber diese Sache funktioniert sowieso nicht wirklich. Für die Platzierung ist nämlich letztendlich der Window Manager zuständig, und der kann Fenster so platzieren, wie er will. Außerdem gibt es durchaus Window-Manager, die keine gleichmäßig breiten Rahmen um Fenster zeichnen, so dass das Fenster zwar in der Mitte steht, aber den Inhalt des Fensters wegen der unterschiedlichen Rahmenbreiten verschoben. Auf diese Rahmenbreite hast du aber keine Einfluss und auch keine Zugriff, weswegen du aus einer Anwendung heraus die tatsächliche Darstellung der Arbeitsfläche gar nicht beeinflussen kannst.

Da ich keine Methode oder Option "center()" o.ä. gefunden habe,

Die wäre auch sinnlos, da sie kaum mehr als eine Empfehlung an den Window Manager ist.

Vielleicht hast du dafür eine Lösung - das wäre super!

Lass dem Window Manager, was des Window Manager's ist. Die Platzierung geht dich nichts an, dass macht der Window Manager. Wenn dein Fenster in die Mitte soll, dann nutze dafür die Möglichkeiten deines Window Managers.
BlackJack

Beitragvon BlackJack » Mittwoch 30. Januar 2008, 22:37

@pütone: Das hier funktioniert zumindest unter Linux, mit kwin als Fentermanager: http://paste.pocoo.org/show/24736/

Wie man sieht braucht man bei `geometrie()` die Fenstergrösse gar nicht anzugeben.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Donnerstag 31. Januar 2008, 14:00

BlackJack hat geschrieben:Wie man sieht braucht man bei `geometrie()` die Fenstergrösse gar nicht anzugeben.
Ja, das löst wirklich pütones Problem in seinem Thread 'Problem mit Größenanpassung eines Frames'.
MfG
HWK
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Donnerstag 31. Januar 2008, 14:11

@BlackJack:
Super, das war's. Bisher hatte ich nirgends einen Hinweis darauf gefunden, dass man im geometry-String Teile weglassen kann - auf die Idee, es einfach mal zu probieren, war ich auch nicht gekommen. Lässt man die Angabe für die Abmessungen weg, dann funktioniert das Zentrieren tadellos.

@lunar:
Du erzählst seltsame Sachen, um es mal milde auszudrücken.

Will das dein User auch?


Ja, der User will das. Ich bin der User, und ich will die zentrierte Darstellung.

Aber diese Sache funktioniert sowieso nicht wirklich.


Natürlich funktioniert die Sache! Der Tipp von BlackJack ist da eindeutig. Probier das Programm doch aus. Wieso stellst du Behauptungen auf, die schlicht nicht stimmen?

Du scheinst von Tk wirklich nicht viel zu verstehen. Tk liefert Methoden zur Ermittlung der Bildschirmauflösung und der Fensterabmessungen - daraus eine zentrierte Positionierung zu ermitteln ist doch ein Leichtes, sofern die gelieferten Daten über die Fensterabmessungen korrekt geliefert werden.

Die wäre auch sinnlos, da sie kaum mehr als eine Empfehlung an den Window Manager ist.


Was hat das mit dem Window Manager zu tun? Tk hat Methoden zur absoluten Bildschirmpositionierung - der Window Manager hat da nix zu melden. Und: Warum soll ich meinen Window Manager ändern, wenn es mir nur um die zentrierte Darstellung EINES Fensters geht? Ansonsten bin ich mit der Einstellung meines WM ja zufrieden. "Sinnlos" ist hier jedenfalls nichts.

Die Platzierung geht dich nichts an


Mach du mit deinem WM, was du für richtig hältst. Aber wieso willst du anderen vorschreiben, dass sie ein Anwendungsfenster nicht gerne zentriert auf dem Bildschirm hätten und es Tk möglich macht, dies zu realisieren.

Statt dieses langen, überflüssigen Beitrages wäre eine kurze, klare Lösung mehr Wert gewesen. Siehe BlackJack.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder