Programmierstil

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

grid() ist doch total leicht zu verstehen: Man muss sich eine Tabelle vorstellen, wo row die Zeile und column die Spalte ist. Bei einem sehr einfachen Design ist column=1 quasi die linke und column=2 die rechte Seite. Die row wird natürlich für jede Zeile erhöht. Mehr Magie steckt nicht dahinter.
Benutzeravatar
__blackjack__
User
Beiträge: 13099
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei das Grid wie vieles in der Informatik bei 0 anfängt. Links oben ist also 0, 0 nicht 1, 1.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ snafu :
du, ich bin nicht auf der Brennsuppn dahergeschwommen !
na, ganz so leicht ist es nun auch wieder nicht. Es geht hier ja um DESIGN !
wenn ich mit column=1 anfange, dann erwarte ich, dass zumindest column0 etwas Space generiert. Aber nein, column0 wird komplett ignoriert, weil es nirgends angegeben ist. Ebenso der Raum ZWISCHEN (vertikal) den Labels. Wenn ich row=1, row=3, row=5, etc. angebe, dann erwarte ich, dass row0, row2, row4 wenigstens etwas Zwischenraum generiert, Pustekuchen ... wie soll ich da eine ORDENTLICHE Tabelle generieren ?
MOMENTAN bleibe ich dabei:
grid ist undankbar (für Anfänger) und sch...

EDIT:
das Bild aus _backjack_'s Post vom Samstag 2. März 2019, 12:24, kannst du ja sehen, dann mach' mal, wenn's so einfach ist ...

@ _blackjack_:
eh klar ;-)
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13099
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: Fazit: Keine Zeilen oder Spalten leer lassen. Warum auch? Für Abstände ist `pad` bei `columnconfigure()`/`rowconfigure()` für ganze Zeilen/Spalten da oder die Padding-Angaben beim `grid()`-Aufruf bei einzelnen Zellen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
ich habe mich bisher noch nicht in grid eingelesen. Und deine Aussage bezüglich *pad *:
das hat mit einer Tabelle im klassischen Sinne nichts mehr zu tun. Wenn ich eine Zelle beispielsweise mit bg (Hintergrundfarbe) formatiere, dann erwarte ich auch, dass diese Zelle KOMPLETT mit dieser Farbe hinterlegt wird. Wenn ein *pad* nun einen weißen oder farblosen Zwischenraum generiert, dann hat dies meiner Meinung nach mit einer klassischen Tabelle persé nichts mehr zu tun. Deswegen auch meine vormalige Aussage:
grid ist für Anfänger undankbar, oder gar besch ... (im Sinne einer Tabelle, wie man sie aus HTML, PHP oder Excel her kennt, wo es Freizeilen oder -reihen gibt, eben eine *klassische Tabelle* !).
Wie gesagt: ich muß mich erst noch einlesen ... mit MEINEM Verständnis einer *klassischen* Tabelle hat grid nichts gemein (mein jetziger Wissensstand) ...
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ alle :
und wenn wir schon dabei sind:
kennt jemand eine wirklich gute UND AKTUELLE Doku über Tkinter (und demzufolge auch über grid). Die kann meinetwegen auch auf afrikanisch sein, kein Problem. Ich habe bisher einige Links auf Seiten 'angeboten' bekommen, aber entweder Python 2.7, Doku von 2005, nur *halbherzige* (unvollkommene) Dokus usw. manchmal fühle ich mich diesbezüglich (Dokus) richtig verars... Mir geht es auch bestimmt nicht darum, irgendwelchen Code oder Dinge ohne Nachzudenken serviert zu bekommen, aber Hinweise auf die richtigen Dokus würden mir schon sehr helfen, da ich als Anfänger meist auch nicht zwischen guten und schlechten/alten Dokus (auf die Schnelle) unterscheiden kann ... auch der erste oder zweite Link bei *duckduckgo.com* muß nicht immer der beste oder gar zielführend sein ;-)
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13099
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: In HTML kann man genau so einen Zwischenraum *zwischen* den Zellen erstellen. Und Du kannst ja auch innerhalb der Zellen ”padden” dann hat die Fläche selbstverständlich auch die entsprechende Farbe des Zellhintergrunds. Das ist im Grunde alles wie bei einer HTML-Tabelle. Und Leerzeilen machen wie gesagt keinen Sinn. Wenn Du die haben möchtest, musst Du halt irgendwas als Platzhalter rein setzen. Aber warum? Zumal man auch nicht so mit Farben rum spielt. Irgendwie scheinen Anfänger immer alle möglichen Farben und Schriftarten ausprobieren zu wollen. 99% der Anwendungen nehmen die Farben und Schriften die der Benutzer für sein System eingestellt hat. Da sieht man dann weder etwas vom Zellhintergrund noch vom Padding zwischen Zeilen/Spalten, weil das alles den normalen Fensterhintergrund als Farbe hat.

Wie bei den meisten GUI-Toolkits ist die beste Dokumentation die Originaldokumentation. Also die von Tk. Andererseits hat sich an Tk und damit Tkinter auch nicht so wirklich viel verändert. Für Tkinter ist das Buch vom Effbot und die Referenzdokumentation von New Mexico Tech geeignet. Beides ist auch in der Dokumentation zum `tkinter`-Modul verlinkt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_ :
danke für den Hinweis auf die Dokus !
Ich spiele nicht gerne mit Farben rum (dafür habe ich schon zu viel mit Excel zu tun gehabt), war nur als Beispiel genannt ... und natürlich machen Leerzellen auch keinen Sinn, klar. Wie gesagt, ich muß mich da erst einmal reinlesen, um zu verstehen, wie grid funktioniert ... danke für alles !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ sirius3 :
so, ich habe jetzt deinen Code mal durchgeackert und bin mächtig beeindruckt (auch von Python) !
Echt toller Code ! Wie einfach es doch ist, wenn man es kann. Leicht zu verstehen, sehr gut zu lesen, wow!
'raise' raffe ich jetzt auch ...
mit 'partial' habe ich noch meine Schwierigkeiten, auch, es ohne *return* zu meistern; werde ich aber auch noch in den Griff bekommen.
Da es sich bei der Argumenten'liste' um Schlüsselwort-Argumente der Form *Option=Wert* handelt, kann ich über beispielsweise 'koerpergroesse_label.keys()' auf die Optionen('liste') 'schauen'. Wie kann ich denn eigentlich auf die Werte('liste') schauen?
Mit 'koerpergroesse_label.values()' (da kein Dict) und 'koerpergroesse_label.items()' (da kein Dict) geht das nicht. Habe bisher noch keine Lösung gefunden ...
Und als nächstes werde ich es mit Klassen versuchen, mal schauen, wie ich das gebacken bekomme ...
Vielen lieben Dank nochmals.
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
__blackjack__
User
Beiträge: 13099
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: An die Optionen von Tk-Widgets kommst Du mit der `config()`/`configure()`-Methode heran. Die kann man auch ohne Argumente aufrufen, dann liefert sie ein Wörterbuch mit den Optionen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ _blackjack_:
hmm, klaaaaaaaaaaaaaar. Ich Honk. Vor lauter Bäumen ...
danke !

EDIT:
und wie komme ich nur an die *Werte* ran ?

Code: Alles auswählen

>>> import tkinter as tk
>>> root = tk.Tk()
>>> koerpergroesse_label = tk.Label(root, text='Größe in m :  ', bg='pink')
>>> koerpergroesse_label.keys()
['activebackground', 'activeforeground', 'anchor', 'background', 'bd', 'bg', 'bitmap', 'borderwidth', 'compound', 'cursor', 'disabledforeground', 'fg', 'font', 'foreground', 'height', 'highlightbackground', 'highlightcolor', 'highlightthickness', 'image', 'justify', 'padx', 'pady', 'relief', 'state', 'takefocus', 'text', 'textvariable', 'underline', 'width', 'wraplength']
Zuletzt geändert von Perlchamp am Montag 4. März 2019, 19:46, insgesamt 1-mal geändert.
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Tholo
User
Beiträge: 177
Registriert: Sonntag 7. Januar 2018, 20:36

@Perlchamp
Ich lunger hier schon seit ca. 1 Jahr im Forum rum. Aber ich möchte dich Beglückwünschen! Ich bin der Meinung, dass du dich und deinen Code schnell reflektieren kannst und die Verständnisse schneller erreichen kannst als ich zb. Mein Respekt und Glückwunsch dazu! Ganz Ehrlich! Ich empfinde wirkliches Interesse an Python bei dir!
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ Tholo :
danke für die Blumen. Mit Lob kann ich allerdings nicht gut umgehen ... aber Python ist einfach geil und macht richtig Spaß, oder ?
Ich habe hier aber auch sehr, sehr gute Tutoren - der Dank oder das Lob gilt euch allen hier !
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Tholo
User
Beiträge: 177
Registriert: Sonntag 7. Januar 2018, 20:36

Auf jeden! die großen und kleinen Schreiber hier seien genannt!
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

moinsen,
gesagt, getan: simples tkinter-Programm mit Klassendefinition, mehr oder minder abgeschrieben. Die Fragen diesbezüglich habe ich als Kommentare *im* Skript gekennzeichnet. Und zum Thema 'guter Programmierstil':
ihr hättet mir den Hosenboden versohlt, wenn ich das hier gepostet hätte ...

Code: Alles auswählen

#!/usr/bin/env python3

__author__ = 'Perlchamp'
__date__ = '06.03.2019'

import tkinter as tk

class Application(tk.Frame):

    def __init__(self, master=None):
        tk.Frame.__init__(self, master)  # tk.Frame wird überladen ?
        self.grid()                      # Objekt mittels grid-Manager sichtbar machen ?
        self.createWidgets()

    def createWidgets(self):
        self.quitButton = tk.Button(self, text='Quit',
                                     command=self.quit) # quit 'offizielle' tkinter-Anweisung/-methode,
                                                        # da keine gleichnamige Funktion/Methode ?
        self.quitButton.grid()                         # warum geht self.quit_button.grid() ohne row und column ?

if __name__ == '__main__' :
    root = Application()
    root.master.title(ROOT_TITLE)  # warum  das *.master* ?
    root.mainloop()
wie kann ich alles unterhalb von *if __name__ == '__main__' :* in def main(self) innerhalb der Klasse schreiben und kann man Konstanten in die Klasse schreiben?
Ich habe Folgendes versucht:

Code: Alles auswählen

#!/usr/bin/env python3

__author__ = 'Perlchamp'
__date__ = '06.03.2019'

import tkinter as tk

##    FAVICON = 'image/perlchamp_20x16.ico'      # kann Konstante auch in Klasse geschrieben werden ?
ROOT_TITLE = ' Button mittels Klassendefinition'
ROOT_WIDTH = 350
ROOT_HEIGHT = 200

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.grid()
        self.create_widgets()

    def create_widgets(self):
        self.quit_button = tk.Button(self, text='Quit', command=self.quit)
        self.quit_button.grid(row=0, column=0)
        
    def main(self):
        self.root = Application()
##        self.root.master.iconbitmap(FAVICON)      
        self.root.master.title(ROOT_TITLE)
        self.root.master.geometry(f'{ROOT_WIDTH}x{ROOT_HEIGHT}')
        self.root.mainloop()
        
if __name__ == '__main__' :
    main()
... und erhalte den Fehler "name 'main' is not defined"
Momentan blick's ich nicht, und raten macht auch keinen Spaß (mehr) ... wie macht man es denn richtig ?

EDIT:
Option *mich benachrichtigen* aktiviert
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

@Perlchamp: ›main‹ ist ja auch eine Methode von `Application`. Du mußt also erst eine `Application`-Exemplar erzeugen, um dann main aufzurufen um dann darin noch ein `Application`-Exemplar zu erzeugen. Das macht keinen Sinn.
`main` muß eine Funktion sein.
Dass Du implizit ein Tk-Objekt erzeugst ist unschön. Ein Widget sollte sich nicht selbst Anordnen, denn so kannst Du den Frame nur mit grid benutzen, nicht mit pack.
Methoden schreibt man wie Funktionen und Variablen klein_mit_unterstrich.
`createWidget` ist eigentlich auch nicht nötig, weil man das direkt in __init__ machen kann.
Dass man `grid` ohne Parameter aufrufen kann, heißt nicht, dass man das auch machen sollte.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.quitButton = tk.Button(self, text='Quit',
            command=self.quit)
        self.quitButton.pack()

def main():
    root = tk.Tk()
    root.title("ROOT_TITLE")
    app = Application(root)
    app.pack()
    root.mainloop()

if __name__ == '__main__' :
    main()
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ sirius3:
vielen Dank für deine Antwort. Ich habe das Beispiel original aus der Tkinter 8.5 Doku von der Mexican Tech. Es ist doch zum Ko ....
Anhand MEINES Codes bei meiner Anfrage wirst du gesehen haben, dass ich zumindet alle Bezeichner und Methoden/Funktionen richtig geschrieben habe. Auch die row- und column-Angabe in grid hatte ich, aber darauf will ich nicht hinaus.
Wo gibt es denn eine Doku/Manual/Tutorial, wo man auch gutes Python lernen kann? Ist doch blöd, wenn man sich zu Anfang *schreckliche* Dinge angewöhnt, die man dann nur noch schwer losbekommt.
Fragen:
Dass Du implizit ein Tk-Objekt erzeugst ist unschön.
du beziehst dich damit auf *self.createWidgets()* ?
Also am besten alles (Widgets, Layout-Manager) unterhalb des Klassenkonstruktors *def __init__ (self, ...)* packen ? (als quasi-Faustregel)
Ein Widget sollte sich nicht selbst Anordnen [...]
du beziehst dich damit auf *self.grid()* ?
Du benutzt in deinem Code ausschließlich den Packer. Bist du ein Freund von pack() ? In der Doku der Mexican Tech steht u.a.:
Your application class must inherit from Tkinter's Frame class. In Tkinter, the Frame widget is the basic unit of organization for complex layouts. A frame is a rectangular area that can contain other widgets.

Although there are three different “geometry managers” in Tkinter, the author strongly prefers the .grid() geometry manager for pretty much everything. This manager treats every window or frame as a table—a gridwork of rows and columns.
Stimmt das alles, oder muß ich wieder etwas anderes lernen ?

unklar ist mir auch noch das *.master* im Originalcode.

Code: Alles auswählen

root.master.title(ROOT_TITLE)
ich bin noch etwas verwirrt, und DEIN Code "klingt" wirklich einleuchtend, danke dafür, sirius3 :-)
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ sirius3:
so, ich habe jetzt etwas mit deinem Code herumgespielt und habe diesbezüglich noch ein paar Fragen mehr. Mein jetziger Code lautet wiefolgt:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''test.py
  tkinter mittels Klassendefinition
  + grafische Benutzeroberfläche (GUI)
  + Erstellen eines quit-Buttons
  + Layout-Manager (grid)
  '''

__author__ = 'Perlchamp'
__date__ = '06.03.2019'


import tkinter as tk

##FAVICON = 'image/perlchamp_20x16.ico'
ROOT_TITLE = ' Button mittels Klassendefinition'
ROOT_WIDTH = 350
ROOT_HEIGHT = 200

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.quit_button = tk.Button(self, text='Quit', command=self.quit)
        self.quit_button.grid(row=0, column=0)

def main():
    root = tk.Tk()
    root.title(ROOT_TITLE)
##    root.iconbitmap(FAVICON)
    root.geometry(f'{ROOT_WIDTH}x{ROOT_HEIGHT}')
    app = Application()
    app.grid(row=0, column=0)
    root.mainloop()

if __name__ == '__main__' :
    main()
wird in der Zeile

Code: Alles auswählen

 tk.Frame.__init__(self, master)
tk.Frame ÜBERLADEN ?
ist in der Zeile

Code: Alles auswählen

self.quit_button = tk.Button(self, text='Quit', command=self.quit)
quit eine build-in-Funktion der tkinter-Klasse ?
was ist der Unterschied in *def main()* zwischen

Code: Alles auswählen

app = Application(root)  # Frage: Tk()-Instanziierung (sagt man das so ?)
und

Code: Alles auswählen

app = Application() # Frage: tk.Frame-Instanziierung ?
funktioniert ja beides, ausgehend von meinem Wissensstand/Test.

EDIT:
anstelle von

Code: Alles auswählen

root.mainloop()
könnte ich ja auch

Code: Alles auswählen

app.mainloop()
schreiben, Worin genau liegt hier der Unterschied ?
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Perlchamp hat geschrieben: Mittwoch 6. März 2019, 21:28 wird in der Zeile

Code: Alles auswählen

 tk.Frame.__init__(self, master)
tk.Frame ÜBERLADEN ?
Überladen bedeutet, dass der Compiler abhängig von Typ und Anzahl der Argumente eine spezifische Funktion oder Methode aufrufen soll. Dies liegt hier nicht vor und wird in Python auch nicht unterstützt. Was man im vorliegenden Code sieht, ist das Überschreiben einer Methode durch die erbende Klasse und der Aufruf der gleichnamigen Methode aus der Elternklasse. Der Aufruf ist nötig, da Python sonst nur den Code aus der neuen "Version" von __init__() ausführen würde und somit alles aus der alten __init__() ignorieren würde.

Auf die anderen Fragen will ich nicht eingehen, da meine TKinter-Kenntnisse eher oberflächlich sind...
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

Tk/Tcl ist eine Skriptsprache, die sehr viel Dinge automatisch macht, um schnell mal in wenigen Zeilen ein Fenster zu machen. Es arbeitet viel mit globalen Zuständen und Funktionen. Die Tkinter-Anbindung an Python hat sich dazu entschieden, viele globale Funktionen als Methoden direkt an die Widgets zu binden, also mainloop, after, etc. die aber gar nicht auf dem jeweiligen Widget operieren. Das kann verwirrend sein.

Das Hauptfenster existiert (oder wird bei Bedarf erzeugt) als globale Variable. Wenn man also nichts angibt, wird automatisch das Hauptfenster genommen.
Das ist aber schlechter Stil. Um wenigstens in Python so zu tun, als ob das Hauptfenster lokal erzeugt wurde, sollte man es immer beim Erzeugen von anderen Widgets als Parent übergeben, statt es einfach wegzulassen. Ebenso ist es guter Stil, nur einen mainloop zu haben, der vom Hauptfenster aus aufgerufen wird.
Antworten