Am trying to make GUI app which compulsory you have to select one of predict button before the number entered will be printed to the terminal,if none of predictbutton is selected the should print outselect predict button to proceed.
In pseudecode something like:
def check:
now = new.get()
if no lotto_button is selected:
print("select predict button to proceed")
else:
print(now)
But having challenges:
1:when i select one predict button both buttons raised.
2:How to make the predict compulsory to be selected before the content in the entry will be printed.
import tkinter as tk
def terminal():
now = new.get()
print(now)
def start_func():
lotto_button.configure(relief=tk.SUNKEN, state=tk.DISABLED)
lotto_button1.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop_func():
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
lotto_button = tk.Button(root, text="predict one", command=start_func)
lotto_button.pack(side="left")
lotto_button1 = tk.Button(root, text="predict two", command=start_func)
lotto_button1.pack()
tk.Button(root, text="print number", command=lambda :[stop_func(),
terminal()]).place(x=150, y=300)
root.mainloop()
Thank you and your advice to do is welcome.
As for making it compulsory for picking, you can define a flag in outermost scope (in same level as root = tk.Tk()) so that you can see in your functions if it's set or not like:
isPredicted = False
And as for disabling each button when one is picked, you can define your your start_func such that it takes button object (lotto_button or lotto_button1) as argument:
def start_func(button_object):
global isPredicted
isPredicted = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
To be able to use this function, you need to configure your buttons in the following way, so that they pass themselves as the argument:
lotto_button.configure(command=lambda button_object=lotto_button: start_func(button_object))
lotto_button1.configure(command=lambda button_object=lotto_button1: start_func(button_object))
You should have isPredicted flag in your stop_func as well so that it unsets it:
def stop_func():
global isPredicted
isPredicted = False
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
As for your terminal function, you'd want to act based on the state of isPredicted so it needs to be defined as:
def terminal():
global isPredicted
if isPredicted:
now = new.get()
print(now)
else:
print("select predict button to proceed")
finally in your "print number" button you need to swap the order of the functions in lambda or isPredicted is always False as far as that button's command is concerned:
tk.Button(root, text="print number", command=lambda :[terminal(),
stop_func()]).place(x=150, y=300)
Your final code should look like:
import tkinter as tk
from tkinter import messagebox
def terminal():
global isPredicted
if isPredicted:
now = new.get()
print(now)
else:
print("select predict button to proceed")
def start_func(button_object):
global isPredicted
isPredicted = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop_func():
global isPredicted
isPredicted = False
lotto_button.configure(relief=tk.RAISED, state=tk.ACTIVE)
lotto_button1.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
isPredicted = False
lotto_button = tk.Button(root, text="predict one")
lotto_button.configure(command=lambda button_object=lotto_button: start_func(button_object))
lotto_button.pack(side="left")
lotto_button1 = tk.Button(root, text="predict two")
lotto_button1.configure(command=lambda button_object=lotto_button1: start_func(button_object))
lotto_button1.pack()
tk.Button(root, text="print number", command=lambda :[terminal(),
stop_func()]).place(x=150, y=300)
root.mainloop()
When you're clicking on one of the button prediction, both are raised because in your function start_func, you're configuring both.
Instead of configuring both of them you can bind an event click and getting the widget in start_func like this:
lotto_button = tk.Button(root, text="predict one")
lotto_button.bind('<1>', start_func)
lotto_button.pack(side="left")
And then in your start_func :
def start_func(event):
w = event.widget
w.configure(relief=tk.SUNKEN, state=tk.DISABLED)
About your second point, I'm not sure to understand what you mean.
Using Radiobutton widgets tends to be better for this sort of multiple choice processing.
Radiobuttons belong to "groups" which means that you can set them up so that one always needs to be selected by default. This means that you don't need to have any kind of error catching or display any sort of instruction to the user, it just intuitively works.
from tkinter import *
root = Tk()
def command(v, entry):
print(v.get(), entry.get())
v = StringVar()
v.set(1)
entry = Entry(root)
rb1 = Radiobutton(root, text="Predict One", variable=v, value=1, indicatoron=0)
rb2 = Radiobutton(root, text="Predict Two", variable=v, value=2, indicatoron=0)
button = Button(root, text="Print Number", command=lambda:command(v, entry))
entry.pack()
rb1.pack()
rb2.pack()
button.pack()
root.mainloop()
So we create a StringVar() which we use to define which Radiobutton widgets should be linked together and then we set it's value to 1 which is the value of the "Predict One" button. If the user presses the other Radiobutton then the value changes to 2 which means the first button "unpresses" and the value of the StringVar() is changed to 2.
Related
Using Tkinter and Python. Already created a window for the buttons to be placed on. I want there to be four buttons to appear, and I want to be able to click one of the four buttons, and be able for it to set the selection variable = "whatever I clicked", so that I can then use this variable later to call an API. When I run the program and click on the "General knowledge" button and print the selection, it does correctly print "General knowledge", but then when I try to return this selection variable it just doesn't work and I don't know why.
def select1():
selection = "General Knowledge"
print(selection)
def select2():
selection = "Science"
def select3():
selection = "Entertainment"
def select4():
selection = "Miscellaneous"
button1 = tk.Button(text = "General Knowledge", command = select1)
button1.place(x=100, y=100)
button2 = tk.Button(text = "Science", command = select2)
button2.place(x=100, y=140)
button3 = tk.Button(text = "Entertainment", command = select3)
button3.place(x=100, y=180)
button4 = tk.Button(text = "Miscellaneous", command = select4)
button4.place(x=100, y=220)
There are several ways to accomplish your goal.
One way is to write a single function that will take a value to assign to your variable. This way you can have as many buttons as you like and only a single function.
Not if you are using functions you have to either pass the variable to the function or let the function know it is in the global namespace.
import tkinter as tk
root = tk.Tk()
selection = ''
def assign_value(value):
global selection
selection = value
lbl["text"] = value
print(selection)
lbl = tk.Label(root, text='Selection Goes Here')
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: assign_value("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: assign_value("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: assign_value("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: assign_value("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
Or you can assign the value directly from the button.
import tkinter as tk
root = tk.Tk()
selection = tk.StringVar()
selection.set('Selection Goes Here')
lbl = tk.Label(root, textvariable=selection)
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: selection.set("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: selection.set("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: selection.set("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: selection.set("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
I am sure if I spent more time on this I could think up something else but the idea is basically write your code in a more DRY (Don't Repeat Yourself) fashion and make sure you are assigning the value to the variable in the global namespace or else it will not work as you expect.
I want to make Button2 do something, but only if Button1 has been pressed first and it's code was successfully run.
Also: Button2 should not execute button_1's function, and I do not want to use global variables.
The code below was my initial thought, and it did not work. I've searched for the right way, but neither of the methods I found gave me the result I hoped for.
Can anyone tell me how to correct this? I'm also open for easier or better ways to achieve my goal.
import tkinter as tk
from sys import exit
window = tk.Tk()
def button_1():
print("Button 1 pressed")
button_1_pressed = "Yes"
return button_1_pressed
def button_2():
if (button_1_pressed == "Yes"):
print("Button 1 was pressed, taking action")
# Action goes here
else :
print("Button 1 was NOT pressed, no action is done")
btn_1 = tk.Button(master=window, text="Button 1", width=10, height=2, command=button_1)
btn_1.pack()
btn_2 = tk.Button(master=window, text="Button 2", width=10, height=2, command=button_2)
btn_2.pack()
btn_Close = tk.Button(master=window, text="Close", width=10, height=2, command=exit)
btn_Close.pack()
window.mainloop()
Note: This is just a quick and simple script, illustrating exactly what I need help with in all simplicity.
How to pass variable from one function to another (button pressed)
To get returned value from the callback you should use invoke() method of the Button.
BUT it's just returned value, and unfortunately you cannot use it as a flag, as it doesn't track was the button pressed or not.
So the trick is to create your custom button with a flag which will be changed to True by callback and pass the flag as an argument to the button_2, to do so you can use lambda or partial func.
I hope it's fine for you, despite of it uses the vars out of function scope.
Updated code:
import tkinter as tk
from sys import exit
window = tk.Tk()
class MyButton(tk.Button):
pressed = False
def button_1():
print("Button 1 pressed")
button_1_pressed = "Yes"
btn_1.pressed = True
return button_1_pressed
btn_1 = MyButton(master=window, text="Button 1", width=10, height=2, command=button_1)
btn_1.pack()
def button_2(state):
if state:
print("Button 1 was pressed, taking action")
print('gotcha!')
else:
print("Button 1 was NOT pressed, no action is done")
btn_2 = tk.Button(master=window, text="Button 2", width=10, height=2, command=lambda: button_2(btn_1.pressed))
btn_2.pack()
btn_Close = tk.Button(master=window, text="Close", width=10, height=2, command=exit)
btn_Close.pack()
window.mainloop()
Useful links:
https://www.tutorialspoint.com/python/tk_button.htm
How to pass arguments to a Button command in Tkinter?
I'm Creating a gui in tkinter and have buttons named btn1 btn2 btn3 etc, what i want the button to do on click is disable the button clicked and enable the next button in order. I can write out 6 seperate functions but that seems to defeat the point of a function.
if (btn1['state'] == tk.NORMAL):
btn1.config(state=tk.DISABLED),
btn2.config(state=tk.NORMAL)
else: print ('already clicked')
this is what i have now, but i want it to look more like btn #+1 (state=DISABLED)
You can put the buttons in a list, and then iterate over the list.
Here's a bit of a contrived example:
import tkinter as tk
root = tk.Tk()
def click(button_number):
button = buttons[button_number]
button.configure(state="disabled")
if button == buttons[-1]:
# user clicked the last button
label.configure(text="BOOM!")
else:
next_button = buttons[button_number+1]
next_button.configure(state="normal")
next_button.focus_set()
label = tk.Label(root, text="")
label.pack(side="bottom", fill="x")
buttons = []
for i in range(10):
state = "normal" if i == 0 else "disabled"
button = tk.Button(root, text=i+1, state=state, width=4,
command=lambda button_number=i: click(button_number))
button.pack(side="left")
buttons.append(button)
buttons[0].focus_set()
root.mainloop()
I want my tkinter button to raised when selected before content in the entry can be printed but both button can be selected to be raised at the same time.All the behaviour i want my widget to act is performing only that am able to select both button at the same time which i want one to raised at a time.
import tkinter as tk
def output():
global choosed
if choosed:
now = new.get()
print(now)
else:
print("select predict button to proceed")
def raised_button(button_object):
global choosed
choosed = True
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop():
global choosed
choosed = False
lot1.configure(relief=tk.RAISED, state=tk.ACTIVE)
lot2.configure(relief=tk.RAISED, state=tk.ACTIVE)
root = tk.Tk()
root.geometry("400x400")
new = tk.StringVar()
en = tk.Entry(root, textvariable=new).pack()
choosed = False
lot1 = tk.Button(root, text="GOOD")
lot1.configure(command=lambda button_object=lot1:
raised_button(button_object))
lot1.pack(side="left")
lot2 = tk.Button(root, text="BAD")
lot2.configure(command=lambda button_object=lot2:
raised_button(button_object))
lot2.pack()
tk.Button(root, text="print number", command=lambda :[output(),
stop()]).place(x=150, y=300)
root.mainloop()
if button GOOD is selected the sunken is applied to it only then if select button BAD sunken effect is applied to it the button Good sunken effect is disabled.
As I understand only one button can be sunken. If you click second button then first button (which is sunken) have to raise again.
You can use stop() inside raise_button().
def raised_button(button_object):
global choosed
choosed = True
stop()
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
Or you can use choosed to remember suken button and raise it when you click other button.
def raised_button(button_object):
global choosed
if choosed: # previously clicked
choosed.configure(relief=tk.RAISED, state=tk.ACTIVE)
choosed = button_object
button_object.configure(relief=tk.SUNKEN, state=tk.DISABLED)
def stop():
global choosed
choosed = None
lot1.configure(relief=tk.RAISED, state=tk.ACTIVE)
lot2.configure(relief=tk.RAISED, state=tk.ACTIVE)
#----
choosed = None # set at start
EDIT: you can also use Radiobuttons with indicatoron=0 and they will look like normal buttons but still only one Radiobutton can be selected.
import tkinter as tk
root = tk.Tk()
v = tk.IntVar()
tk.Radiobutton(root, text="One", variable=v, value=1, indicatoron=0).pack()
tk.Radiobutton(root, text="Two", variable=v, value=2, indicatoron=0).pack()
tk.Button(root, text='Reset', command=lambda:v.set(0)).pack()
root.mainloop()
See more on effbot.org: Radiobutton
In the program I made, the user presses enter and the text typed is then shown as a label in the program. So the label keeps getting updated and then written on the next line. The problem is that in the textbox the previous line the user typed stays there, which means u have to keep manually deleting the string in the textbox to write a new line. How can I make it so that you start out with a cleared textbox? Also, the enter button works but it seems that when i click on the "Return" button it gives me an error:
TypeError: evaluate() missing 1 required positional argument: 'event'
Here's the code:
from tkinter import *
window = Tk()
window.geometry("200x300")
def evaluate(event):
thetext = StringVar()
labeloutput = Label(app, textvariable = thetext)
n = e.get()
thetext.set(n)
labeloutput.grid()
app = Frame(window)
app.pack()
e = Entry(window)
e.pack()
b= Button(window, text="Return", command=evaluate)
b.pack()
window.bind("<Return>", evaluate)
mainloop()
Since you bind evaluate as a callback and you use it as a button command, when you use it in the button you have to use a lambda and pass None to the event. event argument is needed because of the binding, but there is no event when you call it from button click, so just pass None to get rid of the error. You can delete by doing entry.delete(0, 'end').
from tkinter import *
window = Tk()
window.geometry("200x300")
def evaluate(event):
thetext = StringVar()
labeloutput = Label(app, textvariable = thetext)
n = e.get()
thetext.set(n)
labeloutput.grid()
e.delete(0, 'end') # Here we remove text inside the entry
app = Frame(window)
app.pack()
e = Entry(window)
e.pack()
b = Button(window, text="Return", command=lambda: evaluate(None)) # Here we have a lambda to pass None to the event
b.pack()
window.bind("<Return>", evaluate)
mainloop()
Of course, if you want to prevent the lambda from being used, you would have to create a function to handle the key binding, and a separate one for the button click.