Tkinter checkbutton interferences when filling in - python

I'm working on a g.u.i. with tkinter. I'm currently trying to make a couple of labelframes with several checkbuttons. The problem is that one checkbutton gets crossed in a window, and another in the other window get crossed too.
I've been looking for similar questions, but I've found none. Being a beginner, I don't really understand where the problem is.
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from scipy.stats import linregress
import pandas as pd
window= tk.Tk()
#creating the 2 labelframes
models = tk.LabelFrame(window, text="Models", padx=10, pady=10)
models.grid(padx=10, pady=10, sticky='W')
param = tk.LabelFrame(window, text="params", padx=10, pady=10)
param.grid(column=0, row=10, sticky='W', padx= 10)
# adding checkbuttons to the first labelframe
lin_cb = tk.Checkbutton(models, text="linear regression")
lin_cb.grid(column=0, row=2, sticky='W')
nlin_cb = tk.Checkbutton(models, text="non-linear regression")
nlin_cb.grid(column=0, row=5, sticky='W')
#labels for second labelframe
tk.Label(param, text="substate").grid(row=1, sticky='W')
tk.Label(param, text="velocity").grid(row=2, sticky='W')
tk.Label(param, text="if inhibited").grid(row=3, sticky='W')
tk.Label(param, text="inibitor").grid(row=4, sticky='W')
#checkbutton
su_M=tk.Checkbutton(param, text='M')
su_M.grid(column=1, row=1, sticky='W')
su_mM=tk.Checkbutton(param, text='mM')
su_mM.grid(column=2, row=1, sticky='W')
window.mainloop()
Before continuing with the program extracting the information from the crossed checkbutton, I have to understand how to solve this problem. Thanks to everyone. I hope that I gave you all the necessary information. I tried to summarise the code as much as possible.

To use a Checkbutton, you need to create tkinter variables and associate them with each Checkbutton.
import tkinter as tk
window= tk.Tk()
models = tk.LabelFrame(window, text="Models", padx=10, pady=10)
models.grid(padx=10, pady=10, sticky='W')
param = tk.LabelFrame(window, text="params", padx=10, pady=10)
param.grid(column=0, row=10, sticky='W', padx= 10)
all_vars = [tk.IntVar() for _ in range(4)] #create 4 IntVars in one go
for i in all_vars : #set all vars to 0
i.set(0)
lin_cb = tk.Checkbutton(models, text="linear regression",variable=all_vars[0]) #set variable for each checkbutton
lin_cb.grid(column=0, row=2, sticky='W')
nlin_cb = tk.Checkbutton(models, text="non-linear regression",variable=all_vars[1])
nlin_cb.grid(column=0, row=5, sticky='W')
tk.Label(param, text="substate").grid(row=1, sticky='W')
tk.Label(param, text="velocity").grid(row=2, sticky='W')
tk.Label(param, text="if inhibited").grid(row=3, sticky='W')
tk.Label(param, text="inibitor").grid(row=4, sticky='W')
su_M=tk.Checkbutton(param, text='M',variable=all_vars[2])
su_M.grid(column=1, row=1, sticky='W')
su_mM=tk.Checkbutton(param, text='mM',variable=all_vars[3])
su_mM.grid(column=2, row=1, sticky='W')
window.mainloop()

Related

How do I update my meter widget (python, ttkbootstrap) using the results I've gathered from a pyspeedtest?

I am trying to update my meter widget with the results of a ping test using pyspeedtest, but I keep getting the error:
"TypeError: Meter.configure() missing 1 required positional argument: 'self'"
The ping function works without any issues, I just can't seem to figure out how to pass the ping result to the meters "amountused" parameter to change the widget.
from tkinter import *
from tkinter.ttk import *
import ttkbootstrap as ttk
import pyspeedtest
root = Tk()
window = style.master
window_width = 300
window_height = 300
root.resizable(False, False)
ping_meter = ttk.Meter
ping_meter(
master=root,
metersize=300,
padding=20,
amountused=0,
metertype='semi',
subtext='milliseconds',
interactive=False
).grid(sticky=N, row=0, column=1, padx=10, pady=10)
myping = IntVar()
def ping_test():
t = pyspeedtest.SpeedTest(e1.get())
myping.set(t.ping())
ping_meter.configure(amountused = myping)
Label(root, text="Website URL:").grid(sticky=W, row=2, padx=10, pady=10)
Label(root, text="Ping Result:").grid(sticky=W, row=3, padx=10, pady=10)
result = Label(root, text="", textvariable=myping).grid(sticky=W, row=3, column=1, padx=10, pady=10)
e1 = Entry(root)
e1.grid(row=2, column=1)
b = Button(root, text="Check", command=ping_test)
b.grid(sticky=W, row=2, column=3, padx=10, pady=10)
mainloop()
the line ping_meter = ttk.Meter creates the variable ping_meter which is just the class ttk.Meter. therefore .configure() doesn't work. when you create an instance it isn't assigned to any variable, instead try doing this to create an instance of ttk.Meter, note that .grid() is called separately.
ping_meter = ttk.Meter(
master=root,
metersize=300,
padding=20,
amountused=0,
metertype='semi',
subtext='milliseconds',
interactive=False
)
ping_meter.grid(sticky=N, row=0, column=1, padx=10, pady=10)
also in ping_test() use ping_meter.configure(amountused = t) instead.

How to get only a corresponding entry box regardless of how many times I change radiobutton?

from tkinter import *
win=Tk()
var = StringVar()
l = Label(win, bg='white', width=15)
l.grid(row=17,column=1,padx=10, pady=10, sticky='w')
def print1_selection():
if var.get()=="Number":
lab1= Label(win, text="Enter a number").grid(row=4, column=0)
ent1=Entry(win).grid(row=4, column=1)
l.config(text='you have selected ' + var.get())
elif var.get()=="Alphabet":
lab21= Label(win, text="Enter an alphabet").grid(row=5, column=0)
ent21=Entry(win).grid(row=5, column=1)
l.config(text='you have selected ' + var.get())
lbl4=Label(win, text="Select One", bg="crimson", fg="white", font=("times new
roman",15,"bold")).grid(row=1, column=0, padx=10, pady=10, sticky='w')
r1 = Radiobutton(win, text='Number',variable=var, value='Number', command=print1_selection, width=22)
r1.grid(row=2,column=0,padx=10, pady=10)
r2 = Radiobutton(win, text='Alphabet', variable=var, value='Alphabet', command=print1_selection, width=22)
r2.grid(row=2,column=1,padx=10, pady=10)
win.mainloop()
In this code I want that when I select radiobutton number, only enter a number should appear and same for the other.
But the problem is that when I select number after selecting alphabet, it shows both. I need only the selected one and eliminate the other instantly.
This is how I would approach this issue:
from tkinter import Tk, StringVar, Label, Frame, Entry, Radiobutton
def print1_selection():
for widget in entry_frame.winfo_children():
widget.destroy()
value = var.get()
lbl.config(text='You have selected ' + value)
if value == "Number":
Label(entry_frame, text="Enter a number").grid(row=0, column=0)
Entry(entry_frame).grid(row=0, column=1)
elif value == "Alphabet":
Label(entry_frame, text="Enter an alphabet").grid(row=0, column=0)
Entry(entry_frame).grid(row=0, column=1)
win = Tk()
var = StringVar(value=0)
entry_frame = Frame(win)
entry_frame.grid(row=2, column=0, columnspan=2)
lbl = Label(win, bg='white', width=20)
lbl.grid(row=3, column=0, columnspan=2, padx=10, pady=10, sticky='w')
Label(win, text="Select One", bg="crimson", fg="white", font=("times new roman", 15, "bold")).grid(row=0, column=0, padx=10, pady=10, sticky='w')
Radiobutton(win, text='Number', variable=var, value='Number', command=print1_selection, width=22).grid(row=1, column=0, padx=10, pady=10)
Radiobutton(win, text='Alphabet', variable=var, value='Alphabet', command=print1_selection, width=22).grid(row=1, column=1, padx=10, pady=10)
win.mainloop()
As You can see if You don't plan on using the widgets instance anywhere You don't have to assign it to a variable. Also no need to configure label in both statements since that will be done anyways so just do it at the beginning, also rows start from 0 too. Frames help with organizing widgets. Also if You want neither of the radiobuttons selected set the variable to 0.

Advice on how to store data

I am fairly new to coding and I am making an app in tkinter with a window that takes a series of user inputs(string&int). i need to be able to open this window multiple times and input different data and i need it to save it every time so I can display the information in seperate windows later on. i will include the code for the window. to be clear, i don't want to overwrite the data, i want it to save each set of data seperately. any help (code or advice) would be great :) thanks.
import tkinter as tk
from tkinter import *
add = tk.Tk()
add.title("Add a new Exersise")
add.geometry('600x600')
add.configure(bg='grey')
add.grid_columnconfigure(0, weight=1)
ExNm = tk.Label(add, bg='grey', text="Exercise Name")
ExNm.grid(row=0, column=0, pady=10, sticky='nesw')
Name = tk.Entry(add)
Name.grid(row=1, column=0, pady=10, padx=15, sticky='nesw')
YtLink = tk.Label(add, bg='grey', text="Youtube Link")
YtLink.grid(row=2, column=0, pady=10, sticky='nesw')
Link = tk.Entry(add)
Link.grid(row=3, column=0, pady=10, padx=15, sticky='nesw')
DocLink = tk.Label(add, bg='grey', text="Tab Document | e.g. Alternate Picking.pdf")
DocLink.grid(row=4, column=0, pady=10, sticky='nesw')
Tab = tk.Entry(add)
Tab.grid(row=5, column=0, pady=10, padx=15, sticky='nesw')
def sliderFunction(event):
Beats = BPM.get()
print(Beats)
BPM_Label = tk.Label(add, bg='grey', text="BPM")
BPM_Label.grid(row=6, column=0, pady=10, sticky='nesw')
BPM = Scale(add,from_=0, to=400, orient=HORIZONTAL, font=('Helvetica','15'))
BPM.bind("<ButtonRelease-1>", sliderFunction)
BPM.grid(row=7, column=0, pady=10, padx=15, sticky='nesw')
Here's a link.
Normally you could build a treeview and store then into CSV.

Moving buttons/entries using grid in tkinter Python

I have just started learning tkinter and am having troubles with moving items around using grid. I am assuming this is an easy fix but I am trying to get my password entry and "generate password" button to be located much closer than they are as seen in the attached image (essentially I want everything aligned). How can I do this? I have looked on here and elsewhere but can't seem to find anything that replicates my problem.
from tkinter import *
window = Tk()
window.title("Password Manager")
window.config(padx=50, pady=50)
canvas = Canvas(height=200, width=200)
canvas.grid(column=1, row=0)
lock = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=lock)
website = Label(text="Website:")
website.grid(column=0, row=1)
email_user_name = Label(text="Email/Username:")
email_user_name.grid(column=0, row=2)
password = Label(text="Password:")
password.grid(column=0, row=3)
website_entry = Entry(width=35)
website_entry.grid(column=1, row=1, columnspan=2)
email_entry = Entry(width=35)
email_entry.grid(column=1, row=2, columnspan=2)
password_entry = Entry(width=21)
password_entry.grid(column=1, row=3)
generate_button = Button(text="Generate Password")
generate_button.grid(column=2, row=3)
add_button = Button(text="Add", width=30)
add_button.grid(column=1, row=4, columnspan=2)
window.mainloop()
You can add sticky="e" to grid(...) on the labels and sticky="w" on the entries:
from tkinter import *
window = Tk()
window.title("Password Manager")
window.config(padx=50, pady=50)
canvas = Canvas(height=200, width=200)
canvas.grid(column=1, row=0)
lock = PhotoImage(file="logo.png")
canvas.create_image(100, 100, image=lock)
website = Label(text="Website:")
website.grid(column=0, row=1, sticky="e")
email_user_name = Label(text="Email/Username:")
email_user_name.grid(column=0, row=2, sticky="e")
password = Label(text="Password:")
password.grid(column=0, row=3, sticky="e")
website_entry = Entry(width=35)
website_entry.grid(column=1, row=1, columnspan=2, sticky="w")
email_entry = Entry(width=35)
email_entry.grid(column=1, row=2, columnspan=2, sticky="w")
password_entry = Entry(width=21)
password_entry.grid(column=1, row=3, columnspan=2, sticky="w")
generate_button = Button(text="Generate Password")
generate_button.grid(column=3, row=3, sticky="w")
add_button = Button(text="Add", width=30)
add_button.grid(column=1, row=4, columnspan=2)
window.mainloop()
Note that I have added columnspan=2 to password_entry.grid(...) and moved generate_button to column 3.

Tkinter update state (disable): need for redraw/refresh?

I cannot get the state of a (tk.)Label and (tk.)Checkbutton to visually turn to disable and normal depending on the value of an OptionMenu.
The command binding on the OptionMenu below seems fine, but my use of configure(state=...), in updateState() has no visible effect. Should I force some "refresh" or "repaint" (if yes how in the partial code below?) or am I missing something else?
import Tkinter
from Tkinter import Frame, LabelFrame, Label, Entry, Button, StringVar, OptionMenu, Checkbutton, IntVar, DISABLED, NORMAL
class GeneratorDialog:
# The UI to configure the settings by the user
def __init__(self, root, ctrl):
self.__root = root
self.__ctrl = ctrl
def updateState(self, value, label, entry):
if(value.get()==CONST.FORMAT_PDF): # test works, as the dialog below show in alternance as expected
tkMessageBox.showinfo('Info', message="enabling checkbox")
label.configure(state=NORMAL)
entry.configure(state=NORMAL)
else:
tkMessageBox.showinfo('Info', message="disabling the checkbox")
label.configure(state=DISABLED)
entry.configure(state=DISABLED)
#self.__root.update_idletasks() # how to force "redraw" with grid() manager?
def show(self):
self.__root.title(CONST.APP_NAME)
mainFrame = Frame(self.__root)
mainFrame.grid(sticky='ew')
outputFrame = LabelFrame(mainFrame, text='Output Settings')
outputFrame.grid(column=0, row=1, padx=5, pady=5, sticky='ew')
keepGeneratedScribusFilesLabel = Label(outputFrame, text='Keep Scribus Files:', width=15, anchor='e')
keepGeneratedScribusFilesLabel.grid(column=4, row=2, padx=5, pady=5, sticky='e')
keepGeneratedScribusFilesCheckbox = Checkbutton(outputFrame, variable=self.__ctrl.getKeepGeneratedScribusFilesCheckboxVariable(), anchor='w')
keepGeneratedScribusFilesCheckbox.grid(column=5, row=2, padx=5, pady=5, sticky='w')
mergeOutputLabel = Label(outputFrame, text='Merge in Single File:', width=15, anchor='w')
mergeOutputLabel.grid(column=0, row=2, padx=5, pady=5, sticky='w')
mergeOutputCheckbox = Checkbutton(outputFrame, variable=self.__ctrl.getMergeOutputCheckboxVariable())
mergeOutputCheckbox.grid(column=1, row=2, padx=5, pady=5, sticky='w')
outputFormatLabel = Label(outputFrame, text='Output Format:', anchor='e')
outputFormatLabel.grid(column=2, row=2, padx=5, pady=5, sticky='e')
outputFormatListBox = OptionMenu(outputFrame, self.__ctrl.getSelectedOutputFormat(), *self.__ctrl.getOutputFormatList(),
command=lambda l=keepGeneratedScribusFilesLabel, c=keepGeneratedScribusFilesCheckbox, v=self.__ctrl.getSelectedOutputFormat(): self.updateState(v, l, c))
outputFormatListBox.grid(column=3, row=2, padx=5, pady=5, sticky='w')
# Buttons to Cancel or to Run the Generator with the given Settings
helpButton = Button(buttonFrame, text='Help', width=10, command=self.__ctrl.helpButtonHandler)
helpButton.grid(column=0, row=0, padx=5, pady=5, sticky='e')
cancelButton = Button(buttonFrame, text='Cancel', width=10, command=self.__ctrl.buttonCancelHandler)
cancelButton.grid(column=1, row=0, padx=5, pady=5, sticky='e')
generateButton = Button(buttonFrame, text='Generate', width=10, command=self.__ctrl.buttonOkHandler)
generateButton.grid(column=2, row=0, padx=5, pady=5, sticky='e')
# Finally show the Generator Dialog
mainFrame.grid()
self.__root.grid()
self.__root.mainloop()
full code is at https://github.com/berteh/ScribusGenerator/blob/93a12de4be28054344533ad8fc424e37180668de/ScribusGenerator.py#L278
solved it by using class variables (self.X) instead of lambda local variables.
still don't know why the former code (with local variables in the lambda) would not update the status of the Tk elements (maybe it created copies thereof?)... but I found a workaround.
thanks all for your help

Categories