Reducing entry letters using tkinter not working - python

The entry widget in my programme for numbers is working correctly to only allow a maximum of 3 numbers while I tried to do the same thing in a different entry widget but for characters the limit isn't working, I've got no clue why. Do you have to it in a different way since you're using letters?
Here is my code:
def only_letters_max_86(action, char):
if action == "1":
# a character is inserted (deletion is 0) allow the insertion
# only if the inserted character char is a letter
return char.isalpha() and len(char) <= 86
else:
# allow deletion
return True
def only_numbers_max_3(action, new_text):
if action == "1":
return new_text.isdigit() and len(new_text) <= 3
else:
return True
def main():
validate_letter = window.register(only_letters_max_86)
validate_nb = window.register(only_numbers_max_3)
label = Label(window, width = 30, background = 'lightgreen', text='enter temperature, only numbers')
label.grid(row=0, column=0)
entry_tempp = Entry(window, width = 30, validate="key", validatecommand=(validate_nb, '%d', '%P'))
entry_tempp.grid(row = 0, column = 1)
#create another label and entry object for location
label_numb = Label(window, width = 30, background = 'lightgreen', text='enter location, only letters')
label_numb.grid(row=1, column=0)
entry_locations = Entry(window, width = 30, validate="key", validatecommand=(validate_letter, '%d', '%S', '%v'))
entry_locations.grid(row = 1, column = 1)

On this line:
entry_locations = Entry(window, width = 30, validate="key", validatecommand=(validate_letter, '%d', '%S', '%v'))
You are passing '%S' to your validate_letter function which looking at the docs means:
'%S': If the call was due to an insertion or deletion, this argument will be the text being inserted or deleted.
So my guess is that char in only_letters_max_86(action, char) only gets the character that is being inserted which will always be of length one, causing your check to fail. Try changing %S to %Pwhich gives you:
'%P': The value that the text will have if the change is allowed.
Link to the docs: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/entry-validation.html

Related

add a clear button to the GUI which clears the output formatted by the user

I am trying to clear the output displayed When clicked the CLEAR button should 'clear' or remove any text written in the Entry box and any text displayed on the Label. While attempting this on my own I tried using the delete method and del both of which did not remove the output when the button is pressed
from tkinter import *
import random
def generate_name_box():
n = input_string_var.get()
s = ""
s += "+" + "-"*len(n) + "+\n"
s += "|" + n + "|\n"
s += "+" + "-"*len(n) + "+\n"
name_string_var.set(s)
def clear_name_box():
#MAIN
#Generate holding structures for GUI
root = Tk()
mainframe = Frame(root)
#Other variables
font_colour = '#EE34A2'
#Create the widgets and associated Vars
name_string_var = StringVar()
name_label = Label(mainframe, text = "", font = ("Courier", 50), textvariable=name_string_var, fg=font_colour)
instruction_label = Label(mainframe, text="Enter your name", font=("Courier", 20))
greeting_button = Button(mainframe, text ="FORMAT", font=("Courier", 20), command=generate_name_box)
clear_button = Button(mainframe, text="CLEAR", font=("Courier",20), command= clear_name_box)
input_string_var = StringVar()
input_entry = Entry(mainframe, textvariable=input_string_var)
#Grid the widgets
#############
root.minsize(450, 400)
mainframe.grid(padx = 50, pady = 50)
instruction_label.grid(row = 1, column = 1, sticky=W)
input_entry.grid(row = 2, column = 1, sticky=W)
greeting_button.grid(row = 3, column = 1, ipadx=55, ipady=10, sticky=W)
clear_button.grid(row=4,column = 1, ipadx= 55, ipady= 20, sticky=W)
name_label.grid(row = 5, column = 1, sticky=W)
root.mainloop()
To clear the text in the Entry widget, you can use the delete method and specify the indices of the characters that you want to delete. For example, to delete all the text in the Entry widget, you can use the following code:
def clear_name_box():
input_entry.delete(0, 'end')
This code will delete all the text from the beginning (index 0) to the end ('end') of the text in the Entry widget.
To clear the text in the Label widget, you can use the config method to change the text attribute of the Label to an empty string. For example:
def clear_name_box():
input_entry.delete(0, 'end')
name_label.config(text="")
This code will clear the text in both the Entry and Label widgets when the clear_name_box function is called.
Since you have used tkinter StringVar for both the formatted output and entry box, just set them to empty string to clear the entry box and the formatted output:
def clear_name_box():
input_string_var.set('')
name_string_var.set('')

How to fix positioning of labels in tkinter?

So I am trying to have a GUI for my Converter (it is intentionally meant to go up to 255 aka 8bits)
And I have got it to work on the button layout as planned. But to make it more user-friendly I wanted to put a 'Convert From' label/text above the buttons. However, as soon as I shifted the buttons down a row it didn't go as planned and after careful examination of it. I have got nowhere.
image reference of how it looks without label above the buttons (row = 0)
image reference of how it looks with the label above the buttons
as you can see it takes it off screen and out of uniform (row = 1)
#Converter GUI
#importing necessary libaries
import tkinter
import tkinter.ttk
import tkinter.messagebox
import sys
#defining the types of conversion
def bin2den(value):
if len(value) != 8: #checks that it has a length of 8 binary digits
return "None"
return int(value, 2)
def bin2hex(value):
if len(value) != 8: #checks that it has a length of 8 binary digits
return "None"
Ox = hex(int(value, 2))[2:].upper()
Ox = Ox.zfill(2)
return Ox
def bin2bin(value):
if len(value) != 8: #checks that it has a length of 8 binary digits
print("Invalid input, 8 bits required!")
return "None"
return value.zfill(8)
def den2bin(value):
if int(value) > 255 or int(value) < 0:
return "None"
Ob = bin(int(value))[2:]#removing the ob prefix
filled = Ob.zfill(8) #filling it to become an 8 bit binary if worth less than 8 bits
return filled
def den2hex(value):
if int(value) > 255 or int(value) < 0:
return "None"
Ox = hex(int(value))[2:].upper() #removing the ox prefix and capitalising the hex output
Ox = Ox.zfill(2)#filling the output if not double digits
return Ox
def den2den(value):
if int(value) > 255 or int(value) < 0:
print("Out Of Range")
return "None"
return value
def hex2bin(value):
while len(value) != 2 and len(value) > 2: #checking if hex value outside of ff
return "None"
Ob = bin(int(value, 16))[2:] #removing the ob prefix
Ob = Ob.zfill(8)#filling binary to be 8bits if value is below 8 bits
return Ob
def hex2den(value):
while len(value) != 2 and len(value) > 2: #checking if hex value outside of ff
return "None"
return int(value, 16)
def hex2hex(value):
while len(value) != 2 and len(value) > 2: #checking if hex value outside of ff
print("Invalid input, try again")
return "None"
value = value.upper() #capitaliseing for formality
return value
def readFile(fileName):
fileObj = open(fileName, "r")#opens file in read only mode
HexArray = fileObj.read().splitlines()#puts file into an array
fileObj.close()
return HexArray
#setting main window class
#and defining main attributes of the window
class MainWindow():
FONT = ("Consolas", 16)
TxtMaxLen = 32
def __init__(self):
self._window = tkinter.Tk()
self._window.title("Converter")
#self._window.geometry("800x240") redundant as set below due to positioning
self._window["bg"] = "#20A3FF" #background colour
self._window.resizable(False, False) #stops the window being resized
windowWidth = self._window.winfo_reqwidth()
windowHeight = self._window.winfo_reqheight()
# Gets both half the screen width/height and window width/height
positionRight = int(self._window.winfo_screenwidth()/2 - windowWidth/2)-330
positionDown = int(self._window.winfo_screenheight()/2 - windowHeight/2)-200
self._window.geometry(f"{windowWidth}x{windowHeight}+{positionRight}+{positionDown}")
self._window.geometry("800x240")#setting window size
label = tkinter.Label(self._window, text="Number: ", font=MainWindow.FONT)#label defined for number input box
label.grid(row=0, column=0, padx=10, pady=5)#positioning / dimensions of input box
self._txt_input = tkinter.Entry(self._window, width=MainWindow.TxtMaxLen, font=MainWindow.FONT) #defined input box
self._txt_input.grid(row=0, column=1, pady=5)#postioning / dimensions of input box
self._txt_input.focus()
#this is the label that is just runining it
#label = tkinter.Label(self._window, text="Convert From ", font=MainWindow.FONT)
#label.grid(row=0, column=2, padx=5, pady=5)#positioning / dimensions of input box
#following 6 bits of code when row = 0 it works fine but when shifted down a row it goes wrong
self._bt_bin = tkinter.Button(self._window, text="Bin", font=MainWindow.FONT, command=self.BinSelection)#button defined for bin
self._bt_bin.grid(row=0, column=2, padx=5, pady=5)#postioning / dimensions of button box
self._bt_den = tkinter.Button(self._window, text="Den", font=MainWindow.FONT, command=self.DenSelection)#button defined for den
self._bt_den.grid(row=0, column=4, padx=5, pady=5)#postioning / dimensions of button box
self._bt_hex = tkinter.Button(self._window, text="Hex", font=MainWindow.FONT, command=self.HexSelection)#button defined for bin
self._bt_hex.grid(row=0, column=6, padx=5, pady=5)#postioning / dimensions of button box
separator = tkinter.ttk.Separator(self._window,orient=tkinter.HORIZONTAL)
separator.grid(row=1, column=1, pady=4)
#setting the Output boxes and the labels accordingly
#binary output box and label
label = tkinter.Label(self._window, text="Binary:", font=MainWindow.FONT)#label defined for number box
label.grid(row=2, column=0, padx=10, pady=5)
self._stringvar_bin = tkinter.StringVar()
txt_output = tkinter.Entry(self._window, textvariable=self._stringvar_bin, width=MainWindow.TxtMaxLen, state="readonly", font=MainWindow.FONT)#entry box set to readonly to act as a display box
txt_output.grid(row=2, column=1, pady=5)
#denary output box and label
label = tkinter.Label(self._window, text="Denary:", font=MainWindow.FONT)#label defined for number box
label.grid(row=3, column=0, padx=5, pady=5)
self._stringvar_den = tkinter.StringVar()
txt_output = tkinter.Entry(self._window, textvariable=self._stringvar_den, width=MainWindow.TxtMaxLen, state="readonly", font=MainWindow.FONT)
txt_output.grid(row=3, column=1, pady=5)
#hexadecimal output box and label
label = tkinter.Label(self._window, text="Hexadecimal:", font=MainWindow.FONT)#label defined for number box
label.grid(row=4, column=0, padx=5, pady=5)
self._stringvar_hex = tkinter.StringVar()
txt_output = tkinter.Entry(self._window, textvariable=self._stringvar_hex, width=MainWindow.TxtMaxLen, state="readonly", font=MainWindow.FONT)
txt_output.grid(row=4, column=1, pady=5)
def BinSelection(self):
try:
Bin = self._txt_input.get().strip().replace(" ", "")
BinValue = bin2bin(Bin)
DenValue = bin2den(Bin)
HexValue = bin2hex(Bin)
self._set_values(BinValue, DenValue, HexValue)
except Exception as ex:
tkinter.messagebox.showerror("Error", "Invalid conversion")
tkinter.messagebox.showinfo("Error", "Enter a valid 8 bit binary number or a integer / hexadecimal value")
print(ex, file=sys.stderr)
def DenSelection(self):
try:
Den = self._txt_input.get().strip().replace(" ", "")
DenValue = den2den(Den)
BinValue = den2bin(Den)
HexValue = den2hex(Den)
self._set_values(BinValue, DenValue, HexValue)
except Exception as ex:
tkinter.messagebox.showerror("Error", "Invalid conversion")
print(ex, file=sys.stderr)
def HexSelection(self):
try:
Hex = self._txt_input.get().strip().replace(" ", "")
HexValue = hex2hex(Hex)
BinValue = hex2bin(Hex)
DenValue = hex2den(Hex)
self._set_values(BinValue, DenValue, HexValue)
except Exception as ex:
tkinter.messagebox.showerror("Error", "Invalid conversion")
print(ex, file=sys.stderr)
def _set_values(self, BinValue, DenValue, HexValue):
if not BinValue.startswith(""):
BinValue = "" + BinValue
if not HexValue.startswith(""):
HexValue = "" + HexValue
self._stringvar_bin.set(BinValue)
self._stringvar_den.set(DenValue)
self._stringvar_hex.set(HexValue)
def mainloop(self):
self._window.mainloop()
if __name__ == "__main__":
win = MainWindow()
win.mainloop()
any insight on how to fix this would be great thanks. and sorry if this whole question was just a silly one.
Answer to my question as the Issue is now resolved. Fixed it using columnspan which allows you to set a box across several columns.
label = tkinter.Label(self._window, text="Convert From ", font=MainWindow.FONT)
label.grid(row=0, column=2,columnspan=3, padx=5, pady=5)
Here is what it looks like with the resolved problem

Tkinter entry widget wont take input when using notebook

I am trying to get input from an entry widget using Python Tkinter using Notebook. I have managed to get it to work on my main canvas but as soon as I introduced tabs, it would not work. I am clearly missing something linking the .get function to the correct location but I can't work out what. Any ideas?
import tkinter
import win32api
from tkinter import ttk
checklist = tkinter.Tk()
checklist.title("My Checklist")
ScreenWidth=checklist.winfo_screenwidth()
ScreenHeight=checklist.winfo_screenheight()
checklist.geometry("%dx%d+0+0" % (ScreenWidth, ScreenHeight))
count = 0
tasks = []
tabcontrol = ttk.Notebook(checklist, width = 500, height = 500)
tab = ttk.Frame(tabcontrol)
tabcontrol.add(tab, text = "Checklist Home Page")
tabcontrol.grid(row = 0, column = 0)
main_canvas = tkinter.Canvas(checklist, width = 1000, height = 1000, highlightbackground="green")
main_canvas.grid(row=1, column = 0)
main_canvas.columnconfigure(3)
main_canvas.rowconfigure(6)
def create_checklist():
global count
count += 1
if count > 10:
win32api.MessageBox(0, 'Maximum number of checklists made!')
else:
tab = ttk.Frame(checklist, width = 500, height = 500)
tabcontrol.add(tab, text = count)
tabcontrol.grid(row = 0, column = 0)
button_add_task = tkinter.Button(tab, text="Add task", width=20, height=1, bg="purple", command=add_task).grid(row = 2, column= 2, pady = (100, 1))
item_entry = tkinter.Entry(tab).grid(row=6, column =2)
list_items = tkinter.Listbox(tab)
list_items.grid(row =7, column =2, pady=10)
def add_task():
task = item_entry.get()
if task !="":
tasks.append('- ' + task)
update_listbox()
button_create_checklist = tkinter.Button(main_canvas, text="New Checklist", width=20, height=1, bg = "purple", command=create_checklist).grid(row = 3, column = 2, pady = 1 )
checklist.mainloop()
My error is currently:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lucas\anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\lucas\OneDrive\Documents\Employability\untitled0999py.py", line 40, in add_task
task = item_entry.get()
NameError: name 'item_entry' is not defined
Since item_entry is local variable of function create checklist(), it can't be used in add_task() function. So, we'll pass value of Entry field whenever Add Task button is pressed. To do so, we can use lambda expression in command option of Button. There are some minor changes in add_task() function.
Remember: grid is used to organize widgets and it returns None, so item_entry will be a NoneType object in your code and using get() with it will raise AttributeError.
So, we need to replace
item_entry = tkinter.Entry(tab).grid(row=6, column =2)
with
item_entry = tkinter.Entry(master=tab)
item_entry.grid(row=6, column =2)
This code works Fine:
def create_checklist():
global count
count += 1
if count > 10:
win32api.MessageBox(0, 'Maximum number of checklists made!')
else:
tab = ttk.Frame(checklist, width = 500, height = 500)
tabcontrol.add(tab, text = count)
tabcontrol.grid(row = 0, column = 0)
item_entry = tkinter.Entry(master=tab) # Changes in
item_entry.grid(row=6, column =2) # these lines
button_add_task = tkinter.Button(tab, text="Add task", width=20, height=1, bg="purple", command=lambda :add_task(item_entry.get())).grid(row = 2, column= 2, pady = (100, 1))
list_items = tkinter.Listbox(tab)
list_items.grid(row =7, column =2, pady=10)
def add_task(task):
if task !="":
tasks.append('- ' + task)
update_listbox()
Hope this helps.

Is it possible to grab a label variable and put into list with tkinter

I've created a temperature converter programme in which the calculated temperature from an entry widget gets displayed in a separate label, what I need to do is to grab that converted variable and put it into a list.
I think that making a connected entry widget to the label widget would work where they are connected so I could grab the variable using the .get method but that would look awfully messy. Is there any other way I could proceed with this?
This is my first post and I am a beginner in Python, very sorry if the code looks messy and if I included too much code.
data = []
tempVal = "Celcius"
def store_temp(sel_temp):
global tempVal
tempVal = sel_temp
class Calculator:
def __init__(self, num_a, num_b):
self.num_a= num_a
self.num_b = num_b
def convert(self):
if tempVal == 'Fahrenheit':
return float((float(self.num_a) - 32)* 5 / 9)
if tempVal == 'Celcius':
return float((float(self.num_a) * 9/ 5) + 32)
def display_add(entry_numa,entry_numb,label_answer):
#get the value from entry_numa
num_a = entry_numa.get()
num_b = entry_numb.get()
num_a = str(num_a)
num_b = str(num_b)
#create an object
global data
calc = Calculator(num_a,num_b)
label_answer['text'] = calc.convert()
data += [calc]
def calc_history():
global data
#creat e another window
window_calc_list = Tk()
window_calc_list.geometry("400x200")
#create a listbox
listbox_calc_list = Listbox(window_calc_list, width= 300)
listbox_calc_list.pack()
listbox_calc_list.insert(END, "list of data")
for info in data:
listbox_calc_list.insert(END, str(info.num_a) + " " + str(info.num_b) + " " )
window_calc_list.mainloop()
def main():
window = Tk()
window.geometry("500x150")
validate_letter = window.register(only_letters)
validate_nb = window.register(only_numbers_max_3)
label = Label(window, width = 30, background = 'lightblue', text='enter temperature, only numbers')
label.grid(row=0, column=0)
entry_numa = Entry(window, width = 30, validate="key", validatecommand=(validate_nb, '%d', '%P'))
entry_numa.grid(row = 0, column = 1)
#create another label and entry object for num_b
label_numb = Label(window, width = 30, background = 'lightblue', text='enter location, only letters')
label_numb.grid(row=1, column=0)
entry_numb = Entry(window, width = 30, validate="key", validatecommand=(validate_letter, '%d', '%S'))
entry_numb.grid(row = 1, column = 1)
#create another label to display answer
label_answer = Label(window, width = 30, background = 'lightyellow')
label_answer.grid(row = 2, column = 1)
entry_answer = Entry(window, width = 30)
entry_answer.grid(row = 2, column = 0)
button_add = Button(window, text = "ADD", command = lambda: display_add(entry_numa,entry_numb,label_answer))
button_add.grid(row=3, column = 0)
button_delete = Button(window, text = "DELETE", command = lambda: delete_data(data))
button_delete.grid(row=3, column = 2)
#create another button to display all previous calculations
button_display = Button(window,text = "calc_history", command = lambda: calc_history())
button_display.grid(row=3, column = 1)
var = StringVar()
dropDownList = ["Celcius", "Fahrenheit"]
dropdown = OptionMenu(window, var,dropDownList[0], *dropDownList, command=store_temp)
dropdown.grid(row=0, column=2)
window.mainloop()
A tk.Label displayed value can be accessed via the text property
, labelwidgetname['text'].
Depeneding on when and how you want the independent list of stored values
to be updated there are a variety of options. The example shows one if the
user is required to press a submission button. This could be adapted,
for example,when the tempreture calculation is performed.
Of course it would be simpler to update the list of stored values directly at the point in the script where the calculated tempreture for the label text has been derived.
import tkinter as tk
stored_values = []
def add_labelvalue_tolist(temp):
'''Store label value to list.'''
stored_values.append(temp)
print('contents of list', stored_values)
def add_entry_tolabel(event):
display_label['text'] = user_entry.get()
ROOT = tk.Tk()
user_entry = tk.Entry()
user_entry.grid(column=0, row=0)
user_entry.bind('<KeyRelease>', add_entry_tolabel)
display_label = tk.Label()
display_label.grid(column=1, row=0)
# update list via button command linked to label text value
add_button = \
tk.Button(text='add to list',
command=lambda:add_labelvalue_tolist(display_label['text']))
add_button.grid(column=0, row=1)
ROOT.mainloop()
try making a function that is like this
def letterused():
converter=(letter.get())# letter is a entry box at the bottom is the code
converted.set(converter)
for i in range(1):
used_letters1.append(converter) #list
letter = ttk.Entry(root, width = 20,textvariable = letter)
letter.pack()

How to reference an attribute of a tkinter button which is inside of a list? (Python)

I'm making a calculator program and am creating the buttons to go in the calculator's interface. I create all buttons using one for loop initially, and then want to reconfigure certain buttons to change their colour and command. Is there any way to reference an attribute such as the "text" attribute of a button inside of a list? For example, if button index has a text attribute of "+" or "-" or "/" or "*" reconfigure colour to red.
The current code I have to do this is very inefficient as it requires each button to be referenced by index individually. If possible I would like to reference by an attribute and not just by index number. Algorithm in question can be found below.
#Method that creates calculator buttons, appends them to a list and packs them into the grid.
def create_number_buttons(self):
button_characters = "789*456/123-0.=+"
i = 0
self.button_list = []
for row_counter in range(2,6):
for column_counter in range(4):
self.button_list.append(Button(root, bg="#11708e", fg="white", activebackground="#11708e", pady=25, padx=35, text=button_characters[i], font=("Helvetica", 16, 'bold')))
self.button_list[i].grid(row=row_counter, column=column_counter, sticky="NSEW")
self.button_list[i].configure(command = lambda c=button_characters[i]: self.num_press(c))
i += 1
#Reconfigures the specific buttons.
self.button_list[3].configure(bg="#d14302", activebackground="#d14302")
self.button_list[7].configure(bg="#d14302", activebackground="#d14302")
self.button_list[11].configure(bg="#d14302", activebackground="#d14302")
self.button_list[13].configure(bg="#d14302", activebackground="#d14302")
self.button_list[14].configure(command=lambda: self.calculate_answer(), bg="#d14302", activebackground="#d14302")
self.button_list[15].configure(bg="#d14302", activebackground="#d14302")
Thanks for your help!
Full code below :)
from tkinter import *
from tkinter import messagebox
#Import so that I'm able to use regex to remove leading zeroes from the equation string when performing the calcultion.
import re
#Class to support logic of calculator, used for functionality and math operations.
class CalculatorFunctions:
def __init__(self, root):
self.root = root
self.answer = 0
#Command called if a number button is pressed.
def num_press(self, num):
new_input = num
self.text_box.insert(self.value_position, new_input)
self.value_position += 1
#Command that clears everything in the calculator's entrybox.
def clear_screen(self):
self.text_box.delete(0, END)
#Creates a message-box popup to display relevant author information.
def show_author_button(self):
messagebox.showinfo("Author", "Devin, August 2018")
#If the eval function returns a syntaxerror or a zerodivision error this command is called.
#Makes an error message popup box.
def error_popup(self):
messagebox.showwarning("Error", "Please edit your code and calculate again. Common errors include dividing by 0 and including too many decimal points in one number.")
#Uses the eval function to calculate entered string in calculator.
def calculate_answer(self):
errormessage = "SyntaxError"
try:
#Removes leading zeroes from the start of digits but not after a decimal point.
self.answer = eval(re.sub(r"((?<=^)|(?<=[^\.\d]))0+(\d+)", r"\1\2", self.equation.get()))
except (SyntaxError, ZeroDivisionError):
self.error_popup()
self.answer = eval(re.sub(r"((?<=^)|(?<=[^\.\d]))0+(\d+)", r"\1\2", self.equation.get()))
#Appends answer to list of values able to be inserted into calculator entry.
self.accepted_values.append(str(self.answer))
self.text_box.delete(0, END)
self.update_entry_with_answer()
def update_entry_with_answer(self):
self.text_box.insert(0, self.answer)
#Removes the last character in the entry field.
def backspace(self):
current = str(self.text_box.get())
new_input = current[:-1]
self.accepted_values.append(new_input)
self.text_box.delete(0, END)
self.text_box.insert(0, new_input)
#Checks for valid input
def testVal(self, entered_value, modifytype):
#Checks if text wanting to be inserted into the entryfield is valid.
if modifytype == '1': #insert
operators_and_d_point = "/*+-"
current_string = str(self.equation.get())
if entered_value == ".":
if current_string[-1] == ".":
return False
#If the last character entered was an operator, don't allow another operator or decimal point to be added to the entry box.
if entered_value in operators_and_d_point:
if current_string == "":
if entered_value == "-" or entered_value == "+":
return True
else:
return False
if current_string[-1] in operators_and_d_point:
if entered_value == "+" or entered_value == "-":
return True
else:
return False
if entered_value in self.accepted_values:
return True
#Accepts all attempts to remove text from the entryfield.
elif modifytype == "0":#delete
return True
return False
#Class to create widgets for the calculator GUI.
class CalculatorGUI(CalculatorFunctions):
def __init__(self, root):
self.root = root
self.value_position = 0
self.create_calculator_widgets()
root.bind("=", lambda event: self.calculate_answer())
self.accepted_values = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "*", "/", "."]
#Method called to create widgets associated with the calculator.
def create_calculator_widgets(self):
self.create_text_box()
self.create_number_buttons()
self.create_clear_button()
self.create_author_button()
self.create_backspace_button()
#Creates entry field, contents of the entry field stored as textvariable.
def create_text_box(self):
self.equation = StringVar()
self.text_box = Entry(root, justify=RIGHT, validate="key", textvariable=self.equation, font=("Helveitca", 16), borderwidth=15)
#Uses the tkinter entry box's "validatecommand" to check for valid input, method found in above class.
self.text_box['validatecommand'] = (self.text_box.register(self.testVal),'%S','%d')
self.text_box.grid(row=0, column=0, columnspan=4, ipady=10, sticky="WE")
#Method that creates calculator buttons, appends them to a list and packs them into the grid.
def create_number_buttons(self):
button_characters = "789*456/123-0.=+"
i = 0
self.button_list = []
for row_counter in range(2,6):
for column_counter in range(4):
self.button_list.append(Button(root, bg="#11708e", fg="white", activebackground="#11708e", pady=25, padx=35, text=button_characters[i], font=("Helvetica", 16, 'bold')))
self.button_list[i].grid(row=row_counter, column=column_counter, sticky="NSEW")
self.button_list[i].configure(command = lambda c=button_characters[i]: self.num_press(c))
i += 1
#Reconfigures the specific buttons.
self.button_list[3].configure(bg="#d14302", activebackground="#d14302")
self.button_list[7].configure(bg="#d14302", activebackground="#d14302")
self.button_list[11].configure(bg="#d14302", activebackground="#d14302")
self.button_list[13].configure(bg="#d14302", activebackground="#d14302")
self.button_list[14].configure(command=lambda: self.calculate_answer(), bg="#d14302", activebackground="#d14302")
self.button_list[15].configure(bg="#d14302", activebackground="#d14302")
def create_clear_button(self):
clear_button = Button(root, bg="#302e2e", fg="white", text="AC", font=("Helvetica", 12, 'bold'), pady=10, command=lambda: self.clear_screen())
clear_button.grid(row=1, columnspan=2, sticky="WE")
def create_backspace_button(self):
backspace_button = Button(root, bg="#302e2e", fg="white", text="Backspace", font=("Helvetica", 12, 'bold'), command=lambda: self.backspace())
backspace_button.grid(row=1, column=3, sticky="NSEW")
def create_author_button(self):
author_button = Button(root, bg="#302e2e", fg="white", font=("Helvetica", 12, 'bold'), text="Info", command=lambda: self.show_author_button())
author_button.grid(row=1, column=2, sticky="NSEW")
if __name__ == "__main__":
root = Tk()
calc = CalculatorGUI(root)
root.title("Calculator")
#Ensures the GUI window containing the calculator is unable to be resized, the 0,0 represents the x,y of resize allowed.
root.resizable(0, 0)
root.mainloop()
If you know you want to configure a group of widgets to an identical style save the
widget references in a dedicated object(list or dictionary).
You can then loop through those specific references applying the identical configuration.
For example if you wanted to apply red to only the operator buttons.
import tkinter as tk
master = tk.Tk()
numberframe = tk.Frame()
numberframe.grid(row=0, column=0)
button = {}
names = ('one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'zero')
for num, name in enumerate(names):
temp = tk.Button(master=numberframe,
text=(num+1)%10)
temp.grid(column=num%3,
row=num//3,
sticky='nsew')
button[name] = temp
operators = {}
operator_frame = tk.Frame()
operator_frame.grid(row=0, column=1)
operation = (('divide', '/'), ('multiply', '*'),
('subtract', '-'), ('add', '+'))
for name, sign in operation:
temp = tk.Button(master=operator_frame,
text=sign)
temp.grid()
operators[name] = temp
# example individually configure by the reference name.
button['seven'].configure(fg='red')
# example configure by group
for item in operators:
operators[item].configure(fg='red')
master.mainloop()

Categories

Resources