Saverio Vasapollo
Saverio Vasapollo

Reputation: 53

tkinter button double use

I'm new here and new in PY, I'm trying to write a simple GUI with Tkinter (py 2.7.10) where there are two buttons: the first one starts printing stuff and the second one quits. I'd like the first button to change the text after the first click from "START" to "STOP" and of course to stop the loop, so I can pause instead of closing and reopen every time.

Also feel free to give any advice to improve it :)

I hope it's clear, here is the code.

import random, time
from Tkinter import *

START, STOP = "start", "stop"

class AppBase:
    def __init__(self, root):
        self.myRoot = root
        self.frame1 = Frame(root)
        self.frame1["background"] = "LightSteelBlue"
        self.frame1.pack()

        self.delay = Scale(self.frame1, from_=100, to=0)
        self.delay.pack(side = LEFT, padx=5, pady=15)

        self.label0 = Label(self.frame1, text="Notes", background="LightSteelBlue", foreground="darkblue")
        self.label0.pack(padx=5, pady=15)
        self.label1 = Label(self.frame1, text="NOTE", background="LightSteelBlue", foreground="SteelBlue")
        self.label1.pack(padx=30, pady=10)
        self.label2 = Label(self.frame1, text="STRING", background="LightSteelBlue", foreground="SteelBlue")
        self.label2.pack(padx=30, pady=7)
        self.label3 = Label(self.frame1, text="FINGER", background="LightSteelBlue", foreground="SteelBlue")
        self.label3.pack(padx=30, pady=7)

        self.puls1 = Button(self.frame1)
        self.puls1.configure(text = "Start", background = "CadetBlue", borderwidth = 3, command = self.generate_notes)
        self.puls1.pack(side = LEFT, padx=5, pady=15)
        self.puls2 = Button(self.frame1)
        self.puls2.configure(text = "Exit", background = "CadetBlue", borderwidth = 3)
        self.puls2.pack(side = LEFT, padx=5, pady=15)
        self.puls2.bind("<Button-1>", self.close_all)
        self.notes_process=1

    def generate_notes(self):
        self.notes = ['DO','DO#','RE','RE#','MI','MI#','FA','FA#','SOL','SOL#','LA','LA#','SI','SI#']
        self.strings = ['1^ corda','2^ corda','3^ corda','4^ corda','5^ corda','6^ corda']
        self.fingers = ['Indice','Medio','Anulare','Mignolo']
        self.note = random.randrange(0, len(self.notes))
        self.string = random.randrange(0, len(self.strings))
        self.finger = random.randrange(0, len(self.fingers))
        self.timer=self.delay.get()
        if self.timer == '':
            self.timer = 500
        elif int(self.timer) < 1:
            self.timer = 500
        else:
            self.timer=int(self.delay.get())*100
        self.label1["text"] = self.notes[self.note]
        self.label2["text"] = self.strings[self.string]
        self.label3["text"] = self.fingers[self.finger]
        self.myRoot.after(self.timer, self.generate_notes)

    def close_all(self, evento):
        self.myRoot.destroy()
        self.myRoot.quit()

def main():
    master = Tk()
    master.title("Notes")
    appBase = AppBase(master)
    master.mainloop()

main()

I found a solution, thanks to everybody for their help and of course if you want to keep talking about different and (sure) better way to do, you are more than welcome! Here my solution:

step 1, add this to the button: self.puls1.bind("<Button-1>", self.puls1Press1)

step 2, add a new variable: self.active = True

step 3, create a new function:

def puls1Press1(self, evento):
    if self.puls1["text"] == "Start":
        self.puls1["text"] = "Stop"
        self.active = True
    else:
        self.puls1["text"] = "Start"
        self.active = False

step 4, modify the function that I want to stop:

def generate_notes(self):
    if self.active == True:
        [some code]
        [some code]
    else:
        return

Upvotes: 2

Views: 991

Answers (2)

Kundan Kumar
Kundan Kumar

Reputation: 511

StringVar() from variable class can be used to update text as well as a looping condition. Example code:

ButtonText=StringVar()
ButtonText.set("START")
button1 = tkinter.Button(self.frame1, text=ButtonText, width=25, command= lambda: do_something(ButtonText))

Elsewhere where you are looping check for the value of the variable:

My_Loop():
    if(ButtonText.get()=="STOP"):
         break
    else:
        #some print statements

Now in function do_something(ButtonText), which will be called after each button press, change the string to "STOP" or vice versa :

do_something(ButtonText):
    if(ButtonText.get()=="START): #Change text
          ButtonText.set("STOP")
    else:
          ButtonText.set("START") #Change text and call function to loop again
          My_Loop()

Hope this helps.

Upvotes: 0

falsetru
falsetru

Reputation: 369054

You need to save the return value of the after, so that you can use it when you cancel the loop using after_cancel(the_return_value_of_after).

def generate_notes(self):
    if self.puls1['text'] == 'Start':
        # Change button text to Stop, and call the original loop function
        self.puls1['text'] = 'Stop'
        self._generate_notes()
    else:
        # cancel timer
        self.puls1['text'] = 'Start'
        self.myRoot.after_cancel(self.timer_handle)

def _generate_notes(self):
    ...(old codes)..
    self.timer_handle = self.myRoot.after(self.timer, self._generate_notes)

Upvotes: 3

Related Questions