linking radiobutton with functions in tkinter - python

I have this little issue with making functions run depending on the radiobutton selection as you can see in this code.
the purpose is to define which function to be executed when I press Calculate according to the radiobutton selection.
import tkinter as tk
master = tk.Tk()
tk.Label(master, text='Choose Color :').grid(row=0)
tk.Label(master, text='What Is The Number ? ').grid(row=2)
fdose = tk.Spinbox(master, from_ = 0, to = 60).grid(row=2, column=1)
def calculate():
#this should take my input from the spinbox and add 10 to it if I choose Yellow
#this should take my input from the spinbox and add 100 to it if I choose Green
pass
v = tk.IntVar()
pen = tk.Radiobutton(master, text = 'Yellow',variable = v, value = 1).grid(row=0, column=1)
pen = tk.Radiobutton(master,text ='Green', variable = v, value = 2).grid(row=1, column=1)
but1 = tk.Button(master, text = 'Close', width = 20, bg = 'black', fg = 'red',activebackground = 'red', activeforeground = 'black', command = master.destroy)
but1.grid(row = 5, column = 1)
but2 = tk.Button(master, text = 'Calculate', width = 20, bg = 'black', fg = 'red',activebackground = 'red', activeforeground = 'black', command = calculate)
but2.grid(row = 5, column = 0)
master.mainloop()

the function calculate retrieves the value selected in the radiobuttons, and calls the appropriate function.
import tkinter as tk
master = tk.Tk()
tk.Label(master, text='Choose Color :').grid(row=0)
tk.Label(master, text='What Is The Number ? ').grid(row=2)
fdose = tk.Spinbox(master, from_=0, to=60).grid(row=2, column=1)
def do_yellow():
print('doing the yellow thinghy')
def do_green():
print('doing the green thinghy')
def calculate():
"""retrieves the value selected in the radiobuttons, and
calls the appropriate function.
"""
[do_yellow, do_green][int(v.get())-1]()
v = tk.IntVar()
pen = tk.Radiobutton(master, text='Yellow', variable=v, value=1)
pen.grid(row=0, column=1)
pen = tk.Radiobutton(master, text='Green', variable=v, value = 2)
pen.grid(row=1, column=1)
but1 = tk.Button(master, text='Close', width=20, bg='black', fg='red', activebackground='red', activeforeground='black', command=master.destroy)
but1.grid(row=5, column=1)
but2 = tk.Button(master, text='Calculate', width=20, bg='black', fg='red', activebackground='red', activeforeground='black', command=calculate)
but2.grid(row=5, column=0)
master.mainloop()

Related

Tkinter: Cannot edit entry widget after 2nd selection

I've made a simple GUI for placing objects in RoboDK via a Python script using Tkinter.
Essentailly, the user selects an object using the btnSelect button, which then updates the entry widgets with its coordinates (x, y, z, then Euler rotation). The user can then edit the entry widgets then select the "Move object" button (or btnMove in the code) to move the object to the new position. However, when selecting an object for the second time, the entry fields cannot be edited without selecting a new object.
from tkinter.constants import DISABLED, NORMAL, CENTER, END
from typing import *
import tkinter as tk
import threading
from robolink import * # RoboDK API
from robodk import * # Robot toolbox
X_MAX = 500
X_MIN = 0
Y_MAX = 300
Y_MIN = -360
ROTZ_MAX = 180
ROTZ_MIN = -180
# Keep track of selected item
obj = None
def main():
rdk = Robolink()
window = buildGUI(rdk)
window.mainloop()
def buildGUI(rdk: Robolink) -> tk.Tk:
window = tk.Tk()
canvas = tk.Canvas(window, width=200)
canvas.grid(columnspan=3, rowspan=14)
# Set the window title (must be unique for the docking to work, try to be creative)
window_title = 'Move object window'
window.title(window_title)
title = tk.Label(window, text="Move Object", font="none 14 bold")
title.grid(columnspan=3, column=0, row=0)
# Delete the window when we close it
window.protocol("WM_DELETE_WINDOW", lambda: onClose(window))
deadspace1 = tk.Label(text="")
deadspace1.grid(columnspan=3, column=0, row=1)
selectText = tk.StringVar()
btnSelect = tk.Button(window, textvariable=selectText, height=2, width=0,
bg="#bbbbbb", fg='white', justify=CENTER)
selectText.set("Select object")
btnSelect.grid(column=1, row=2)
deadspace2 = tk.Label("")
deadspace2.grid(columnspan=3, column=0, row=3)
objName = tk.StringVar()
objLabel = tk.Label(window, textvariable=objName, font="none 12 bold")
objName.set("None Selected")
objLabel.grid(columnspan=3, column=0, row=4)
deadspace2 = tk.Label("")
deadspace2.grid(columnspan=3, column=0, row=5)
# Position options
xLabel = tk.Label(window, text="x: ", font='none 12')
xLabel.grid(column=0, row=6)
xEntry = tk.Entry(window, width=10)
xEntry.grid(columnspan=2, column=1, row=6)
yLabel = tk.Label(window, text="y: ", font='none 12')
yLabel.grid(column=0, row=7)
yEntry = tk.Entry(window, width=10)
yEntry.grid(columnspan=2, column=1, row=7)
zLabel = tk.Label(window, text="z: ", font='none 12')
zLabel.grid(column=0, row=8)
zEntry = tk.Entry(window, width=10)
zEntry.grid(columnspan=2, column=1, row=8)
# Rotation options
rxLabel = tk.Label(window, text="rx: ", font='none 12')
rxLabel.grid(column=0, row=9)
rxEntry = tk.Entry(window, width=10)
rxEntry.grid(columnspan=2, column=1, row=9)
ryLabel = tk.Label(window, text="ry: ", font='none 12')
ryLabel.grid(column=0, row=10)
ryEntry = tk.Entry(window, width=10)
ryEntry.grid(columnspan=2, column=1, row=10)
rzLabel = tk.Label(window, text="rz: ", font='none 12')
rzLabel.grid(column=0, row=11)
rzEntry = tk.Entry(window, width=10)
rzEntry.grid(columnspan=2, column=1, row=11)
entries = [xEntry, yEntry, zEntry, rzEntry, ryEntry, rxEntry]
deadspace3 = tk.Label(text="")
deadspace3.grid(columnspan=3, column=0, row=12)
btnMove = tk.Button(window, text="Move object", height=2, width=0,
bg="#bbbbbb", fg='white', justify=CENTER,
command=lambda: moveObject(entries))
btnMove.grid(column=1, row=13)
selectCallback = lambda: select_item(rdk, selectText, objName, entries)
btnSelect['command'] = selectCallback
EmbedWindow(window_title)
return window
# Close the window
def onClose(window: tk.Tk):
window.destroy()
quit(0)
def select_item(rdk: Robolink, selectText: tk.StringVar, objName: tk.Label,
entries: List[tk.Entry]):
def thread_btnSelect():
selectText.set("Waiting...")
item = rdk.ItemUserPick('Select an item', ITEM_TYPE_OBJECT)
if item.Valid():
global obj
obj = item
objName.set(item.Name())
updateObjectPosition(item, entries)
selectText.set("Select object")
# Prevent RoboDK from freezing
threading.Thread(target=thread_btnSelect).start()
def updateObjectPosition(item: Item, entries: List[tk.Entry]):
pose = item.Pose()
coords = Pose_2_KUKA(pose)
for entry, coord in zip(entries, coords):
entry.delete(0, END)
entry.insert(0, str(coord))
def moveObject(entries: tk.Entry):
global obj
if obj is None:
ShowMessage("No object selected")
return
try:
coords = getCoords(entries)
obj.setPose(KUKA_2_Pose(coords))
except Exception as err:
ShowMessage(str(err))
def getCoords(entries: List[tk.Entry]) -> list:
coords = [0] * 6
for i, entry in enumerate(entries):
coords[i] = float(entry.get())
return coords
if __name__ == "__main__":
main()
Using a tkinter.Variable such as tkinter.DoubleVar with your entries should fix this issue. You can also use tkinter.DoubleSpin for convenience.
x, y, z, rx, ry, rz = Pose_2_TxyzRxyz(item.Pose())
xVar = tk.DoubleVar(value=x)
xEntry = tk.Spinbox(window, textvariable=xVar, format="%.2f", from_=-9999999, to=9999999)
xVal = xVal.get()

Python progress bar selecting limitation

I'm using Tkinter with a progress bar.
I've got the code below with the "callback" function that adding 50% to my progress bar.
I would like to limit the function to work only once for each OptionMenu selection.
Currently, I can click twice on the first OptionMenu and get to 100% in the progress bar.
Does anyone know what I should change in the "callback" function in order to make it work only once for each OptionMenu? No matter how many times the user has clicked to change its selected value.
from tkinter import *
from tkinter.ttk import Progressbar
root = Tk()
root.title('Input window V1')
root.geometry('600x400')
root.resizable(False, False)
frame = Frame(root, width=600, height=400)
frame.configure(background="gray28")
frame.pack(fill=BOTH, expand=True)
progress = Progressbar(root, orient=HORIZONTAL, length=300, mode='determinate')
progress.place(x=150, y=15)
Budget = {'Flexible', 'Variable', 'Fixed'}
Commitment = {'High', 'Medium', 'Low'}
def callback(*args):
progress["value"] += 50
bottom_header = Label(root, bg="gray28", fg="white", pady=3,
font=("Helvetica", 20, 'underline'), text='Please fill the following attributes:')
bottom_header.place(x=110, y=100)
lbl1 = Label(root, bg="gray28", text='Budget:', fg="cyan2", font=("Helvetica", 14))
lbl1.place(x=120, y=200)
lbl2 = Label(root, bg="gray28", text='Commitment:', fg="cyan2", font=("Helvetica", 14))
lbl2.place(x=120, y=240)
var1 = StringVar(root)
pl1 = OptionMenu(root, var1, *Budget)
pl1.config(width=20, bg="GREEN", fg="white")
pl1.place(x=250, y=200)
var1.trace("w", callback)
var2 = StringVar(root)
pl2 = OptionMenu(root, var2, *Commitment)
pl2.config(width=20, bg="GREEN", fg="white")
pl2.place(x=250, y=240)
var2.trace("w", callback)
global var_dict
var_dict = dict(Budget=var1,
Commitment=var2)
button1 = Button(root, text="Test")
button1.config(width=25, bg="white")
button1.place(x=220, y=320)
root.mainloop()
Thanks in advance!
Try this out:
from tkinter import *
from tkinter.ttk import Progressbar
def callback(*args):
user_input = (var_1.get(), var_2.get()) # Here you can add even more variables
value = 100 - 100/len(user_input)*(user_input.count("")+user_input.count("Select option"))
progress.config(value=value)
root = Tk()
progress = Progressbar(root, orient="horizontal", length=300)
progress.pack()
var_1 = StringVar(root)
var_1.trace("w", callback)
optionmenu_1 = OptionMenu(root, var_1, "Select option", "Option 1", "Option 2")
optionmenu_1.pack()
var_2 = StringVar(root)
var_2.trace("w", callback)
optionmenu_2 = OptionMenu(root, var_2, "Select option", "Option 1", "Option 2")
optionmenu_2.pack()
# You can remove these if you don't like them:
var_1.set("Select option")
var_2.set("Select option")
root.mainloop()
It counts the number of empty OptionMenus and setts the progress bar to the correct percentage.
Keep track of which of the two you have already accounted for, and update only if there was not yet 50% added for this part.
The callback function is changed (and is understandable) and the passing of the callback is changed to a lambda function (which can be confusing if you never used them).
this works for me:
from tkinter import *
from tkinter.ttk import Progressbar
root = Tk()
root.title('Input window V1')
root.geometry('600x400')
root.resizable(False, False)
frame = Frame(root, width=600, height=400)
frame.configure(background="gray28")
frame.pack(fill=BOTH, expand=True)
progress = Progressbar(root, orient=HORIZONTAL, length=300, mode='determinate')
progress.place(x=150, y=15)
Budget = {'Flexible', 'Variable', 'Fixed'}
Commitment = {'High', 'Medium', 'Low'}
budgetset = False
commitmentset = False
def callback(nb):
global budgetset, commitmentset
if nb == 0 and not budgetset:
budgetset = True
progress["value"] += 50
if nb == 1 and not commitmentset:
commitmentset = True
progress["value"] += 50
bottom_header = Label(root, bg="gray28", fg="white", pady=3,
font=("Helvetica", 20, 'underline'), text='Please fill the following attributes:')
bottom_header.place(x=110, y=100)
lbl1 = Label(root, bg="gray28", text='Budget:', fg="cyan2", font=("Helvetica", 14))
lbl1.place(x=120, y=200)
lbl2 = Label(root, bg="gray28", text='Commitment:', fg="cyan2", font=("Helvetica", 14))
lbl2.place(x=120, y=240)
var1 = StringVar(root)
pl1 = OptionMenu(root, var1, *Budget)
pl1.config(width=20, bg="GREEN", fg="white")
pl1.place(x=250, y=200)
var1.trace("w", lambda *_, x=0: callback(x))
var2 = StringVar(root)
pl2 = OptionMenu(root, var2, *Commitment)
pl2.config(width=20, bg="GREEN", fg="white")
pl2.place(x=250, y=240)
var2.trace("w", lambda *_, x=1: callback(x))
global var_dict
var_dict = dict(Budget=var1,
Commitment=var2)
button1 = Button(root, text="Test")
button1.config(width=25, bg="white")
button1.place(x=220, y=320)
root.mainloop()

Parameters passed to a function does not works as intended

When the "view" button is pressed, it should trigger the function solution(i) such that label should be displayed in the new window. The problem is that the window opens and the previous label is packed but the label which gets it's text from "i" does not gets packed, Is there any issue in passing the parameter.
Any help is appreciated.
root = Tk()
root.config(background = "#303939")
root.state('zoomed')
def pre():
with open("DoubtSolution.txt","r+") as f:
dousol = f.read()
dousol_lst = dousol.split("`")
k = 0
window = Tk()
window.config(background = "#303939")
window.state('zoomed')
predoubt = Label(window,
text="Previous Doubts",
fg="Cyan",
bg="#303939",
font="Helvetica 50 bold"
).grid(row=0, column=1)
def solution(text):
print(text)
window1 = Tk()
window1.config(background="#303939")
window1.state('zoomed')
sol = Label(window1,
text=text[:text.find("~")],
font=font.Font(size=20),
bg="#303939",
fg="Cyan")
sol.pack()
window1.mainloop()
for i in dousol_lst:
if i[-5:] == admno:
doubt = Label(window, text=i[i.find("]]")+2:i.find("}}}}")], font=font.Font(size=20), bg="#303939",
fg="Cyan")
doubt.grid(row=2+k, column=1, pady=10)
view = Button(
master=window,
text="View", font=font.Font(size=15, family="Helvetica"),
activebackground="White",
bg="Teal",
bd=0.8,
fg="White",
command = lambda k = k:solution(i)
)
view.grid(row=2+k, column=2, padx=20)
k=k+1
window.mainloop()
previous = Button(
master=root,
text="Previous Doubts", font="Helvetica 22 bold",
activebackground="White",
bg="Teal",
bd=0.8,
fg="White",
command = pre
).grid(row=4, column=3, padx=20)
root.mainloop()

How can I import this entry answer into a text after

Okay so I have this sign up form and there is a part where you have to enter your name, I want that name answer to be taken to the page after.
import tkinter as tk
root = tk.Tk()
root.geometry("150x50+680+350")
def FormSubmission():
global button_start
button_start.place_forget()
l1.place_forget()
root.attributes("-fullscreen", True)
frame = tk.Frame(root)
tk.Label(frame, text="First Name:").grid(row=0)
name = entry1 = tk.Entry(frame) # I want the name written here to be taken from here to the welcome text.
entry1.grid(row=0, column=1)
tk.Label(frame, text="Last Name:").grid(row=1)
e2 = tk.Entry(frame)
e2.grid(row=1, column=1)
tk.Label(frame, text="Email:").grid(row=2)
e3 = tk.Entry(frame)
e3.grid(row=2, column=1)
tk.Label(frame, text="Date of Birth:").grid(row=3)
e4 = tk.Entry(frame)
e4.grid(row=3, column=1)
frame.pack(anchor='center', expand=True)
button_next = tk.Button(frame, text = "Next", height = 2, width = 7, command =lambda: MainPage(frame))
button_next.grid(row=4, column=1)
def MainPage(frame):
global FormSubmission
frame.pack_forget()
root.attributes("-fullscreen", True)
l1.place(x = 500, y = 10)
button_start.place_forget()
l1 = tk.Label(root, text="Welcome," , font=("Arial", 44)) #As you can see here in this line I want the entry 1 name here after welcome and the comma
button_start = tk.Button(root, text="Start", height=3, width=20, command = FormSubmission)
button_start.place(x = 0, y = 10)
button_exit = tk.Button(root, text="Exit", command=root.destroy)
button_exit.place(x=1506, y=0)
root.mainloop()
What I want to do is take the entry 1 answer and put it in the welcome text. There is an indicator on the lines I'm talking about.
Here is an example how to provide text from your widget entry1
in function FormSubmission():where you are defining your button you should pass the text you want to show in your label
button_next = tk.Button(frame, text = "Next", height = 2, width = 7, command =lambda: MainPage(frame, entry1.get()))
in funtion MainPage(frame):you should set text to your label:
def MainPage(frame, entry1):
global FormSubmission
frame.pack_forget()
root.attributes("-fullscreen", True)
l1.place(x = 500, y = 10)
button_start.place_forget()
l1.config(text="Welcome," + entry1) #<-------

Python: How can I remove excel entries via openpyxl using a feedback loop?

I am building a small app to study the vocabulary of various languages (see below the code for Mandarin). I have the basic funcions which work well. Now I want to add a button in my GUI where i can remove entries (i.e. individual words) from the database, once i have mastered the word (i.e. a button in tkinter which would remove the entry). After removing, the random function in python should then only select words from the reduced database. Do you have any idea how to do this? Any help is welcome!
from tkinter import *
import random
import sys
import os
randvalue_start = random.randint(2, 592)
window = Tk()
window.title('Mandarin Vocabulary')
window.geometry('500x400')
icon = PhotoImage(file = r'C:\Users\PycharmProjects\Mandarin\HSKlogopng.600px.png')
icon2 = icon.subsample(5 ,5)
label1 = Label(window, image = icon2, anchor="ne")
import openpyxl
path = r"\Users\PycharmProjects\Mandarin\characters.xlsx"
worbook = openpyxl.load_workbook(path, read_only=True)
sheet = worbook.active
row_count = (sheet.max_row)
def english_btn1():
global randvalue_start
english = f"B{randvalue_start}"
english_value = sheet[english].value
label_eng = Label(window, text=english_value+":", width=20, height=3, font=("TkDefaultFont",15))
label_pin = Label(window, text="", font=30, width=15, height=3)
label_mand = Label(window, text="", font=30, width=15, height=4)
label_eng.grid(row=8,column=1,rowspan=2)
label_pin.grid(row=8, column=2)
label_mand.grid(row=9, column=2)
def pinying_btn2():
global randvalue_start
pinying = f"C{randvalue_start}"
mandarin = f"D{randvalue_start}"
pinying_value = sheet[pinying].value
mandarin_value = sheet[mandarin].value
combined = f"{pinying}'/'{mandarin}"
combined_value = f"{pinying_value}'/'{mandarin_value}"
label_pin = Label(window ,text=pinying_value,font=("TkDefaultFont",15), width=10, height=2)
label_mand = Label(window,text=mandarin_value,font=("TkDefaultFont",30), width=8,height=2, borderwidth=5,relief="ridge")
label_pin.grid(row=8,column=2)
label_mand.grid(row=9,column=2)
randvalue_start = random.randint(2, 592)
def reset():
os.execl(sys.executable, sys.executable, *sys.argv)
frame = LabelFrame(window,text="Input",padx=5, pady=5)
frame.grid(row=0,column=1,padx=10,pady=10)
btn2 = Button(frame,text = "Show answer", fg = "green" ,width=20 ,command=pinying_btn2)
btn3 = Button(frame,text = "clear", fg= "red", width=20 ,command=reset)
btn1 = Button(frame,text = "Next character", fg = "black" ,width=20,command=english_btn1)
words_label = Label(frame,text = "# of characters: " + str(row_count))
label1.grid(row=0,column=2, columnspan=2)
Label(window, text="", width=20, height=3, font=("TkDefaultFont", 15)).grid(row=8, column=1)
label_blk1 = Label(window, text="", font=("TkDefaultFont", 15), width=10, height=3).grid(row=8, column=2)
label_blk2 = Label(window, text="", font=("TkDefaultFont", 30), width=10, height=2, padx=1, pady=1).grid(row=9, column=2)
btn1.grid(padx=5, pady=5)
btn2.grid(padx=5, pady=5)
btn3.grid(padx=5, pady=5)
words_label.grid(padx=5,pady=5)
window.mainloop()
This is not really a question about Pyxl or Excel. The question is really: how do you generate random numbers that skip certain numbers.
from random import randint
n = 592
numbers = list(range(n))
# To get a random number from the list
random_number = numbers[randint(0, len(numbers)-1)]
# To remove 123 from the list
numbers.remove(123)

Categories