TKinter Change Label with "Next" Button - python

The program is meant to review a set of sentences one at a time. I want to show one and then when the "next" button is clicked, it shows the next input. Right now it blasts through them. How do I get it to stop? I have a feeling I'm missing something small.
So here's the code:
from Tkinter import *
import ttk
root = Tk()
def iterate(number):
return number + 1
inputs = open("inputs.txt").readlines
lines = inputs()
numlines = len(lines)
x=0
for tq in lines:
sentence = lines[x].strip('\n')
sen = StringVar()
sen.set(sentence)
x = iterate(x)
ttk.Label(textvariable = sen).grid(column=1, row=1, columnspan=99)
ttk.Button(text = "next", command = x).grid(column=99, row=5, pady=5)
root.update()
root.mainloop()

To change what is displayed in a label you can call the configure method, giving it any of the same arguments you give when you create it. So, you would create a single label, then call this method to modify what is displayed.
The basic logic looks like this:
def do_next():
s = get_next_string_to_display()
the_label.configure(text=s)
the_label = ttk.Label(...)
the_button = ttk.Button(..., command=do_next)

This is the code I ultimately used to solve the issue:
from Tkinter import *
import ttk
root = Tk()
root.title("This space intentionally left blank")
root.minsize(800,200)
mainframe = ttk.Frame(root)
mainframe.grid(column = 0, row = 0)
def nextInputs(*args):
sen.set(inputs())
inputs = open("inputs.txt").readline
sen = StringVar()
ttk.Label(mainframe, textvariable=sen).grid(column=1, row=1, columnspan=99)
Button = ttk.Button(mainframe, text = "next", command = nextInputs).grid(column=99, row=5, pady=5)
root.bind('<Return>', nextInputs)
root.mainloop()

Related

How to display the updated text value without erasing the label text in python tkinter?

I am new to tkinter. I have tried the below program. It's working fine. Is there any way I can get the number of character without erasing the label text?
import tkinter as tk
my_w = tk.Tk()
from tkinter import *
my_w.geometry("400x150") # Size of the window width x height
my_w.title("plus2net.com") # Adding a title
Generator = tk.Frame(my_w)
Generator.pack(padx=10, pady=10, fill='x', expand=True)
e1_str=tk.StringVar()
e1_str=tk.StringVar() # declaring a StringVar()
e1 = tk.Entry(Generator,textvariable=e1_str,bg='yellow',font=28) # Entry box
e1.pack(padx=0,fill='x', expand=True)
l1 = tk.Label(Generator, text='No of Chars here' ,font=28) # added one Label
l1.pack(padx=0,fill='x', expand=True)
def my_upd(*args):
l1.config(text=str(len(e1_str.get()))) # read & assign text to StringVar()
e1_str.trace('w',my_upd) # triggers on change of StringVar
my_w.mainloop()
Update text property in your label to: f'No of Chars here: {len(e1_str.get())}':
import tkinter as tk
my_w = tk.Tk()
my_w.geometry("400x150")
my_w.title("plus2net.com")
Generator = tk.Frame(my_w)
Generator.pack(padx=10, pady=10, fill='x', expand=True)
e1_str = tk.StringVar()
e1 = tk.Entry(Generator, textvariable=e1_str, bg='yellow', font=28)
e1.pack(padx=0, fill='x', expand=True)
l1 = tk.Label(Generator, text='No of Chars here', font=28)
l1.pack(padx=0, fill='x', expand=True)
def my_upd(*args):
l1.config(text=f'No of Chars here: {len(e1_str.get())}')
e1_str.trace('w', my_upd) # triggers on change of StringVar
my_w.mainloop()
Output:
You get number of characters by e1_str.get()
For example you could modify your function:
def my_upd(*args):
t = e1_str.get()
if t:
l1.config(text='Number of Chars here: ' + str(len(t)))
else:
l1.config(text='No of Chars here')

python issue adds a new label

take a look at this code
well it happens to just add another label for no reason
import tkinter
from tkinter import *
clicks = 1
def click_count():
global clicks
# making the label that shows how many idk you have
label = Label(frame, text="you have " + str(clicks), font=(('Courrier'), 32))
label.pack()
clicks += 1
label.pack()
#generating the window
root = tkinter.Tk()
root.geometry('500x500')
#making the expandable frame
frame = Frame(root)
frame.pack(expand=YES)
#making the button
button = Button(frame, text= "click", font=(('Courrier'), 32), command=click_count)
button.pack()
root.mainloop()
and then i tried this
and i also tried to remove the label.pack at the end
but it still does the same thing which is adding another label
import tkinter
from tkinter import *
clicks = 1
def click_count():
global clicks
# making the label that shows how many idk you have
label = Label(frame, text="you have " + str(clicks), font=(('Courrier'), 32))
label.pack()
label.destroy()
clicks += 1
label.pack()
#generating the window
root = tkinter.Tk()
root.geometry('500x500')
#making the expandable frame
frame = Frame(root)
frame.pack(expand=YES)
#making the button
button = Button(frame, text= "click", font=(('Courrier'), 32), command=click_count)
button.pack()
root.mainloop()
i was expecting it to add a nmber to the label but it just shows another label
It does not add a Label for no reason. It adds the label because that's what your function tells it to do. Each time you click the button, the function is executed that creates and packs a new Label.
What you should do is create the label at the onset and link it to a variable. Then, you can change the value of this variable in the function.
Also, you don't have to import tkinter twice and it's sensible to update the clicker first and then display the result instead of showing the last value it had. Your approach works in such a small program but the value of clicks will always be one higher than displayed. So, you may get into problems when you use the value.
from tkinter import *
def click_count():
global clicks
clicks += 1
click_counter.set("you have " + str(clicks))
#Initiate root
root = Tk()
root.geometry('500x500')
#Set initial values for click counter
clicks = 0
click_counter = StringVar()
click_counter.set("you have 0")
#making the expandable frame
frame = Frame(root)
frame.pack(expand=YES)
# making the label that shows how many idk you have
label = Label(frame, textvariable=click_counter, font=(('Courrier'), 32)) ## The label gets updated, whenever the value of click_counter changes.
label.pack()
#making the button
button = Button(frame, text= "click", font=(('Courrier'), 32), command=click_count)
button.pack()
root.mainloop()

How to change values from a matrix GUI tkinter?

I want to change a number from a matrix and then display it in the same tk window, but I find it hard to work with variables from an input. The r[][] should be the matrix formed with the user's input. And after all I have to display the matrix with the modification: r[0][1] += 5, in the same tk window.
from tkinter import *
import numpy as np
root = Tk()
def process():
values = [e1.get(),e2.get(),e3.get(),e4.get()]
a = np.zeros((2,2),dtype=np.int64)
for i in range(2):
for j in range(2):
a[i][j] = values[i*2+j]
print(a)
e1 = Entry(root)
e2 = Entry(root)
e3 = Entry(root)
e4 = Entry(root)
e1.grid(row=0,column=0,padx=10,pady=10)
e2.grid(row=0,column=1)
e3.grid(row=1,column=0,padx=10,pady=10)
e4.grid(row=1,column=1)
b = Button(root,text='Process',command=process)
b.grid(row=2,column=0,columnspan=4,sticky=E+W)
root.mainloop()
r=[[e1.get(),e2.get()],[e3.get(),e4.get()]]
r[0][1] += 5
Tkinter GUI programs are event-driven which requires using a different programming paradigm than the one you're probably familiar with which is called imperative programming. In other words, just about everything that happens is done in response to something the user has done, like typing on the keyboard, clicking on a graphical button, moving the mouse, etc.
I think the code below will give you a good idea of how to do what you want in a framework like that. It creates a StringVar for each Entry widget, which has the advantage what's displayed in each Entry will automatically be updated whenever the corresponding StringVar is changed (make that more-or-less automatic).
To determine which StringVar is associated with a given Entry, a separate dictionary is created which maps the internal tkinter variable name to corresponding Python variable. The internal tkinter variable name is obtained by using the universal cget() widget method.
import tkinter as tk
from tkinter.constants import *
ROWS, COLS = 2, 2
def process(entry_widgets, row, col):
var_name = entry_widgets[row][col].cget('textvariable')
var = root.variables[var_name]
try:
value = float(var.get())
except ValueError: # Something invalid (or nothing) was entered.
value = 0
var.set(value+5) # Update value.
root = tk.Tk()
# Create a grid of Entry widgets.
entries = []
root.variables = {} # To track StringVars.
for x in range(COLS):
row = []
for y in range(ROWS):
var = tk.StringVar(master=root) # Create variable.
root.variables[str(var)] = var # Track them by name.
entry = tk.Entry(root, textvariable=var)
entry.grid(row=x, column=y)
row.append(entry)
entries.append(row)
btn = tk.Button(root, text='Process', command=lambda: process(entries, 0, 1))
btn.grid(row=2, column=0, columnspan=COLS, sticky=E+W)
root.mainloop()
Would this be what you're looking for? I deleted a bunch of code that seems to do nothing in context -- you just want to replace the text in the corner box right?
from tkinter import *
def process():
replace(e4)
def replace(entry_loc):
temp = int(entry_loc.get())
temp += 5
entry_loc.delete(0,500)
entry_loc.insert(0, temp)
root = Tk()
var_e1 = StringVar
var_e2 = StringVar
var_e3 = StringVar
var_e4 = StringVar
e1 = Entry(root, textvariable=var_e1)
e2 = Entry(root, textvariable=var_e2)
e3 = Entry(root, textvariable=var_e3)
e4 = Entry(root, textvariable=var_e4)
e1.grid(row=0, column=0, padx=10, pady=10)
e2.grid(row=0, column=1)
e3.grid(row=1, column=0, padx=10, pady=10)
e4.grid(row=1, column=1)
b = Button(root, text='Process', command=process)
b.grid(row=2, column=0, columnspan=4, sticky=E + W)
root.mainloop()

tkinter - Changing variables assigned to labels causes duplicate window

I'm using python to interact with some excel spreadsheets. I have all that working and now I'm working on a UI using tkinter. I have 3 buttons one to pull the location of a data file, output file save location and I have a start button.
I'm trying to use a tkinter.Label to display the value of the first two buttons, example "c:/user/data_file". However, when ever I get the variable from the user and try to update the GUI with it, a copy of the window is created with the updated information. I need it to update directly to the current window seamlessly. I've been working to try to resolve this, but I just can't figure it out. Below is the code for my tkinter stuff.
def main():
def InputFilePrompt():
global InputFileLocation
InputFileLocation = askopenfilename()
update()
def OutputFilePrompt():
global OutputFileLocation
OutputFileLocation = filedialog.asksaveasfilename()
update()
def update():
root = Tk()
root.title("test")
root.resizable(width=TRUE,height=TRUE)
InputFile = Button(root, text = "input data", command = InputFilePrompt)
InputFile.grid(row = 0,column = 0)
InputFileValue = Label(root, text = InputFileLocation, bg = 'white')
InputFileValue.grid(row = 1,column = 0)
OutputFile = Button(root, text = "Compiled Data save loacation", command = OutputFilePrompt)
OutputFile.grid(row = 4,column = 0)
OutputFileValue = Label(root, text = "location: N/A", bg = 'white')
OutputFileValue.grid(row = 5,column = 0)
startButton = Button(root, text = "start", bg = 'light green', command = Excel)
startButton.grid(row = 7)
BlankUI = [0 for x in range(2)]
for blankspace in range(2):
BlankUI[blankspace] = Label(root, text = "")
BlankUI[0].grid(row = 2)
BlankUI[1].grid(row = 6)
root.mainloop()
update()
Error:
Here's a version that doesn't create the duplicate window. I've incorporated most of the suggestions I made in comments—except for the one about defining functions inside of other functions. The following still does this because doing so made it very easy to avoid using global variables (which are generally considered a poor programming practice).
Notice that there's no update() function. The values of the two tkinter.Labels are now being stored in two tkinter.StringVars objects instead of in regular Python strings. A StringVar is one of the tkinter so-called "Variable" classes. Their primary feature is that they will cause all widgets referencing them to automatically update themselves whenever their contents get changed. To use them in a Label, they're specified by using the textvariable= option (instead of the text= option) when the constructor is called.
Here's some documentation I found about them with more details on how they work.
import tkinter as tk
from tkinter.filedialog import askopenfilename, asksaveasfilename
def excel():
""" Undefined. """
pass
def main():
def get_input_file_location():
input_file_location.set(askopenfilename())
def get_output_file_location():
output_file_location.set(asksaveasfilename(confirmoverwrite=False))
root = tk.Tk()
root.title('test')
root.resizable(width=True, height=True)
input_file_location = tk.StringVar()
input_file_location.set('<undefined>')
output_file_location = tk.StringVar()
output_file_location.set('<undefined>')
input_file = tk.Button(root, text="Input data",
command=get_input_file_location)
input_file.grid(row=0, column=0)
input_file_value = tk.Label(root, textvariable=input_file_location,
bg='white')
input_file_value.grid(row=1, column=0)
output_file = tk.Button(root, text='Compiled data save loacation',
command=get_output_file_location)
output_file.grid(row=4, column=0)
output_file_value = tk.Label(root, textvariable=output_file_location,
bg='white')
output_file_value.grid(row=5, column=0)
startButton = tk.Button(root, text='start', bg='light green',
command=excel)
startButton.grid(row=7)
blank_ui = [tk.Label(root, text='') for _ in range(2)]
blank_ui[0].grid(row=2)
blank_ui[1].grid(row=6)
root.mainloop()
if __name__ == '__main__':
main()

How to control the tkinter combobox selection highlighting

I wrote a small farad converter to learn GUI programming. It works great, looks fine-ish. The only problem is I can't seem to figure out how to control this strange highlighting that comes up on my ttk.Combobox selections. I did use a ttk.Style(), but it only changed the colors of the ttk.Combobox background, entries, etc. I also tried changing openbox/gtk themes.
I'm talking about what's seen there on the text "microfarads (uF)".
It'd be fine, if it highlighted the entire box; but I'd rather have it gone completely.
How can I manipulate a ttk.Combobox's selection highlight?
# what the farad?
# thomas kirkpatrick (jtkiv)
from tkinter import *
from tkinter import ttk
# ze la programma.
def conversion(*args):
# this is the numerical value
inV = float(inValue.get())
# these two are the unit (farads, microfarads, etc.) values
inU = inUnitsValue.current()
outU = outUnitsValue.current()
# "mltplr" is multiplied times inValue (inV)
if inU == outU:
mltplr = 1
else:
mltplr = 10**((outU - inU)*3)
outValue.set(inV*mltplr)
# start of GUI code
root = Tk()
root.title("What the Farad?")
# frame
mainFrame = ttk.Frame(root, width="364", padding="4 4 8 8")
mainFrame.grid(column=0, row=0)
# input entry
inValue = StringVar()
inValueEntry = ttk.Entry(mainFrame, width="20", justify="right", textvariable=inValue)
inValueEntry.grid(column=1, row=1, sticky="W")
# input unit combobox
inUnitsValue = ttk.Combobox(mainFrame)
inUnitsValue['values'] = ('kilofarads (kF)', 'farads (F)', 'millifarads (mF)', 'microfarads (uF)', 'nanofarads (nF)', 'picofarads (pF)')
inUnitsValue.grid(column=2, row=1, sticky="e")
inUnitsValue.state(['readonly'])
inUnitsValue.bind('<<ComboboxSelected>>', conversion)
# result label
outValue = StringVar()
resultLabel = ttk.Label(mainFrame, textvariable=outValue)
resultLabel.grid(column=1, row=2, sticky="e")
# output unit combobox
outUnitsValue = ttk.Combobox(mainFrame)
outUnitsValue['values'] = ('kilofarads (kF)', 'farads (F)', 'millifarads (mF)', 'microfarads (uF)', 'nanofarads (nF)', 'picofarads (pF)')
outUnitsValue.grid(column=2, row=2, sticky="e")
outUnitsValue.state(['readonly'])
outUnitsValue.bind('<<ComboboxSelected>>', conversion)
# padding for widgets
for child in mainFrame.winfo_children(): child.grid_configure(padx=4, pady=4)
# focus
inValueEntry.focus()
# bind keys to convert (auto-update, no button)
root.bind('<KeyRelease>', conversion)
root.mainloop()
Could it be that with a readonly combobox the problem is not the selection but the relatively strong focus-indicator?
With this workarround you lose the ability to control your program by keyboard. To do it right you would have to change the style of the focus-highlighting.
from tkinter import *
from ttk import *
def defocus(event):
event.widget.master.focus_set()
root = Tk()
comboBox = Combobox(root, state="readonly", values=("a", "b", "c"))
comboBox.grid()
comboBox.set("a")
comboBox.bind("<FocusIn>", defocus)
mainloop()
You can use the Combobox's selection_clear() method to clear the selection whenever you want.
e.g
inUnitsValue.selection_clear()
Just refresh the selected value of the Combobox.
This will help for removing the highlight.
import tkinter.ttk
import tkinter
items = ["test1","test2","test3","test4"]
class TkCombobox(tkinter.ttk.Combobox):
def __init__(self, *arg, **kwarg):
super(TkCombobox, self).__init__(*arg, **kwarg)
self._strvar_ = tkinter.StringVar()
self._strvar_.set("")
self["textvariable"] = self._strvar_
self.bind("<<ComboboxSelected>>", self.highlight_clear)
def highlight_clear(self, event):
current = self._strvar_.get()
self.set("")
self.set(current)
master = tkinter.Tk();master.geometry("400x400")
c = TkCombobox(master, values=items, state="readonly")
c.pack()
master.mainloop()

Categories