How do you change the output to lowercase in Tkinter? - python

I'm using Tkinter in python for the first time.
I'm trying to make the output the user has entered lowercase.
So if the enter "TEST" the output would be "test"
My code is:
from tkinter import *
# event functions (10:30 mins)
def onClickSubmitButton(): # submit button event handler
userEnteredText = textbox.get() # get the enterd text from the Entry text box
outputTextField.delete(0.0, END) # (14:30 mins)delete all of the output field text contents
outputTextField.insert(END, userEnteredText) # (15:50 mins) output the user eneterd text
#main window (1:30 mins)
window = Tk()
window.title("Python Glossary")
window.configure(background="white")
# display text using - Label (05:30 mins)
Label(window, text="Enter a string and press submit", bg="white", font="none 12 bold").grid(row=1,column=0,sticky=W) # using grid layout
# textbox for text entry - Entry (8:15 mins)
textbox = Entry(window, width=20, bg="white")
textbox.grid(row=2, column=0,sticky=W) # grid position of textbox
# submit button - Button (9:30 mins) - calls onClickSubmitButton function when clicked
Button(window, text="SUBMIT", width=6, command=onClickSubmitButton ).grid (row=2,column=1, sticky =W)
#definitions - Label (11:50 mins)
Label(window, text="\n Your string", bg="white", font="none 12 bold").grid(row=4,column=0,sticky=W) # using grid layout
# output textField - Text(12:40 mins)
outputTextField = Text(window, width=75, height=6, wrap=WORD, background="white",)
outputTextField.grid(row=4, column=1,sticky=W) # grid position of textField
# run the main loop
window.mainloop()
I tried:
outputTextField.insert.lower(END, userEnteredText)
but that didn't work. Any advice?

If you do outputTextField.insert(END, userEnteredText.lower()) then the entered text will be converted to lower case and then the insert function works as expected, taking the lowercase string as an argument.

in the most cases of these string methods you need to know, that you need to
make a new variable for it.
def onClickSubmitButton(): # submit button event handler
userEnteredText = textbox.get() # get the enterd text from the Entry text box
low = userEnteredText.lower()
outputTextField.delete(0.0, END) # (14:30 mins)delete all of the output field text contents
outputTextField.insert(END, low) # (15:50 mins) output the user eneterd text

So here is a bit fancier option (I don't know if You need something like this but it also does what You ask for except no button has to be pressed to change characters to lowercase, in this case it will do that as the user is typing, try it out):
from tkinter import Tk, Text
def lower_input(event):
if not event.char or r'\x' in repr(event.char):
return
text.delete('insert-1c')
text.insert('insert', event.char.lower())
root = Tk()
text = Text(root)
text.pack()
text.bind('<Key>', lambda e: root.after(1, lower_input, e))
root.mainloop()
Basically it just binds the "<Key>" event to the text widget which means that when any key is pressed (and the focus is on the text widget) the event will be triggered which will then call the given function. Also .bind passes an event argument so that should be handled even if not used however here it is used to detect the character or to stop the function if the pressed key does not have a character (e.g. "Caps Lock" or "Backspace" (which actually has a bytes type thingy so that is why there is also the other comparison of r"\x" in repr(event.char))). Then it just deletes the just written character and places a new one that is in lower case in its place. The root.after is used because the event is called before the character is typed to the Text widget meaning incorrect indexes are used so there is a tiny delay (1 ms) so that the character can appear on the screen and then the indexing happens.
EDIT: it is also possible to add or event.char.islower() (if that doesn't work could also try or not event.char.isupper()) to that if statement to increase the performance a little bit since it won't go through the replacing process if the character is already lowercase
EDIT 2: as per PEP8 You should use snake_case for naming variables and functions and NOT camelCase
Useful sources/docs:
this one specifically about indexes but contains a lot of other very useful stuff too
simple docs I like to use

Related

Python Tkinter: How do you loop through a list and display items on a new line in a new root

I am building a translation app using tkinter, and I am trying to get the translated results to appear on a new line in a new root window. So if the user translates
one
two
three
The new tkinter root window should show
uno
dos
tres
Here is the function that displays the translated words
def display_translated(text_to_trans):
root2 = Tk() # new root window
root2.title('Translated text')
root2.geometry('200x200')
label2 = Label(root2, text='This is the translated text') # label to explain what the root window is showing
label2.pack()
display_words = [] # list of empty words that will be appended with the list of translated words that was passed to the function
for item in text_to_trans:
display_words.append(item.text)
textbox1 = Text(root2, height=10, width=20, font=("Arial", 20), bg='yellow')
textbox1.pack()
textbox1.insert(1.0, display_words)
My guess is that the issue is with the way that I am displaying the words on the screen (the display_words list), but I am unsure of a better way to do this to get the translated words.
EDITED: When I am getting instead is
uno dos tres.
You need to explicitly insert a newline between each element. The simplest way is with join:
textbox1.insert("1.0", "\n".join(display_words))

How to identify labels on a Python Tkinter Tab in the event handler

I am placing labels on a Tab in Tkinter with a for loop. How can I identify in the event handler which label was clicked (or its loop index)? I guess it is functionally similar to a ListBox but without the formatting restrictions. I might want to put the labels in a circle or place them diagonally. I tried finding the coordinates of the label but these are available only if the tab is the first one visible or the tab is redrawn when made active. Also the x, y passed in the event handler is the x, y within the label which does not help to identify the label.
I could copy the label code about 10 times and and have about 10 event handlers. This would work but this is no longer 1970!
Perhaps I could bind a handler to the tab canvas and identify the label from its coordinates. The label would need to be on the first tab or the tab drawn when active.
Perhaps I could create a different event handler for each label by holding the event handlers in an array. I would need an event handler for each label. The code would need to change if the number of labels changed.
I am currently trying a label with ''. Would using buttons with command be easier?
What simple part of Python am I missing? I cannot be the first person to need this! Any help or advice would be appreciated.
You can save a reference to the label text for each label widget in a dict.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry('+800+50')
notebook = ttk.Notebook(root, width=300, height=200, padding=[10,10,10,10])
notebook.pack()
tab_one = tk.Frame(notebook, bg='wheat')
notebook.add(tab_one, text='Cheese', padding=[10,10,10,10])
tab_two = tk.Frame(notebook, bg='mint cream')
notebook.add(tab_two, text='Misc.', padding=[10,10,10,10])
def clicked(event):
print('Clicked:', name_dict[event.widget])
# Populating Cheese tab with clickable Labels
name_list = ['Cheddar', 'Ilchester', 'Limburger']
name_dict = {}
for index, name in enumerate(name_list):
a = tk.Label(tab_one, width=10, text=name, bg='peru')
a.grid(row=index, column=0, padx=5, pady=5)
name_dict[a] = name # Save references in a dict
a.bind('<Button-1>', clicked)
tk.Label(tab_two, text='Just some text...', bg='powder blue').pack(anchor='nw')
root.mainloop()
Is this what you had in mind?
When you bind events, the function receives an object that includes a reference to the widget that received the event. In the following example, notice how it uses event.widget to refer to the widget that was clicked on.
import tkinter as tk
def update_label(event):
event.widget.configure(text="You clicked me")
root = tk.Tk()
for i in range(10):
l = tk.Label(root, text="Click me", width=20)
l.pack()
l.bind("<1>", update_label)
root.mainloop()

Remove the default 0 in in integer entry in Tkinter

I am learning to do a GUI using tkinter and I create an integer entry which is working fine except that whenever I run my program the number 0 is already put in the entry, is there anyway to remove it and just have nothing instead? It doesn't do that with strings
I checked answers like this one: https://stackoverflow.com/a/39879154/13061992
but I didn't work (the user already has said that is only for strings but I gave it a shot anyway)
To explain more, I am creating a text box using the following:
tries_var = tk.IntVar()
tries_label = tk.Label(root, text='Number Of Tries', font=('calibre', 10, 'bold'))
tries_entry = tk.Entry(root, textvariable=tries_var, font=('calibre', 10, 'normal'))
tries_label.grid(row=2, column=0)
tries_entry.grid(row=2, column=1)
When I run the program I have 0 written by default, like this:
I want to get rid of this and instead have the box to be empty, any help would be appreciated.
The reason for this is, you are using tk.IntVar() which by default will put a 0 onto the Entry widget. To get rid of this, change tk.IntVar() to tk.StringVar().
tries_var = tk.StringVar()
Though keep in mind, tk.IntVar.get() will return int, now that you are using tk.StringVar, you might need int(tk.StringVar.get()), given that your input is completely numbers.
print(int(tries_var.get()) # Given that, your input is entirely numbers
Try this:
import tkinter as tk
def only_allow_numbers(event):
char = event.char.lower()
if (event.state & 4) >> 2:
# If ctrl is also pressed:
# Check and handle Ctrl+c, Ctrl+v, Ctrl+x
# For now I will just allow it
return None
if char.isprintable() and (not event.char.isdigit()):
return "break"
root = tk.Tk()
entry = tk.Entry(root)
entry.pack()
entry.bind("<Key>", only_allow_numbers)
root.mainloop()
It uses bindings. When you return "break" from a binding that key is ignored (isn't inserted in the entry.)

Python - User input - start function automatically after entering 7 digits

I am struggling to find the correct search terms to find an answer to my question. I have a program that is working, but I am trying to minimize the number of clicks required to make it work. I have a tkinter interface that takes a 7 digit input and looks it up in a spreadsheet and then displays some relevant information. Right now, the user scans a barcode which puts 7 digits in an entry box like this:
workorder = tk.Entry(root)
workorder.focus()
canvas1.create_window(175, 800, window=workorder)
Then, the user has to press the enter key to start the function that uses those 7 digits:
def f1(event):
getPartNumber()
root.bind('<Return>', f1)
I am trying to find a way to start the function automatically so a keyboard is not required. I was trying to do something like:
if len(str(workorder)) == 7:
getPartNumber()
However, it seems like this only works to check the length of an entry after the entry has been made. Is it possible to check on the state of the entry box before the entry is made?
You can associate a variable with the entry widget, and then set a trace on the variable. The trace will call a function whenever the data in the widget changes. Inside the trace you can examine the length of the data and call a function when the length is 7.
Here's an example that updates a label when you enter 7 characters:
import tkinter as tk
root = tk.Tk()
var = tk.StringVar()
entry = tk.Entry(root, textvariable=var)
label = tk.Label(root, text="", anchor="w")
entry.pack(side="top", fill="x")
label.pack(side="top", fill="x")
def boom(*args):
if len(var.get()) == 7:
label.configure(text="Boom!")
var.trace("w", boom)
root.mainloop()

Tkinter: Adding and self-deleting buttons in list | Adding works, Deleting not

I am just in the middle of creating an entry form for a program, and it seems that I have got stuck with the logic on this one.
Basically I wanted to design a dropdwon-list, which adds words to an array and displays these words as little buttons beneath it. When you click the buttons they disappear again and remove themselfs from the array.
Simple enough, I thought. The adding worked fine so far. But removing not so much... There is a logic error with the button array and I can't seem to figure it out!
I extracted the code for reviewing,
any help is greatly appreciated!
Word adding Window
import tkinter as tk
from tkinter import ttk
def rel_add(*args):
rel_array.append(tkvar.get())
print(rel_array)
rel_buttons_update()
def del_button(i):
print(i)
del rel_array[i]
print(rel_array)
rel_buttons[i].grid_remove()
# del rel_buttons[i]
rel_buttons_update()
def rel_buttons_update():
for i, rel in enumerate(rel_array):
rel_buttons.append(tk.Button(rel_grid, text=rel, font="Helvetica 7", command=lambda c=i: del_button(c)))
rel_buttons[i].grid(column=i, row=0, sticky="nw")
rel_array = []
rel_buttons = []
win = tk.Tk()
tkvar = tk.StringVar(win) # Create a Tkinter variable
choices_words = ["oolbath", "pflanze", "haus", "wasser", "brimbambum"] # Create Variable List
tkvar.set('Related Words...') # set the default option
choices_words.sort() # Sort List
tk.Label(win, text="Related Words: ").grid(row=0,column=0, sticky="w")
rel = tk.OptionMenu(win, tkvar, *choices_words)
rel.grid(row=0,column=1, sticky="w")
# Callbuck Function for Dropdwon Menu
tkvar.trace("w", rel_add)
rel_grid = tk.Frame(win)
# Display the Buttons for the related Words
rel_grid.grid(row=1,column=1, sticky="w")
win.mainloop()
The main problem is that you keep recreating the same buttons over and over, so rel_buttons contains many more elements than you expect.
As a simple experiement, add a print statement to rel_buttons_update like this:
def rel_buttons_update():
for i, rel in enumerate(rel_array):
rel_buttons.append(ttk.Button(rel_grid, text=rel, command=lambda c=i: del_button(c)))
rel_buttons[i].grid(column=i, row=0, sticky="nw")
print('in update, rel_buttons is now', rel_buttons)
You'll notice that there is one button the first time you use the option menu, three buttons the second time, six buttons the third time, and so on.
You need to either only create new buttons, or delete all the old buttons before recreating them.

Categories