tkButton

Fragen zu Tkinter.
Antworten
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Hallo Pythonistas

Ich habe seit geraumer Zeit, mich immer mal wieder, an der Programmierung
in Python versucht. Nun, da ich mehr Zeit habe, möchte ich dieser Versuchung
nachgeben.
Mein Problem:
Wie weise ich einem button direkt einen Wert zu?

"tkButton(command=funtion_b(wert))" funktioniert nicht,

geht nur der Umweg über

tkButton(command=function_a())
"def function_a():
wert=0
function_b(wert)" ??

Grüsse
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

Auch Dein zweiter Code funktioniert nicht, weil man command eine Funktion übergeben muß, und nicht dessen Rückgabewert.

Man benutzt dafür functools.partial:

Code: Alles auswählen

from functools import partial
tk.Button(command=partial(function, wert))
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Hallo Sirius3,
erstmal Danke für Deine Rückmeldung.
Also das funktioniert:

Code: Alles auswählen

#usr/bin/env python3
#-*- coding: utf-8 -*-
import tkinter as tk
class MaingUI():
	def __init__(self, master):
		self.master = master
		master.geometry('325x300')
		master.resizable(0, 0)
#####hintergrund
		self.back = tkFrame(master = root, bg = '#000000')
		self.back.place(x = 3, y = 3, width = 320, height = 295)
#####ausgabe
		self.ausGabe = tkLabel(master = self.back, bg = '#ffffff', text = '0', anchor = 'e')
		self.ausGabe.place(x = 20, y = 20, width = 280, height = 60)
#####buttons zahlen
		self.b1 = tkButton(master = self.back, text = '1', relief = 'flat', command = self.z1)
#####umleitung buttoneingabe zur ausgabe
	def z1(self):
		i = 1
		self.zeig_Ausgabe(i)
#####anzeigen der eingabe
	def zeig_Ausgabe(self, i):
		self.ausgabewert.append(str(i))
		self.ausGabe.configure(text = '')
		self.ausGabe.configure(text = str(''.join(self.ausgabewert)))
if __name__ == '__main__':
	root = tk()
	My_aPP = MaingUI(root)
	root.mainloop()
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Habe eben partial aus functools getestet, funkt, dadurch spare ich mir die funktion self.z1
habe aber einen import mehr, besten dank für den tip
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Code: Alles auswählen

#usr/bin/env python3
#-*- coding: utf-8 -*-
from tkinter import Tk as tk
from functools import partial as fupa
class MaingUI():
	def __init__(self, master):
		self.master = master
		master.geometry('325x300')
		master.resizable(0, 0)
#####hintergrund
		self.back = tkFrame(master = root, bg = '#000000')
		self.back.place(x = 3, y = 3, width = 320, height = 295)
#####ausgabe
		self.ausGabe = tkLabel(master = self.back, bg = '#ffffff', text = '0', anchor = 'e', font = ("Sans Bold", 20))
		self.ausGabe.place(x = 20, y = 20, width = 280, height = 60)
#####buttons zahlen
		self.b1 = tkButton(master = self.back, text = '1', relief = 'flat', command = fupa(self.zeig_Ausgabe, i = 1))
#####anzeigen der eingabe
	def zeig_Ausgabe(self, i):
		self.ausgabewert.append(str(i))
		self.ausGabe.configure(text = '')
		self.ausGabe.configure(text = str(''.join(self.ausgabewert)))
if __name__ == '__main__':
	root = tk()
	My_aPP = MaingUI(root)
	root.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 13107
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@roomwithaview: ``from functools import partial as fupa``? Ernsthaft?

Dann sind `tkFrame`, `tkLabel`, und `tkButton` undefiniert. `tkinter.Tk` explizit als `tk` zu importieren ist auch eine ziemlich schlechte Idee.

Der Code im ``if __name__ ...``-Zweig gehört in eine Funktion. Denn der definiert globale Variablen und eine davon wird dann auch prompt versucht in der Klasse zu verwenden.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Mal davon abgesehen: Warum ist das ”g” in `ausGabe` gross geschrieben? Warum das ”g” in `MaingUI` klein? Warum ”y” und ”a” in `My_aPP` klein? Die Vorsilbe „my“ ist in Namen zudem auch noch unsinnig solange es nicht auch „our“ oder etwas in der Richtung gibt wogegen das „my“ dann eine wirklich relevante Information ist um Dinge auseinander halten zu können.

Kommentare fangen mit *einem* ``#`` an und werden entsprechend dem Code eingerückt zu dem sie gehören. Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist.

`master` ist ein passender Argumentname für das erste Argument einer `__init__()`-Methode wenn das auch tatsächlich eine Widgetklasse ist und `master` das übergeordnete Widget in der Hierarchie ist. Das ist in der vorliegenden Klasse aber nicht der Fall. Die erbt implizit von `Objekt` und das als `master` übergebene Objekt ist in keinerlei Beziehung ein ”Meister” dieser Klasse. Es würde an dieser Stelle vielleicht Sinn machen tatsächlich von `Tk` zu erben. Dann gibt es aber auch keine übergeordnete Widgetklasse, denn `Tk` ist grundsätzlich an der Spitze einer solchen Hierarchie.

Das `master`-Argument ist bei `tkinter`-Widgets die ein übergeordnetes Objekt benötigen *immer* das erste Argument. Es ist also nicht nötig oder sinnvoll da beim ersten Argument eine Übergaben als Schlüsselwortargument zu machen.

`place()` und Grössenangaben in Pixeln macht man nicht. Das funktioniert nicht wirklich. Das geht auf dem System wo man das so entwirft, aber sowie sich Randbedingungen wie Bildschirmauflösung, Schrifteinstellung, und so weiter, ändern, sieht das entweder nicht mehr richtig aus, oder ist sogar unbenutzbar wenn sich Bedienelemente überlappen und/oder Texte nicht mehr oder nicht mehr ganz sichtbar sind.

Wenn das `tkinter`-Modul Konstanten für bestimmte Argumente definiert, sollte man *die* verwenden, statt den Wert als Zeichenkettenliteral selbst noch mal zu schreiben.

Das Attribut `ausgabewert` ist undefiniert. Soll wohl eine Liste sein‽

Namen sollten nicht kryptisch abgekürzt werden und auch nicht nummeriert werden. Warum heisst `b1` nicht einfach `button`? Warum überhaupt ein Name für dieses Objekt, und dann auch noch als Attribut, denn das wird ja anscheinend danach nicht mehr verwendet. Den `Frame` hätte man auch nicht an das Objekt binden müssen.

`zeige_ausgabe()` ist inhaltlich falsch weil die Methode mehr macht als nur eine Ausgabe zu zeigen. Das erweitert die Ausgabe. `i` ist da auch kein besonders guter Argumentname. Und ist das wirklich notwendig, das man dort andere Werte als Zeichenketten übergeben können muss? Denn wenn dort eh alles in Zeichenketten umgewandelt wird, kann man auch gleich nur Zeichenketten übergeben.

Es macht keinen Sinn in dem Label eine leere Zeichenkette zu setzen um gleich in der nächsten Zeile einen anderen Wert für den Text zu setzen.

Das Ergebnis der `str.join()`-Methode ist bereits eine Zeichenkette. Ein zusätzlicher `str()`-Aufruf mit dem Ergebnis macht den Wert nicht irgendwie noch ”zeichenkettiger”.

Zwischenstand:

Code: Alles auswählen

#/usr/bin/env python3
import tkinter as tk
from functools import partial


class MainGUI(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.resizable(False, False)
        self["background"] = "#000000"

        self.ausgabe_teile = list()

        self.ausgabe_label = tk.Label(
            self,
            text="0",
            width=20,
            anchor=tk.E,
            font=("Sans Bold", 20),
            background="#ffffff",
        )
        self.ausgabe_label.pack(padx=5, pady=5)

        text = "1"
        tk.Button(
            self,
            text=text,
            relief=tk.FLAT,
            command=partial(self.erweitere_ausgabe, text),
        ).pack()

    def erweitere_ausgabe(self, text):
        self.ausgabe_teile.append(text)
        self.ausgabe_label["text"] = "".join(self.ausgabe_teile)


def main():
    gui = MainGUI()
    gui.mainloop()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Hallo,

Code: Alles auswählen

@__blackjack__
Dir auch besten Dank für die hilfreiche Rückmeldung.
Bei

Code: Alles auswählen

from functools import partial as fupa
wollte ich mir Schreibarbeit sparen aber Du hast Recht, da kommt man
bei laengerem Code wahrscheinlich durcheinander.
from tkinter import label as tkla, button as tkbu, ...
:roll:
Ich habe mal den Code von Dir 1zu1 uebernommen. Mit pack muss ich
mich noch anfreunden. Mein neuer Code:

Code: Alles auswählen

#/usr/bin/env python3
import tkinter as tk
from functools import partial


class MainGUI(tk.Tk):
	def __init__(self):
		tk.Tk.__init__(self)
		self.resizable(False, False)
		self["background"] = "#000000"

		self.ausgabe_teile = list()

		self.ausgabe_label = tk.Label(
			self,
			text="0",
			width=20,
			anchor=tk.E,
			font=("Sans Bold", 20),
			background="#ffffff",
		)
		self.ausgabe_label.pack(padx=5, pady=5)


		text = "1"
		tk.Button(
			self,
			text = text,
			relief = tk.FLAT,
			command = partial(self.erweitere_ausgabe, text),
		).pack(padx = 5, side = tk.LEFT)
		text = "2"
		tk.Button(
			self,
			text = text,
			relief = tk.FLAT,
			command = partial(self.erweitere_ausgabe, text),
		).pack(side = tk.LEFT)
		text = "3"
		tk.Button(
			self,
			text = text,
			relief = tk.FLAT,
			command = partial(self.erweitere_ausgabe, text),
		).pack(padx = 5, side = tk.LEFT)
		text = "4"
		tk.Button(
			self,
			text = text,
			relief = tk.FLAT,
			command = partial(self.erweitere_ausgabe, text),
		).pack(side = tk.LEFT)
		text = "C"
		tk.Button(
			self,
			text = text,
			relief = tk.FLAT,
			command = self.loesche_ausgabe,
		).pack(padx = 5, side = tk.LEFT)
	def erweitere_ausgabe(self, text):
		self.ausgabe_teile.append(text)
		self.ausgabe_label["text"] = "".join(self.ausgabe_teile)
	def loesche_ausgabe(self):
		if len(self.ausgabe_teile) != 0:
			self.ausgabe_teile.pop()
			self.ausgabe_label["text"] = "".join(self.ausgabe_teile)
		else:
			pass
def main():
	gui = MainGUI()
	gui.mainloop()


if __name__ == "__main__":
	main()
Nun habe ich erneut eine Frage zu den Buttons. Es werden definitiv
mehr hinzukommen. Der Code waere entsprechend lang und mit sehr
vielen Wiederholungen gespickt. Welchen Ansatz schlagt ihr vor?

Gruesse
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@roomwithaview: Du hast den Code ja nicht übernommen, sondern aus der Einrückung mit 4 Leerzeichen Tabs gemacht. Es wird aber immer mit 4 Leerzeichen eingerückt.
Wenn man viele Wiederholungen hat, benutzt man for-Schleifen.
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Ja das stimmt, habe Gedit als Editor und arbeite
mit Tabs zur Einrueckung. Wo ist das Problem?
__deets__
User
Beiträge: 14540
Registriert: Mittwoch 14. Oktober 2015, 14:29

Macht man nicht weil es zum einen überraschend gesetzt wird je nach Editor und Einstellungen, und zum zweiten von Menschen nicht von Spaces unterschieden werden kann. Und so zu Fehlern führen, wenn du zb Code aus einer Webseite kopiert hast, und Spaces mit Tabs mischt.

Darum sagt der offizielle Styleguide man soll 4 Spaces verwenden.

Ein guter Editor akzeptiert aber trotzdem Tab (und shift tab zb ) zum einrücken, du tippst also nicht mehr. Er wandelt das einfach in Spaces um.
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

An eine for schleife dachte ich auch.
Etwa so:

Code: Alles auswählen

for i in range(0, 9, 1):
    text = i
    tk.Button(
        self,
        text = text,
        relief = tk.FLAT,
        command = partial(self.erweitere_ausgabe, text),
        ).pack(padx = 5, side = tk.LEFT)
:?:
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Das funzt schom mal:

Code: Alles auswählen

for i in range(0, 10, 1):
    text = i
    tk.Button(
        self,
        text = text,
        relief = tk.FLAT,
        command = partial(self.erweitere_ausgabe, str(text)),
        ).pack(padx = 5, side = tk.LEFT)
Nur die Ausrichtung laesst noch wuensche offen.
roomwithaview
User
Beiträge: 9
Registriert: Samstag 19. September 2020, 15:55

Gedit laesst sich in den Einstellungen dazu bewegen Leerzeichen
anstatt Tabs einzufügen. Habs eben geaendert.
Antworten