Button drücken, Zahl um 1 erhöhen

Fragen zu Tkinter.
Antworten
Daniel7
User
Beiträge: 8
Registriert: Mittwoch 24. Juni 2015, 19:53

Hallo, ich möchte mithilfe eines Buttons eine Zahl rauf zählen lassen. Dabei soll im Hauptfenster ein Button dazu dienen, ein weiteres Fenster zu öffnen. In diesem Fenster soll ein Button dazu dienen, eine Zahl um 1 zu erhöhen.

Problem - bei Betätigung des Buttons kommt diese Fehlermeldung:

label.configure(text=klicks)
NameError: name 'label' is not defined

Code: Alles auswählen

from tkinter import *

root = Tk()
root.geometry("1350x690+0+0")

def Temperaturschwelle():

    toplevel = Toplevel()

    toplevel.geometry("1125x500+205+40")

    counter = 0

    label=Label(toplevel,text="")
    label.pack()

    def counter():

        global label
        global klicks
        label.configure(text=klicks)
        label.update()
        klicks+=1
    
    button1 = Button(toplevel, width=15, height=5, text='Schwelle erhöhen', command=counter)
    button1.place(x=0, y=0)

    button4 = Button(toplevel, width=15, height=5, command=toplevel.destroy)
    button4.place(x=0, y=315)



randomhButton = Button(root, width=15, height=5, text="Temperaturschwelle \n einstellen", command=Temperaturschwelle)
randomhButton.place(x=0, y=315)
     

quitButton = Button(root, width=15, height=5, text='Quit', command = root.destroy)
quitButton.place(x=0, y=420)


root.mainloop()
BlackJack

@Daniel7: `label` ist auf Modulebene ja auch nicht definiert. Da wird es gesucht weil Du gesagt hast es sei dort (``global``). Auf ``global`` sollte man sowieso verzichten, was bei einer objektorientierten Lösung ja auch kein Problem ist und bei GUIs muss man in Python in der Regel eigene Klassen schreiben wenn man eine saubere und so verworrene Lösung haben möchte.
Daniel7
User
Beiträge: 8
Registriert: Mittwoch 24. Juni 2015, 19:53

@BlackJack: Vielen Dank für die schnelle Antwort. Programm funktioniert jetzt :D
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Tkinter bietet "Variablen", welche sich darum kümmern, dass die jeweiligen Widgets aktualisiert werden. Das folgende Beispiel sollte das verdeutlichen:

Code: Alles auswählen

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

class TemperatureFrame(tk.Frame):
    def __init__(self, parent, initial_temperature=0):
        super().__init__(parent)
        self.temperature_threshold = tk.IntVar(value=initial_temperature)

        tk.Label(self, textvariable=self.temperature_threshold).pack()
        tk.Button(self, text='Increase', command=self.increase).pack()
        tk.Button(self, text='Decrease', command=self.decrease).pack()
        tk.Entry(self, textvariable=self.temperature_threshold).pack()

    def increase(self):
        self.temperature_threshold.set(self.temperature_threshold.get() + 1)
        
    def decrease(self):
        self.temperature_threshold.set(self.temperature_threshold.get() - 1)
        
def main():
    root = tk.Tk()
    frame = TemperatureFrame(root, 42)
    frame.pack()
    root.mainloop()
    
if __name__ == '__main__':
    main()
Folgende Punkte solltest Du auf jeden Fall berücksichtigen:
  • Verzichte auf Sternchen-Importe (from tkinter import *)
  • Keine globalen Objekte
  • Kein Code auf Moduleebene
  • Statt des place-Layouters solltest Du besser auf pack oder grid setzen
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Daniel7
User
Beiträge: 8
Registriert: Mittwoch 24. Juni 2015, 19:53

@bwbg, vielen Dank für deine Tipps.
Zu deinem Programm hätte ich jedoch noch 3 Fragen:

1) Was ist der Unterschied zwischen "import tkinter as tk" und "from tkinter import *"?
2) Was bewirkt bzw. für was dient die Zeile "super().__init__(parent)"?
3) Wofür dient die Zeile "if __name__ == '__main__': main()"?

Mit freundlichen Grüßen
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Zu 1:
Sternchenimporte holen so ziemlich alles in den Namensraum, "müllen" diesen somit voll.

Zu 2:
Dies ruft vereinfacht gesagt die Initialisierungsmethode (__init__) der Elternklasse auf. Hier solltest Du Dein Wissen über Klassen und Vererbung aufbessern. Dies ist gerade bei GUIs wichtig.

Zu 3:
Das ist das sogenannte main-Idiom. Die Bedingung ist nur wahr, wenn das Python-Programm direkt aufgerufen wird (genau dann ist __name__ gleich "__main__". Ist das der Fall, wird die main-Funktion aufgerufen. Wenn das Modul importiert wird, wird main daher nicht aufgerufen. So kann man Klassen, Funktionen, etc. aus dem Modul nutzen, ohne dass z. B. das Fenster direkt angezeigt würde.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Daniel7
User
Beiträge: 8
Registriert: Mittwoch 24. Juni 2015, 19:53

@bwbg, Vielen Dank für diese Erklärung! :)
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Hallo,

versuche mich gerade hier zurechtzufinden, aber komme noch nicht so richtig klar.
Ich habe ein Hauptfenster "main" was auch zu funktionieren scheint und möchte ein zweites "settings" fenster über Button öffnen. zwar öffnet das fenster aber es kommen keinen Buttons etc.


mit dem Bereich komme ich auch noch nicht klar was das bedeutet

Code: Alles auswählen

 def __init__(self, parent, initial_temperature=0):
        super().__init__(parent)
initial_temperatur=0 brauche ich ja nicht wenn ich diesen raus nehme kommt aber als fehler.

Traceback (most recent call last):
File "C:/python36/2.py", line 165, in <module>
main()
File "C:/python36/2.py", line 160, in main
frame = mainframe(fenster, 42)
TypeError: __init__() takes 2 positional arguments but 3 were given



Hier mal der gesamte Code der fenster.

Code: Alles auswählen

#Settings Fenster#
def set_fenster():
        set_fenster = Tk()
        set_fenster.title("Einstellungen")
        set_fenster.geometry("180x500+10+180")
        set_fenster.configure(bg='steelblue1')
        frame = settings(set_fenster, 41)
        frame = settings
        frame.pack()
        set_fenster.mainloop

class settings(tk.Frame):
     def __init__(self, parent, initial_temperature=0):
          super().__init__(parent)
         
          settings_label = Label(self, bg="steelblue1", text="Einstellungen")
          settings_label.place(x = 15, y = 5, width=150, height=40)
          settings_label.config(font=("Arial", 15))
       
          anweisungs_label = Label(self, bg="steelblue1", text="Helligkeit")
          anweisungs_label.place(x = 0, y = 70, width=80, height=40)
        
          bri1_button = Button(self, text="+", background='steelblue1', activebackground='steelblue3', command=cambri1)
          bri1_button.place(x = 80, y = 70, width=40, height=40)
          bri2_button = Button(self, text="-", background='steelblue1', activebackground='steelblue3', command=cambri2)
          bri2_button.place(x = 130, y = 70, width=40, height=40)

class mainframe(tk.Frame):

    def __init__(self, parent):
        super().__init__(parent)
       


        Start_button = Button(self, text=" Starten", background='steelblue1', activebackground='steelblue3',  command=Capture)
        Stop_button = Button(self, text="Stopen", background='steelblue1', command=EXIT)
        Settings_button = Button(self, text="Einstellungen", background='steelblue1', command=set_fenster)
        exit_button = Button(self, text="Beenden", background='steelblue1', command=quit)
        Info_button = Button(self, text="Info", background='steelblue1', command=action_get_info_dialog)
        Start_button.grid(row=0, column=2, pady = 20, padx = 20)    
        Stop_button.grid(row=0, column=4, pady = 0, padx = 20)
        Settings_button.grid(row=0, column=6, pady = 0, padx = 20)
        exit_button.grid(row=0, column=8, pady = 0, padx = 20)
        Info_button.grid(row=0, column=10, pady = 0, padx = 20)
       

    

        
#Hauptfenster
def main():

    fenster = tk.Tk()
    fenster.title("Hauptfenster")
    fenster.geometry("1280x800")
    frame = mainframe(fenster, 42)
    frame.pack()
    fenster.mainloop()
    
if __name__ == '__main__':
    main()


__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst auch die aufrufende Stelle veraendern. Da versuchst du ja immer noch, 42 als Temperatur zu uebergeben. Und die Fehlermeldung sagt dir, welche Zeile den Fehler verursacht: 160, mit der Zeile frame = mainframe(fenster, 42)
.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Streifenhase1: Es darf übrigens immer nur *ein* `Tk`-Exemplar gleichzeitig existieren. Das ist *das* Hauptfenster. Wenn man zusätzliche Fenster erstellen möchte, nimmt man `Toplevel`. Bei `mainloop()` gilt im Grunde ähnliches. Das sollte nur einmal laufen, es sei denn man weiss genau was man da macht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Streifenhase1

Was hältst du von folgendem SKript Setup?:

Code: Alles auswählen

import tkinter as tk

APP_TITLE = "Temperature"
APP_XPOS = 10
APP_YPOS = 10
APP_WIDTH = 1280
APP_HEIGHT = 800


class Settings(tk.Toplevel):
    def __init__(self, parent, initial_temperature=0):
        super().__init__(parent)
        
        self.title("Settings")
        
        main_frame = tk.Frame(self)
        main_frame.pack(padx=10, pady=10)
        
        tk.Label(main_frame, text="Einstellungen", font=("Arial", 15)
            ).pack(pady=2)
        
        tk.Label(main_frame, text="Helligkeit").pack(pady=2)

        button_frame = tk.Frame(main_frame)
        button_frame.pack(pady=4)
        
        tk.Button(button_frame, text="+", background='steelblue1',
            activebackground='steelblue3', command=self.cambri1).pack(
                side='left', padx=4)
            
        tk.Button(button_frame, text="-", background='steelblue1',
            activebackground='steelblue3', command=self.cambri2).pack(
                side='left', padx=4)

    def cambri1(self):
        print("cambr1")
        
    def cambri2(self):
        print("cambr2")
        
class MainFrame(tk.Frame):
    
    def __init__(self, haupt_fenster):
        super().__init__(haupt_fenster)
        self.haupt_fenster = haupt_fenster
        self.haupt_fenster.protocol("WM_DELETE_WINDOW", self.close)

        self.build()
        
    def build(self):
        button_frame = tk.Frame(self)
        button_frame.pack(pady=5)
        
        tk.Button(button_frame, text=" Starten", background='steelblue1',
            activebackground='steelblue3',  command=self.capture
            ).pack(side='left', padx=4)
        tk.Button(button_frame, text="Stopen", background='steelblue1', 
            command=self.stop).pack(side='left', padx=4)
        tk.Button(button_frame, text="Einstellungen", background='steelblue1',
            command=self.set_fenster).pack(side='left', padx=4)
        exit_button = tk.Button(button_frame, text="Beenden",
            background='steelblue1', command=self.close).pack(
                side='left', padx=4)
        tk.Button(button_frame, text="Info", background='steelblue1',
            command=self.action_get_info_dialog).pack(side='left', padx=4)

    def capture(self):
        print("Capture")
    def set_fenster(self):
        print("set_fenster")
        self.settings = Settings(self.haupt_fenster)
    def action_get_info_dialog(self):
        print("action_get_info_dialog")
    def stop(self):
        print("Stop")
    def close(self):
        print("Application-Shutdown")
        self.master.destroy()
    
def main():
    haupt_fenster = tk.Tk()
    haupt_fenster.title(APP_TITLE)
    #haupt_fenster.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    haupt_fenster.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    haupt_fenster.option_add("*highlightThickness", 0)
    
    main_frame = MainFrame(haupt_fenster)
    main_frame.pack(fill='both', expand=True, padx=6, pady=6)
    
    haupt_fenster.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf ;-)
Take it easy Mates!
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Ja vielen Dank.

Habe auf deinem Skript aufgebaut. Sicher nicht fehlerfrei aber schon mal was.

Mal sehen ob ich weiter komme.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

so hab wieder eine Frage...

kann ich in dieser zeile

Code: Alles auswählen

tk.Label(self, textvariable=self.temperature_threshold).pack()
den kleinstmöglichen und den größten wert festlegen? Also das beim betätigen des Buttons der wert dann nicht mehr kleiner oder größer wird?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein. Eine solche Beschränkung kannst du nur an der Stelle vornehmen, wo du auf eine Aktion des Nutzers reagierst. Du musst als an der Stelle, an der du erhöhst vorher prüfen, ob das ok geht oder nicht. Gleiches mit der Erniedrigung.
Streifenhase1
User
Beiträge: 90
Registriert: Dienstag 22. Mai 2018, 07:15

Ok Danke.

Dann zum nächsten. Ich habe jetzt z.b. die Temperatur von 42 auf 50 erhöht möchte den Wert aber speichern so das er beim nächsten Start wieder 50 ist.

Das heißt ich muss den Wert in eine .txt Datei speichern und dann wieder auslesen.

Könnt ihr mir das einem Beispiel Skript erklären
Antworten