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
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: 13079
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: 13079
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: 17741
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: 6738
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: 17741
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.
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ snafu:
deine Antwort verwirrt mich etwas, denn:
Ein wichtiges Konzept der objektorientierten Programmierung ist der Polymorphismus (bzw. die Polymorphie). Damit ist die Möglichkeit gemeint, den gleichen Namen für (mehr oder weniger) gleichartige Operationen zu verwenden, die auf Objekte unterschiedlicher Klassen angewendet werden. Man spricht auch vom Überladen (overloading) einer Operation.
Bei Python können Operatoren und Standardfunktionen überladen werden, indem man bei einer neuen Klasse bestimmte Methoden mit vorgegebenen Namen definiert. Diese reservierten Methodennamen beginnen und enden mit doppelten Unterstrichen. [...]
Und ich gehe davon aus, dass du genau das gemeint hast ...
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:
ok, das ist in der Tat verwirrend, aber ich denke, dass ich dies soweit verstanden habe, muss es aber zuvor noch sacken lassen. Es ist schade, dass dies in vielen Tuts ignoriert wird, was es mir schwerer macht ... nun gut, einen Tod muss ich wohl sterben ...
Danke für deine Antwort und deine sehr gute Erklärung ...
wer lesen kann ist klar im Vorteil ;-)
es gibt keine Probleme, sondern nur Lösungen !
Bildung ist die Freude auf mich selbst !
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Perlchamp hat geschrieben: Donnerstag 7. März 2019, 21:02 @ snafu:
deine Antwort verwirrt mich etwas, denn:

[...]

Und ich gehe davon aus, dass du genau das gemeint hast ...
"Überladen" meint in der Programmierung normalerweise das Überladen von Methoden oder Funktionen, so wie snafu geschrieben hat.
Dein Textauszug, den du aus dem Zusammenhang reißt (stammt übrigens aus "Python 3: Lernen und professionell anwenden. Das umfassende Praxisbuch" von Michael Weigend) meint aber - wie das auch in dem Text steht - das Überladen von Operatoren. Das ist etwas anderes.

Übrigens ist deutsche Literatur im Bezug auf Python in der Regel ... schwierig bis falsch. Dieses Buch kenne ich allerdings nicht.
Benutzeravatar
Perlchamp
User
Beiträge: 172
Registriert: Samstag 15. April 2017, 17:58

@ sparrow:
__add__ beispielsweise ist ein Operator, richtig. Ich 'rede' ja in dem Textauszug von Operatoren UND Funktionen (und somit auch Methoden).
Folgende Passage von snufu hat mich verwirrt:
Ü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.
Im Grunde weiß ich ja, was gemeint ist/war, und möchte mich daran jetzt auch nicht aufhängen ...
Ich wollte ja nur wissen, ob dies durch

Code: Alles auswählen

tk.Frame.__init__(self, master)
der Fall ist ...
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: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Perlchamp: `__add__()` ist eine Methode. ``+`` ist ein Operator. Mittels `__add__()` kann man in Python den ``+``-Operator überladen. Bei Methoden geht das in Python nicht, weil sich das Überladen auf den gleichen Namensraum bezieht und es kann jeden Namen immer nur einmal pro Namensraum geben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten