Code runs but Tkinter window stays blank - python

The problem i'm having is that it even though it executes, the tkinter window remains blank. and as a side issue the window doesn't refresh to update the Actions checkbutton.
from tkinter import *
Pieces = {}
Actions =[]
class GameCreation(Frame):
def __init(self,master):
super(GameCreation,self).__init__(master)
self.grid()
self.CreatePiece()
#Creating pieces function
def CreatePiece(self):
Label(self,text ="What piece are we working with?").grid(row =0,
column = 0,
sticky = W)
self.piece_entry = Entry(self)
self.piece_entry.grid(row =0,
column = 1,
sticky = W)
Label (self, text = "Tick all the actions which the piece has").grid (row =1,
column = 0,
sticky = W)
self.Actions = BooleanVar()
self.Actions.set(None)
column = 0
row = 4
for action in Actions:
Checkbutton(self,text = action, variable = self.checkButton, value = action).grid( row = row,
column = column,
sticky = W)
if column == 5:
row +=1
column = 0
else:
column +=1
Button(self,text = "Add action", command = self.AddAction).grid(row = 1,
column = 0,
sticky = W)
self.action_entry = Entry(self)
self.action_entry.grid(row = 1, column = 1, sticky = W)
Button (self, text = "Create piece and it's actions", command = Add_to_dict).grid(row =2,
column = 0,
sticky = W)
self.Add_dict = Text(self, width =10, height = 2, wrap = WORD)
self.Add_dict.grid( row = 3, column = 0, columnspan = 4)
This function should add to the Actions list
def addAction(self):
action = self.action_entry.get()
Actions.append(action)
This function should just print the name of the piece and the actions chosen for it
def Add_to_dict(self):
actions = Actions.get()
piece = piece_entry.get()
rules = piece, ":", actions
self.Add_dict.delete(0.0,END)
self.Add_dict.insert(0.0,rules)

You need to use __init__, not __init
Also, if you're using BooleanVar, you must set it to True or False, not None:
self.Actions.set(False)
Also, you have a method named addAction but you are calling it like self.AddAction, and you have a method named Add_to_dict that you are calling like Add_to_dict rather than self.Add_to_dict.
And finally, you don't appear to be creating an instance of GameCreation anywhere.

Related

python tkinter show right widgets after Combobox selection

I am new to tkinter and am trying to create a GUI with a Combobox. If a certain value ('new subgroup') is chosen, other widgets should appear (label_4, label_5 and label_6). If any other value of the combobox is being chosen, label_7 should appear.
The issue that I am having right now, is that this works only the first time! If I change my mind, and chose another value than first chosen, the labels that appeared through my first choice still stay, with the second choice just appearing on top of it.
How can I only see the labels I want to see, even after having changed my mind and chosen another value from the combobox?
The code is somewhat long, but the important part starts at input_3, the rest is just for a bit of context ;).
from tkinter import *
from tkinter import ttk
root = Tk()
#configure the root
root.title('Add nodes')
root.columnconfigure(0, weight = 1)
root.rowconfigure(0, weight = 1)
#add frame on the root
frame_add = ttk.Frame(root)
frame_add.columnconfigure(0, weight = 1)
frame_add.columnconfigure(1, weight = 1)
frame_add.columnconfigure(2, weight = 1)
frame_add.rowconfigure(0, weight = 1)
frame_add.rowconfigure(1, weight = 1)
frame_add.rowconfigure(2, weight = 1)
frame_add.rowconfigure(3, weight = 1)
frame_add.rowconfigure(4, weight = 1)
frame_add.grid(column = 0, row = 0)
#first row
label_1 = ttk.Label(frame_add, text = 'Label (name of the .json file):')
label_1.grid(column = 0, row = 0, sticky = 'E')
label = ttk.Entry(frame_add)
label.insert(0, 'write label here')
label.grid(column = 1, row = 0, columnspan= 2, pady = 5)
#second row
label_2 = ttk.Label(frame_add, text = 'Node (name of the node \
in the graph database):')
label_2.grid(column = 0, row = 1, sticky = 'E')
Node = ttk.Entry(frame_add)
Node.insert(0, 'write node here')
Node.grid(column = 1, row = 1, columnspan = 2, pady = 5)
#third row
label_3 = ttk.Label(frame_add, text = 'Define subgroup of node:')
label_3.grid(column = 0, row = 2, sticky = 'E')
selected_colour = StringVar()
input_3 = ttk.Combobox(frame_add, textvariable = selected_colour, )
input_3['state'] = 'readonly'
input_3['values'] = ['requirement', 'property',
'measurement_calculate', 'measurement_value',
'measurement_signal_characterization',
'measurement_technology', 'calculate_value',
'measured_variables_expression', 'main_function',
'part_function', 'partial_solution',
'test_bed_module', 'electronics',
'mechanical_structure', 'new subgroup']
width = len(max(input_3['values'], key = len)) + 2
input_3['width'] = width
input_3.grid(column = 1, row = 2, columnspan = 2, pady = 5)
#after having chosen a value from input_3, this shows (depending on the value):
label_4 = ttk.Label(frame_add, text = 'Please insert the \
properties and corresponding values of the new subgroup:')
label_5 = ttk.Entry(frame_add)
label_5.insert(4, 'Category')
label_6 = ttk.Entry(frame_add)
label_6.insert(1, 'Carateristic to save')
label_7 = ttk.Entry(frame_add)
label_7.insert(1, 'Test')
#event to read the choice on input 3 and show the different widgets
def retrieve(event):
if 'new subgroup' == selected_colour.get():
label_4.grid(column = 0, row = 3, columnspan = 3)
label_5.grid(column = 0, row = 4, pady = 5)
label_6.grid(column = 1, row = 4, pady = 5)
label_7.destroy()
else:
label_4.destroy()
label_5.destroy()
label_6.destroy()
label_7.grid(column = 0, row = 3, pady = 5)
input_3.bind('<<ComboboxSelected>>', retrieve, "+")
root.mainloop()
Thanks everyone for your help!

Displaying images iteratively in tkinter

# Generates a frame that also contains all the necessary widgets for all mounts in a list
# Takes the parent window the frame will be part of (TK()),
# the row (int) and column (int) the new frame will be located on the parent window,
# the name of the frame we're creating (string),
# and a list of all the mounts to go into the frame (list of string),
# the complement_checkbox (tkinter.CheckButton())
# Returns (tkinter.LabelFrame)
def generate_widgets(master, frame_name, mount_list, complement_checkbox):
new_frame = LabelFrame(master, text = frame_name, font=("Arial Narrow", 18), padx = 5, pady = 5)
new_frame.grid(row = 0, column = 0, padx = 10, pady = 10, sticky = N + S + E + W)
# We have row weight be equal to the number of mounts per frame
master.rowconfigure(0, weight = len(mount_list))
master.columnconfigure(0, weight = 1)
label_widgets = {}
image = {}
icon_label = {}
attempts_string = {}
spin_widgets = {}
button_widgets = {}
for i in range(len(mount_list)):
full_name = mount_list[i]
mount_name = full_name.split(' - ')[1]
label_widgets[i] = Label(new_frame, text = mount_list[i], font = ("Arial Narrow", 12))
label_widgets[i].grid(row = i, column = 0, sticky = W)
image[i] = PhotoImage(file = "Assets\\" + mount_name + ".png")
icon_label[i] = Label(new_frame, image = image[i])
icon_label[i].grid(row = i, column = 1, sticky = E)
attempts_string[i] = StringVar()
attempts_string[i].set(load_attempts(mount_name))
spin_widgets[i] = Spinbox(new_frame, from_ = 0, to = 1024, width = 5, textvariable = attempts_string[i])
spin_widgets[i].grid(row = i, column = 2, sticky = E)
button_widgets[i] = Button(new_frame,
text = "Calculate",
# j = i saves the current value of i into j when lambda is defined,
# if we don't have this line, the command will always use the value of i when the
# command is called, which will be the last row (i-th)
command = lambda j = i: open_and_save(mount_list[j],
mount_list[j].split(' - ')[1],
spin_widgets[j].get(),
complement_checkbox.get()))
button_widgets[i].grid(row = i, column = 3, sticky = E)
new_frame.rowconfigure(i, weight = 1)
# Column 0 is label, column 1 is spinbox, column 2 is button
new_frame.columnconfigure(0, weight = 1)
new_frame.columnconfigure(1, weight = 1)
new_frame.columnconfigure(2, weight = 1)
new_frame.columnconfigure(3, weight = 1)
return new_frame
I'm using the above code to create a new frame and fill it iteratively with widgets. So the problem I'm having right now is that the images I'm trying to display with icon_label[i] isn't working, and is instead just a blank space. I'm quite sure why this is happening, as when I try adding an image to the frame after the function has already run, the image display. I also noticed that if I make images{} and icon_label{} global, some of the images display, but not all (some frames have none, some only have the last few, or only the last). So I'm just wondering what is going on?

Radiobutton only shows one option

I'm not sure what I'm doing wrong, but it seems that my radiobutton only shows one option instead of two options(which is what I originally wanted).
PLAYERS = [("Black", "black"),
("White", "white")]
def first_player(self) -> str:
self.firstplayer = tkinter.StringVar(value = 'black')
self._player_text = tkinter.StringVar()
self._player_text.set('Which player moves first: ')
player_label = tkinter.Label(
master = self.root_window, textvariable = self._player_text,
background = 'yellow', height = 1, width = 20, font = DEFAULT_FONT)
player_label.grid(row=1, column = 0, padx = 10, pady=90, sticky = tkinter.W+tkinter.N)
for text,mode in PLAYERS:
first = tkinter.Radiobutton(self.root_window, text = text,
variable = self.firstplayer , value = mode)
first.grid(row = 1, column = 0, padx = 300, pady = 90, sticky = tkinter.W + tkinter.N)
return self.firstplayer.get()
You are placing both radiobuttons in the same place: row 1, column 0. The first one it thus invisible because it is under the second one. If you want the label and two radiobuttons on the same row but different columns, the solution is to give them all the same row, and different columns.
There are many ways to accomplish this, I'll show you one:
column = 1
for text,mode in PLAYERS:
first = tkinter.Radiobutton(self.root_window, text = text,
variable = self.firstplayer , value = mode)
first.grid(row = 1, column = column, sticky = tkinter.W + tkinter.N)
column += 1

Python Tkinter replacing the label and command of a button by clicking another button

I'm writing a scientific calculator with 2nd button. What is the function for second button so for example it changes sin to sin^-1, plus changing the sin button command; and if you click the 2nd button again, it changes sin^-1 back to sin
I would split my calculator up into section using different frames (one to show the calculations , one with buttons which won't have 2 functions and lastly the buttons which have 2 functions).
The reason I would split it up is because I would use destroying objects and making the new ones this splitting up means you can destroy the wanted frame rather than specific buttons (would require less code). Also for this I would have 3 create GUI defs. one would be the buttons with one function and the bit showing the calculations. one be the buttons which have 2 functions (their first function) and lastly the buttons which have 2 functions (their second functions). To decide between which GUI gen def to use have an if statement with global variable which gets changed each time 2nd function button called and that decides which def to use.
If it was just commands you wanted changing instead of both labels and commands I would have a variable which is etheir 1 or 2(change when 2nd button clicked) then in your definitions (ones which your buttons call) have an if statement to decide between to do normal action (e.g cos) or 2nd action (e.g cos-1).
Here is code below that uses what i have described in the first paragraph:
from tkinter import *
class Calc(Frame):
def __init__(self, master):
self.modefunction = 1
""" Initialize the frame. """
super(Calc,self).__init__(master)
self.grid()
self.calculations_frm = Frame(self, width=100, height=30)#bg = "red"
self.calculations_frm.grid(row = 0, column = 0, columnspan=2)
self.buttons_frm = Frame(self, width= 50, height=30,)#bg = "green")
self.buttons_frm.grid(row = 1, column = 1)
self.buttons_2_functions_1_frm = Frame(self, width=50, height=30)#bg = "blue")
self.buttons_2_functions_1_frm.grid(row = 1, column = 0)
self.create_GUI()
def create_show_calculations(self):
self.calculation_lbl = Label(self.calculations_frm, text = "will show caluclations here").pack()
def create_buttons(self):
#mc stands for mode change
self.mode_change_btn = Button(self.buttons_frm, text = "mc", command = self.mode_change, height = 1, width = 5)
self.mode_change_btn.grid(row = 0,column = 0)
self.plus_btn = Button(self.buttons_frm, text = "plus", height = 1, width = 5)
self.plus_btn.grid(row = 1,column = 0)
def create_GUI(self):
self.create_show_calculations()
self.create_buttons()
self.create_1_function_gui()
def create_1_function_gui(self):
self.tan_btn = Button(self.buttons_2_functions_1_frm, text = "tan", height = 1, width = 5)
self.tan_btn.grid(row = 0,column = 0)
self.san_btn = Button(self.buttons_2_functions_1_frm, text = "san", height = 1, width = 5)
self.san_btn.grid(row = 0,column = 1)
self.coz_btn = Button(self.buttons_2_functions_1_frm, text = "coz", height = 1, width = 5)
self.coz_btn.grid(row = 1,column = 0)
def create_2_function_gui(self):
self.buttons_2_functions_2_frm = Frame(self, width=50, height=30)#bg = "blue")
self.buttons_2_functions_2_frm.grid(row = 1, column = 0)
self.inverse_tan_btn = Button(self.buttons_2_functions_2_frm, text = "tan-1", height = 1, width = 5)
self.inverse_tan_btn.grid(row = 0,column = 0)
self.inverse_san_btn = Button(self.buttons_2_functions_2_frm, text = "san-1", height = 1, width = 5)
self.inverse_san_btn.grid(row = 0,column = 1)
self.inverse_coz_btn = Button(self.buttons_2_functions_2_frm, text = "coz-1", height = 1, width = 5)
self.inverse_coz_btn.grid(row = 1,column = 0)
def mode_change(self):
if self.modefunction == 1:
self.buttons_2_functions_1_frm.destroy()
self.modefunction = 2
self.buttons_2_functions_2_frm = Frame(self, width=50, height=30)#bg = "blue")
self.buttons_2_functions_2_frm.grid(row = 1, column = 0)
self.create_2_function_gui()
else:
self.buttons_2_functions_2_frm.destroy()
self.modefunction = 1
self.buttons_2_functions_1_frm = Frame(self, width=50, height=30)#bg = "blue")
self.buttons_2_functions_1_frm.grid(row = 1, column = 0)
self.create_1_function_gui()
root = Tk()
root.title("booking system")
root.geometry("500x500")
root.configure(bg="white")
app = Calc(root)
root.mainloop()

Tkinter getting data from an entry box and sending it to other functions

(Python 3.3) With no formal instruction, I am trying to advance my very basic knowledge of Python into Tkinter. Below is a program I am trying to write. I have two problems:
1 - When I run this, both radio buttons are active until I click one. Not a huge deal, but it annoys me.
2 - I can't seem to get the .get() method to pull the data entered in the Entry box from the data_window function to the check_data function. As my program eludes, the next step after it passes the check data function will be to send it on to the formatEntry function, which is not written yet. But until I figure this put, that obviously won't work either.
I have a functional version of this without using TKinter and I am trying to adapt that knowledge into this for the purpose of learning. So please feel free to point out any other problems you see, just please keep the explanations very basic for a newb! Thanks
from tkinter import *
import os, shelve
food_entry = None
# Opens a new window for entering food items
def data_window():
global food_entry
new_window_entry = Tk()
new_window_entry.title('Data Entry Window')
Label(new_window_entry, text = 'Enter the food items you have eaten below, separated by commas:').grid(sticky = W, columnspan = 2)
Label(new_window_entry, text = '(i.e. Apple, Eggs, Ground Beef)').grid(sticky = W, columnspan = 2)
food_entry = Text(new_window_entry, width = 55, height = 2, wrap = WORD)
food_entry.grid(sticky = W, columnspan = 2)
#food_entry = Entry(new_window_entry)
Label(new_window_entry, text = 'Within two hours after eating, did you experience any of the following symptoms:').grid(sticky = W, columnspan = 2)
Label(new_window_entry, justify = LEFT, wraplength = 450, text = 'bloating, diarrhea, nausea, vomiting, irritable bowel, skin rashes, fatigue, joint pain, dark circles under the eyes, night sweats, or tingling or swelling of the face, fingers, feet or other extemities?').grid(sticky = W, columnspan = 2)
inflam = StringVar(master = new_window_entry)
Radiobutton(new_window_entry, text = 'Yes', variable = inflam, value = 'y').grid(row = 9, column = 0, sticky = E)
Radiobutton(new_window_entry, text = 'No', variable = inflam, value = 'n').grid(row = 9, column = 1, sticky = W)
Button(new_window_entry, text = 'Submit', command = check_data).grid(row = 10, column = 0, sticky = W + E)
Button(new_window_entry, text = 'Cancel', command = new_window_entry.destroy).grid(row = 10, column = 1, sticky = W + E)
#Check to ensure all fields have been entered
#Convert entry into formatted list
new_window_entry.mainloop()
def check_data():
global food_entry
print(food_entry.get(1.0, END))
if food_entry.get(1.0, END) == None:
print('Nothing Entered')
# tkMessageBox.showwarning(message = 'Please complete all fields of the form.')
else:
print('Next Function')
# formatEntry()
root = Tk()
root.title('')
Label(root, text = 'Food Tracker v3.0').grid(columnspan = 2)
Button(root, text = 'Enter Data', command = data_window).grid(row = 1, column = 0, sticky = W)
Button(root, text = 'View Data', command = view_window).grid(row = 1, column = 1, sticky = E)
First of all you defined food_entry twice, and the second time you never did anything with it (food_entry = Entry(new_window_entry)). You'll need to remove that 2nd definition.
Next, this assigns what grid() returns to food_entry, which is None
food_entry = Text(new_window_entry, width = 55, height = 2, wrap = WORD).grid(sticky = W, columnspan = 2)
So instead you'll need to grid() on a separate line. This keeps the Text() object assigned to food_entry as you intended:
food_entry = Text(new_window_entry, width = 55, height = 2, wrap = WORD)
food_entry.grid(sticky = W, columnspan = 2)
Finally, when accessing a Text() with get() you need to specifiy the start and ending points that you're trying to obtain:
...
print(food_entry.get(1.0, END))
if food_entry.get(1.0, END) == None:
....
Edit: One last thing to cover your question about the Radiobutton() displaying as selected initially, you can correct this by explicitly declaring the master of your StringVar():
inflam = StringVar(master = new_window_entry)
Edit 2: For your if / else statement not working:
if food_entry.get(1.0, END) == None:
This is checking to see if the string in the Text is None, which it's not, it's actually an empty string, so we need to check it accordingly:
if food_entry.get(1.0, END).strip() == '': # Use .strip() to remove spaces and newlines
Here's a complete code sample:
from tkinter import *
import os, shelve
food_entry = None
# Opens a new window for entering food items
def data_window():
global food_entry
new_window_entry = Toplevel() # Change to Toplevel (a popup) instead of a new Tk instance
new_window_entry.title('Data Entry Window')
Label(new_window_entry, text = 'Enter the food items you have eaten below, separated by commas:').grid(sticky = W, columnspan = 2)
Label(new_window_entry, text = '(i.e. Apple, Eggs, Ground Beef)').grid(sticky = W, columnspan = 2)
food_entry = Text(new_window_entry, width = 55, height = 2, wrap = WORD)
food_entry.grid(sticky = W, columnspan = 2)
Label(new_window_entry, text = 'Within two hours after eating, did you experience any of the following symptoms:').grid(sticky = W, columnspan = 2)
Label(new_window_entry, justify = LEFT, wraplength = 450, text = 'bloating, diarrhea, nausea, vomiting, irritable bowel, skin rashes, fatigue, joint pain, dark circles under the eyes, night sweats, or tingling or swelling of the face, fingers, feet or other extemities?').grid(sticky = W, columnspan = 2)
Radiobutton(new_window_entry, text = 'Yes', variable = inflam, value = 'y').grid(row = 9, column = 0, sticky = E)
Radiobutton(new_window_entry, text = 'No', variable = inflam, value = 'n').grid(row = 9, column = 1, sticky = W)
Button(new_window_entry, text = 'Submit', command = check_data).grid(row = 10, column = 0, sticky = W + E)
Button(new_window_entry, text = 'Cancel', command = new_window_entry.destroy).grid(row = 10, column = 1, sticky = W + E)
#new_window_entry.mainloop() No need for this, the mainloop is already running
def check_data():
global food_entry
print(food_entry.get(1.0, END))
if food_entry.get(1.0, END).strip() == '':
print('Nothing Entered')
else:
print('Next Function')
root = Tk()
inflam = StringVar() # move inflam init to a broader scope so that the buttons don't but
inflam.set('n') # initialize it as 'n'
root.title('')
Label(root, text = 'Food Tracker v3.0').grid(columnspan = 2)
Button(root, text = 'Enter Data', command = data_window).grid(row = 1, column = 0, sticky = W)
#Button(root, text = 'View Data', command = view_window).grid(row = 1, column = 1, sticky = E)
root.mainloop()

Categories

Resources