Seite 1 von 1

Neuling brach hilfe bei einfachem Counter

Verfasst: Samstag 26. Januar 2013, 00:11
von Zett
Ich lerne hobbymässig nen bisschen Python und versuch grad nen einfachen Couner zu basteln.
Ich hab 2 Buttons, einen zum Hochzählen und einen zum Runterzählen(jeweils um 1) und das Ausgabelabel.
Die Darstellung funktioniert auch so wie sie soll, nur wird keine funktion ausgeführt, das Label bleibt bei 0 stehen.

Code: Alles auswählen

import tkinter as tk

class Application(tk.Frame):
    def __init__(self,master=None):
        tk.Frame.__init__(self,master)
        self.pack()
        self.createWidgets()

    def createWidgets(self):
        self.b1=tk.Button(text="Count +",command=Zahlenwert1.count_mehr())
        self.b2=tk.Button(text="Count -",command=Zahlenwert1.count_weniger())
        self.b3=tk.Button(text="Ende",command=root.destroy)
        self.l1=tk.Label(text=Zahlenwert1.Ausgabe())
        self.b1.pack()
        self.l1.pack()
        self.b2.pack()
        self.b3.pack()
   
class counter:
    def __init__(self,z):
        self.Anzahl=z
    def count_mehr(self):
        self.Anzahl+=1
        print(self.Anzahl)
    def count_weniger(self):
        self.Anzahl-=1
        print(self.Anzahl)
    def Ausgabe(self):
        print (self.Anzahl)
        return self.Anzahl
Zahlenwert1=counter(0)
root=tk.Tk()
app=Application(master=root)
app.mainloop()
Die print() in den Funktionen hab ich nur drinnen um zu sehen ob sich überhaupt was tut.
Warum tut sich da nix?

Re: Neuling brach hilfe bei einfachem Counter

Verfasst: Samstag 26. Januar 2013, 00:20
von Sirius3
Der Parameter command muss eine Funktion sein und kein Rückgabewert der Funktion.

Code: Alles auswählen

self.b1=tk.Button(text="Count +",command=Zahlenwert1.count_mehr)
Außerdem muss dem Label ein StringVar-Objekt übergeben werden, das dann beim Counterzählen
geändert wird.

Re: Neuling brach hilfe bei einfachem Counter

Verfasst: Samstag 26. Januar 2013, 00:31
von BlackJack
@Zett: Du übergibst nicht die Methoden als `command`-Argumente, sondern Du *rufst sie auf* und übergibst ihren *Rückgabewert*, also in diesem Fall `None` als `command`. `None` kann tkinter nicht aufrufen wenn die Schaltflächen gedrückt werden.

Bezüglich der Namensschreibweise könntest Du mal einen Blick in den Style Guide for Python Code werfen. Neben der Schreibweise sollte man keine Denglisch-Mix verwenden. Entweder Deutsch oder Englisch. Da die Programmiersprache und die Standardbibliothek in Englisch ist, bietet es sich an auch für den Rest dabei zu bleiben.

Widgets sollten sich nicht selbst „layouten”. Das macht keines der Widgets die von `tkinter` angeboten werden. Aus guten Grund, denn man nimmt damit dem Benutzer die Entscheidungsfreiheit sich selbst ein passendes Layout auszuwählen und die Widgets überall zu verwenden.

`createWidgets()` greift auf Namen auf Modulebene zurück die dort nicht hingehören. Man kann die `Application`-Klasse nur benutzen wenn man vorher bestimmte Objekte auf Modulebene an Namen gebunden hat. So eine Kopplung gehört nicht in ein sauberes Programm. Funktionen und Methoden sollten nur auf Werte zurückgreifen, die als Argumente übergeben wurden. Ausnahmen sind Konstanten. Wenn die `Application` also ein Zählerobjekt benötigt, dann sollte das in der `__init__()` übergeben und an das `Application`-Exemplar gebunden werden.

Re: Neuling brach hilfe bei einfachem Counter

Verfasst: Samstag 26. Januar 2013, 01:16
von Zett
Ich hab das nach dem TK-Manual zusammengeschraubt.
In die verschiedenen Konstruktoren muss ich mich erst noch einlesen, irgendwo.
Aber wie bekomme ich jetzt in dem Code den StringValue hin?
Ein einfaches str(self.Anzahl) hilft nicht weiter, auch die Methode __str__() nich, da bleibt das Label einfach leer

Re: Neuling brach hilfe bei einfachem Counter

Verfasst: Samstag 26. Januar 2013, 08:51
von wuf
Hi Zett

Willkommen im Forum. Habe dein Skript ein wenig aufgepeppt:

Code: Alles auswählen

import tkinter as tk

class Application(tk.Frame):
    def __init__(self, title='', counter_set_value=0):
        
        self.app_win = tk.Tk()
        self.app_win.title(title)
        self.app_win.geometry('{}x{}+{}+{}'.format(100, 200, 20, 20))
        self.counter = Counter(counter_set_value)
        
        tk.Frame.__init__(self, self.app_win, relief='sunken', bd=2)
        self.pack(expand=True)
        self.display_value = tk.StringVar()
        
        self.createWidgets()

    def createWidgets(self):

        tk.Label(self, textvariable=self.display_value, font=('helvetica', 20),
            bg='white', fg='blue', relief='raised', bd=1).pack(fill='x')

        tk.Button(self, text="Count +",command=self.count_up).pack(fill='x')
        tk.Button(self, text="Count -",command=self.count_down).pack(fill='x')
        tk.Button(self, text="Ende",command=self.master.destroy).pack(fill='x')
                
        self.display(self.counter.count)
        
    def count_up(self):
        self.counter.up()
        self.display(self.counter.count)
        
    def count_down(self):
        self.counter.down()
        self.display(self.counter.count)
        
    def display(self, value):
        self.display_value.set(value)

    def run(self):
        self.app_win.mainloop()
        
class Counter:
    def __init__(self, start_value):
        self.count = start_value
        
    def up(self):
        self.count += 1
        
    def down(self):
        self.count -= 1
            
app = Application('Counter', 100).run()
Gruß wuf :wink:

Re: Neuling brach hilfe bei einfachem Counter

Verfasst: Samstag 26. Januar 2013, 09:06
von BlackJack
@Zett: Mir fällt gerade noch ein Fehler auf: Widgets müssen bei der Erstellung als erstes das Widget übergeben bekommen in dem sie dargestellt werden. Sonst wird automatisch das `Tk`-Exemplar genommen. Es ist nur Zufall, dass das bei Deiner GUI nicht auffällt, dass Du einen leeren `Frame` (`Application`) hast und die Schaltflächen und das Label im `Tk`-Exemplar darstellst, statt in dem `Application`-Frame.

In einem ordentlichen Programm trennt man Programmlogik und GUI, das heisst wenn Du nach dem ändern des Zählers den geänderten Zählerstand in der GUI anzeigen möchtest, dann ist das Code der zur GUI gehört. Deshalb sollten die Schaltflächen mit Methoden in der UI-Klasse verbunden werden, die dann ihrerseits die Programmlogik auf dem Zähler-Objekt aufruft und danach die Anzeige aktualisiert.

Einbuchstabige Namen und solche mit angehängten Nummern sollten in der Regel auch nicht vorkommen. Der Name sollte dem Leser vermitteln was ein Objekt im Programmkontext bedeutet und nicht zum raten zwingen. An Objekte sollte man Werte nur binden, wenn sie auch tatsächlich dort gebraucht werden. Bei der Benutzeroberfläche trifft das nur auf das `Label`-Objekt zu.

Code: Alles auswählen

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


class Counter(object):
    def __init__(self, start_value=0):
        self.value = start_value
    
    def increase(self):
        self.value += 1
    
    def decrease(self):
        self.value -= 1


class CounterUI(tk.Frame):
    def __init__(self, master, counter):
        tk.Frame.__init__(self, master)
        self.counter = counter
        tk.Button(self, text='Count +', command=self.increase).pack()
        tk.Button(self, text='Count -', command=self.decrease).pack()
        tk.Button(self, text='End', command=self.master.destroy).pack()
        self.counter_label = tk.Label(self, text=self.counter.value)
        self.counter_label.pack()
    
    def increase(self):
        self.counter.increase()
        self.counter_label['text'] = self.counter.value

    def decrease(self):
        self.counter.decrease()
        self.counter_label['text'] = self.counter.value


def main():
    root = tk.Tk()
    ui = CounterUI(root, Counter())
    ui.pack()
    root.mainloop()


if __name__ == '__main__':
    main()