I am supposed to write a program with check buttons that allow the user to select any or all of these services. When the user clicks a button the total charges should be displayed. I already have the first portion done and finished but I need help with the second part. I can't find a calculation that works when the user clicks the buttons and the total charges are calculated and displayed within the same box. What is the correct calculation to add the selected? Here's what I have so far:
#Create the checkbutton widgets in top frame.
self.cb1 = tkinter.Checkbutton(self.top_frame, \
text = 'Oil Change-$30.00', variable = self.cb_var1)
self.cb2 = tkinter.Checkbutton(self.top_frame, \
text = 'Lube Job-$20.00', variable = self.cb_var2)
self.cb3 = tkinter.Checkbutton(self.top_frame, \
text = 'Radiator Flush-$40.00', variable = self.cb_var3)
self.cb4 = tkinter.Checkbutton(self.top_frame, \
text = 'Transmission Flush-$100.00', variable = self.cb_var4)
self.cb5 = tkinter.Checkbutton(self.top_frame, \
text = 'Inspection-$35.00', variable = self.cb_var5)
self.cb6 = tkinter.Checkbutton(self.top_frame, \
text = 'Muffler Replacement-$200.00', variable = self.cb_var6)
self.cb7 = tkinter.Checkbutton(self.top_frame, \
text = 'Tire Rotation-$20.00', variable = self.cb_var7)
#Pack the checkbuttons.
self.cb1.pack()
self.cb2.pack()
self.cb3.pack()
self.cb4.pack()
self.cb5.pack()
self.cb6.pack()
self.cb7.pack()
#Create an OK button and Quit button.
self.ok_button = tkinter.Button(self.bottom_frame, \
text = 'OK', command = self.show_choice)
self.quit_button = tkinter.Button(self.bottom_frame, \
text = 'Quit', command = self.main_window.destroy)
#Pack the buttons.
self.ok_button.pack(side = 'left')
self.quit_button.pack(side = 'left')
#Pack frame.
self.top_frame.pack()
self.bottom_frame.pack()
I am not a tkinter person but I would do it as if I was making this in wxpython and you will just have to translate it from there.
So first I would make a dictionary of all checkbox names and the price associated with it. It would look something like this:
priceCheckUp = {"Oil Change-$30.00":30, "Lube Job-$20.00":20...} #Keep going with all the rest of them
Next you would want list of all the checkboxes. I would change your code to have your checkboxes appended to a list like:
checkboxes = []
checkboxes.append(tkinter.Checkbutton(self.top_frame, \
text = 'Oil Change-$30.00', variable = self.cb_var1)) #Do that for all of them
So now that you have a list, you can use a for loop like such after the user presses the button:
total = 0
for i in checkboxes:
if i.isChecked():
total = total + priceCheckUp[i.GetLabel()]
print total #Or display the data however you want
The above code was done for wxPython Checkboxes so you will have to do some translating.
Here's an implementation of the essence of what I said in my comment. Although it's based on the code in your answer, I've added a lot of supporting code so I could test it. One significant change I made was to put all the Checkbutton widgets and their associated control variables into lists instead of explicitly giving each one a unique name — which was getting out-of-hand you have so many of them.
That said, the checking of the state of each Checkbutton and adding up the costs of checked items in shown in the show_choice() method.
import tkinter
# Table of services containing their names and costs.
SERVICES = [('Oil Change', 30.00),
('Lube Job', 20.00),
('Radiator Flush', 40.00),
('Transmission Flush', 100.00),
('Inspection', 35.00),
('Muffler Replacement', 200.00),
('Tire Rotation', 20.00)]
class MyApp(tkinter.Frame):
def __init__(self, master=None):
tkinter.Frame.__init__(self, master)
self.pack()
self.main_window = root
self.top_frame = tkinter.Frame(self)
self.bottom_frame = tkinter.Frame(self)
# Create list of control variables to query state of CheckButtons.
self.cb_vars = [tkinter.IntVar() for _ in range(len(SERVICES))]
# Create another list to hold a corresponding Checkbuttons.
self.cbs = [
tkinter.Checkbutton(
self.top_frame,
text='{}-${:.2f}'.format(SERVICES[i][0], SERVICES[i][1]),
variable=self.cb_vars[i])
for i in range(len(self.cb_vars))
]
# Pack the Checkbuttons.
for i in range(len(self.cbs)):
self.cbs[i].pack()
#Create an OK button and Quit button.
self.ok_button = tkinter.Button(self.bottom_frame,
text='OK', command=self.show_choice)
self.quit_button = tkinter.Button(self.bottom_frame,
text='Quit', command=self.main_window.destroy)
#Pack the buttons.
self.ok_button.pack(side = 'left')
self.quit_button.pack(side = 'left')
#Pack frames.
self.top_frame.pack()
self.bottom_frame.pack()
def show_choice(self):
popup_window = tkinter.Toplevel()
label_frame = tkinter.LabelFrame(popup_window, text='Total Charges')
label_frame.pack()
# Add up the cost of all the items which are checked.
total = sum(SERVICES[i][1] for i in range(len(self.cb_vars))
if self.cb_vars[i].get())
tkinter.Label(label_frame, text='${:.2f}'.format(total)).pack()
# Enter a local mainloop and wait for window to be closed by user.
root.wait_window(popup_window)
root = tkinter.Tk()
app = MyApp(root)
app.master.title('Cost Calculator')
app.mainloop()
Here's a screenshot of it running:
Related
I am trying to get tkinter to be able to find the total cost of some services that I input into the GUI. I haven't been able to get the actual calculations in the function "myClicker" to return any values to the screen. Looking for some help as to how I can get this code to take the inputs and use them for the calculations. I put in plenty of notes to try and help out too. This is my second post, go easy on me , Thanks!
import tkinter
service = { #This is the dictionary that holds all of the services and their associated prices
'Mergers and Acquisitions':3000,
'Business Valuations':2000,
'Financial Analysis & Operational Ideas':5000,
'Strategic Planning Services':3500,
'Specialized Strategic Consultion Services':4000,
'Litigation Support':6000,
'': 0
}
services = [ #This is the list that holds all of the services (Used for the GUI output)
'',
'Mergers and Acquisitions',
'Business Valuations',
'Financial Analysis & Operational Ideas',
'Strategic Planning Services',
'Specialized Strategic Consultion Services',
'Litigation Support'
]
window = tkinter.Tk() #Creates the window (GUI)
class QuotaCalc:
## A class that asks for data about a client and then calculates
## both the time required for the service and the total estimate cost
def __init__(self, main, cust_name = 'none', co_size = 0, option1=None, option2=None, option3=None): ##This initializes the class with all of the variables that we will use
self.co_name = tkinter.Label(main, text = 'Customer/Company Name', font=('Arial Narrow', 20)).grid(row=20, column=1) #This displays text, the font is the font, and this tells the program what to display
self.co_name_input = tkinter.Entry(main).grid(row=20, column=3) #Allows user to input information #by putting both on row 0, it aligns the text
#can add in blank labels to space out the boxes (reduce the font to something small) on the GUI
clicked = tkinter.StringVar() #initializing "clicked" as a string variable
clicked2 = tkinter.StringVar()
clicked3 = tkinter.StringVar()
clicked.set(services[0]) #Text to be displayed on the menu dropdown
clicked2.set(services[0])
clicked3.set(services[0])
timeRequired = 0 #Initializing the variable timeRequired
comp_size_input = tkinter.IntVar() #Initializing the variable comp_size_input, to be called later in the myClicker function for the calculation
self.co_size = tkinter.Label(main, text = 'Company Size', font=('Arial Narrow', 20)).grid(row=40, column=1) #Company Size Label
self.comp_size_input = tkinter.Entry(main) #Company Size Input Box
self.comp_size_input.grid(row=40, column=3) #Packing the Company Size Label
self.option_1 = tkinter.Label(main, text = 'Service 1 Needed', font=('Arial Narrow', 20)).grid(row=60, column=1) #Service Label
drop = tkinter.StringVar() #Initalizing the variable drop (for the drop box input)
self.drop = tkinter.OptionMenu( main , clicked , *service ) #DropBox Entry Options
self.drop.grid(row = 60, column = 3) #packs the variable drop to the screen at the grid coordinates
#dropped = tkinter.StringVar(drop) Done in the myClicker function
self.option_2 = tkinter.Label(main, text = 'Service 2 Needed', font=('Arial Narrow', 20)).grid(row=80, column=1) #Service 2 Label
drop2 = tkinter.StringVar() #Initalizing the variable drop2 (for the drop box input)
self.drop2 = tkinter.OptionMenu( main , clicked2 , *service ) #DropBox Entry Options
self.drop2.grid(row = 80, column = 3) #packs the variable drop2 to the screen at the grid coordinates
#dropped2 = tkinter.StringVar(drop2)
self.option_3 = tkinter.Label(main, text = 'Service 3 Needed', font=('Arial Narrow', 20)).grid(row=100, column=1) #Service 3 Label
drop3 = tkinter.StringVar() #Initalizing the variable drop3 (for the drop box input)
self.drop3 = tkinter.OptionMenu( main , clicked3 , *service ) #DropBox Entry Options
self.drop3.grid(row = 100, column = 3) #packs the variable drop3 to the screen at the grid coordinates
#dropped3 = tkinter.StringVar(drop3)
self.bt = tkinter.Button(main, text='Calculate', command = self.myClick, fg = "purple", bg = "light blue").grid(row=120, column=2) #Creates the Calculate button to run the code that finds the total cost and time required ##fg is foreground (color), bg is background (color)
#Need to convert to when the button presses, it runs other functions of the class
time_req = tkinter.Label(window, text = 'Time Required', font=('Arial Narrow', 20)).grid(row=140, column=1) #Creates the label Time Required to describe the output
total_cost = tkinter.Label(window, text = 'Price Quote', font=('Arial Narrow', 20)).grid(row=160, column=1) #Creates the label Total Cost to describe the output
#To fix the calcuation problem, maybe make a boolean to see if the button has been clicked and set it to false, when the boolean becomes true run the functions that do the math?
def myClick(self): #A function that activates once the button has been clicked and is desigend to calculate the total cost and time required for the services and output it to the GUI
comp_size = self.comp_size_input.get() #Initalizes the variable copm_size to be used in the time required calcuation
comp_size = int(comp_size) #Converts the variable comp size into an int
drop = str(self.drop) #Initializes and converts the chosen options for services 1, 2, and 3 into a string so they can be used to look up the prices in the service dictionary
drop2 = str(self.drop2)
drop3 = str(self.drop3)
timeRequired = 0
cost = 0
if comp_size == 0: #This determines how much time will be necessary based on the size of the company
self.timeRequired = 0 #Need to add data validation for the company size
elif comp_size <= 20:
self.timeRequired = 1
elif comp_size <= 40:
self.timeRequired = 2
elif comp_size <= 60:
self.timeRequired = 3
elif comp_size <= 80:
self.timeRequired = 4
elif comp_size <= 100:
self.timeRequired = 5
elif comp_size <= 150:
self.timeRequired = 6
else:
self.timeRequired = 8
cost = timeRequired * service[drop] #This section is used to determine the total costs based off of the services and the amount of time for the all the services
if self.drop2 != '':
cost += self.timeRequired * service[drop2]
if self.drop3 != '':
cost += self.timeRequired * service[drop3]
myLabel = tkinter.Label(window,text = timeRequired) #Designed to show the total time required and the total cost outputted on the GUI screen
myLabel.grid(row=140, column=3)
myLabel2 = tkinter.Label(window, text = cost)
myLabel2.grid(row=160, column=3)
logo = tkinter.PhotoImage(file=r"C:\Users\brian\OneDrive\Documents\TCU\Junior Year\Second Semester\Business Information System Development INSC 30833\Bar Ad Pic.PNG")
##YOU MUST USE THE FILE PATH TO THE LOGO ON YOUR OWN COMPUTER
##THIS SHOWS MY PERSONAL FILE PATH
w1 = tkinter.Label(window, image=logo).grid(row=0, column = 2) #Displays the picture at this grid coordinate
window.title('Barrington Advisory Quota Calculator') #Window Title
window.geometry('1000x500') #Sets the size of the window
#window.configure(bg='light blue') <- If we want to change the color of the background
e = QuotaCalc(window)
window.mainloop() #Tells the program to continue running until the GUI is closed
Note: The below code can be used by OP and anybody else with a little bit of tweaking.
Options like the ones in the comments (like Matiiss' comment on using StringVar(), which I am using here) may be more helpful to you, but I'd do it this way (there are many ways to do it, but I chose this one):
import tkinter
from tkinter import ttk # This is to import *most* of the elements you need for a decent-ish GUI w/o calling "tkinter" then elemtent name. I do this because I am lazy
# Setting up the GUI
window = tkinter.Tk()
window.title('Barrington Advisory Quota Calculator') # Window Title
window.geometry('500x500') # Sets the size of the window. Edit this to suit you. I am gonna put 500x500 because I am fine with it
#window.configure(bg='light blue') # If we want to change the color of the background (optional)
window.resizable(False, False) # Make sure that the current user cannot resize the window, keeping it at a fixed size
# Some variables that are kinda important to OP's project (OP, uncomment the line below)
# logo = tkinter.PhotoImage(file=r"C:\Users\brian\OneDrive\Documents\TCU\Junior Year\Second Semester\Business Information System Development INSC 30833\Bar Ad Pic.PNG")
currentSelected = tkinter.StringVar() # Kind of like doing 'currentSelected = ""' but with a bit of a special use later
# Functions
def fetch():
localCurSel = currentSelected.get() # Local variable to keep things easy imo
# BIG DISCLAIMER:
# I have no idea what is going on with the program OP is trying to make for a project
# as I am very new to Python (~4 months)
# Everything after the last line of this function can be expanded to OP's or anyone's
# needs. So if you wanna do some fancy stuff with it, go ahead. What's next is how to display
# the value from this function
leaveMeEmpty.configure(text="Output: {0}".format(localCurSel)) # This is how you display the output of the function
# I don't really get the "self" parameter much, so let's do this on how I'd write this
# GUI Variables
# NOTE: ALWAYS put functions ahead of GUI variables ESPECIALLY when calling a function with a variable
intrLabl = ttk.Label(window, text="Barrington Advisory Quota Calculator")
serviceList = ttk.Combobox(window, textvariable=currentSelected, width=50)
serviceList["values"] = ( # This is the list that holds all of the services for the combobox
'',
'Mergers and Acquisitions',
'Business Valuations',
'Financial Analysis & Operational Ideas',
'Strategic Planning Services',
'Specialized Strategic Consultion Services',
'Litigation Support'
)
serviceCalcul8 = ttk.Button(window, text="Calculate the ", command=fetch)
leaveMeEmpty = ttk.Label(window, text="Output: ") # Variable kinda empty, eh? This is where I-can't-Explain-Further-than-This-because-I-am-a-noob-land begins
# Combobox configs
serviceList["state"] = "readonly" # Make sure that the user cannot change what's inside the combobox except for the ones only in line 19
# Placing the elements/GUI parts thingy
intrLabl.pack()
serviceList.pack(padx=10, pady=10)
serviceCalcul8.pack(padx=10)
leaveMeEmpty.pack(padx=10)
window.mainloop()
I documented it/filled it with comments because it might help someone understand what's going on in a line, for example
This is my first real Python project. I am currently developing a GUI in Tkinter that allows the user to select Tasks and CVs to automatically compile documents using standard predefined task and CV texts from a database.
I have created two "Add" buttons in the main window to add Tasks and CVs that show a popup Listbox that allow the user to select the Tasks and CVs they want to have included in the commercial proposal. I have managed to create the popup window as a separate Class and it stores the selected Tasks in a list, but now I need to pass the list with the selected items to the Listbox in the main window when the user clicks the Select button in the popup window, but I cannot get my head around on how to do that.
I have researched on different fora and watched a variety of Youtube videos, but all focus on entry popups or some sort.
This is the code for the main window:
from tkinter import *
from Add import *
# make main window
root = Tk()
theLabel = Label(root, text="ProposalBuilder")
theLabel.grid(row=0)
# make frames
taskFrame = Frame(root)
taskFrame.grid(row=1, column=0)
CVFrame = Frame(root)
CVFrame.grid(row=1, column=1)
buildFrame = Frame(root)
buildFrame.grid(row=2, columnspan=2)
# add labels to frames
taskLabel = Label(taskFrame, text="Tasks")
taskLabel.pack()
CVLabel = Label(CVFrame, text="CVs")
CVLabel.pack()
# add listboxes to frames
scrollTask = Scrollbar(taskFrame, orient=VERTICAL)
listTask = Listbox(taskFrame, selectmode=MULTIPLE, yscrollcommand=scrollTask.set)
scrollTask.config(command=listTask.yview)
scrollTask.pack(side=RIGHT, fill=Y)
listTask.pack()
scrollCV = Scrollbar(CVFrame, orient=VERTICAL)
listCV = Listbox(CVFrame, selectmode=MULTIPLE, yscrollcommand=scrollCV.set)
scrollCV.config(command=listCV.yview)
scrollCV.pack(side=RIGHT, fill=Y)
listCV.pack()
# add commands to buttons
def addTask():
taskBox = Add('C:\\Users\\204703\\ProposalBuilder\\Database')
sel_test = taskBox.selection
def addCV():
CVBox = Add('C:\\Users\\204703\\ProposalBuilder\\Database')
# add buttons to frames
buttonAddTask = Button(taskFrame, text="Add", command=addTask)
buttonAddTask.pack(fill=X)
buttonDelTask = Button(taskFrame, text="Delete")
buttonDelTask.pack(fill=X)
buttonUpTask = Button(taskFrame, text="Up")
buttonUpTask.pack(fill=X)
buttonDownTask = Button(taskFrame, text="Down")
buttonDownTask.pack(fill=X)
buttonAddCV = Button(CVFrame, text="Add", command=addCV)
buttonAddCV.pack(fill=X)
buttonDelCV = Button(CVFrame, text="Delete")
buttonDelCV.pack(fill=X)
buttonUpCV = Button(CVFrame, text="Up")
buttonUpCV.pack(fill=X)
buttonDownCV = Button(CVFrame, text="Down")
buttonDownCV.pack(fill=X)
buttonBuild = Button(buildFrame, text="Build Proposal")
buttonBuild.pack(side=RIGHT)
root.mainloop()
This is the code for the separate class I created for the popup window:
from tkinter import*
from os import *
class Add:
def __init__(self, path):
# the slected tasks
self.selection = []
# make a frame
top = Toplevel()
# get file names from the directory (path) and save in list
self.path = path
self.dirList = listdir(self.path)
# add listbox to frames and populate with file names
self.scrollList = Scrollbar(top, orient=VERTICAL)
self.listbox = Listbox(top, selectmode=MULTIPLE, yscrollcommand=self.scrollList.set)
self.scrollList.config(command=self.listbox.yview)
self.scrollList.pack(side=RIGHT, fill=Y)
for item in self.dirList:
self.listbox.insert(END,item)
self.listbox.pack()
# add buttons to frame
self.selectButton = Button(top, text="Select", command=self.select)
self.selectButton.pack()
self.quitButton = Button(top, text="Quit", command=top.destroy)
self.quitButton.pack()
# identify selected rows and return a list with the selection
def select(self):
selectedRows = self.listbox.curselection()
for item in selectedRows:
self.selection.append(self.dirList[item])
print(self.selection)
return self.selection
Question: pass the list with the selected items to the Listbox in the main window
You need a reference of the main window Listbox.
I show, how to using listTask
Extend your __init__ to accept the reference target_listbox
class Add:
def __init__(self, target_listbox, path):
self.target_listbox = target_listbox
Insert the selected items into .target_listbox
Note: Your, return self.selection is useless, a Button.command can't process returns.
def select(self):
selectedRows = self.listbox.curselection()
for item in selectedRows:
self.target_listbox.insert(tk.END, self.dirList[item])
Pass the reference listTask to Add(...
taskBox = Add(listTask, ...)
Here's the code I have written. It's supposed to ask the user for the user's home value and return an assessment value and taxes due.
I'm not sure whether there's an issue with the IDLE on my computer or with my program.
The program is supposed to:
1. ask the user to input their home value
2. give back the assessment value
3. include at least 2 buttons
4. Work (obviously)
import tkinter
class PropertyTaxApp:
def __init__(self):
# Creates main Window
self.main_window
tkinter.mainloop()
#Creates the four frames
self.homevalue_frame = tkinter.Frame(self.main_window)
self.assessmentvalue_frame = tkinter.Frame(self.main_window)
self.propertytaxes_frame = tkinter.Frame(self.main_window)
self.button_frame = tkinter.Frame(self.main_window)
#Create and pack the widgets for the home value
self.homevalue_label = tkinter.Label(self.homevalue_frame,
text = "Enter your home's value here: ")
self.homevalue_entry = tkinter.Entry(self.homevalue_frame,
width=10)
self.homevalue_label.pack(side="left")
self.homevalue_entry.pack(side="left")
#Create and pack the widgets for the assessment value
self.result_label = tkinter.label(self.assessmentvalue_frame,
text="Assessment Value: ")
self.assessmentvalue_label = tkinter.label(self.assessmentvalue_frame,
textvariable=self.assessmentvalue)
self.result_label.pack(side="left")
self.assessmentvalue_label.pack(side="left")
#Create and pack the widgets for the property taxes
self.result_label = tkinter.label(self.propertytaxes_frame,
text="Property Taxes: ")
self.propertytaxes_label = tkinter.label(self.propertytaxes_frame,
textvariable=self.propertytaxes)
self.result_label.pack(side="left")
self.assessmentvalue_label.pack(side="left")
#Create and pack the button widgets
self.calculate_button = tkinter.Button(self.button_frame,
text="Calculate",
command=self.calc_info)
self.quit_button = tkinter.Button(self.button_frame,
text="Quit Program",
command=self.main_window.destroy)
self.calculate_button.pack(side="left")
self.quit_button.pack(side="left")
#Pack frames
self.homevalue_frame.pack()
self.assessmentvalue_frame.pack()
self.propertytaxes_frame.pack()
self.button_frame.pack()
#Start the main loop
tkinter.mainloop()
#the calc_info method is used in the calculate_button widget
def calc_info(self):
#set constants
self.assessmentvaluepct = 0.6
self.propertytaxespct = 0.0075
#get home value input by user
self.homevalue = float(self.homevalue_entry.get())
#calculate the assessment value and property taxes
self.calculatedassessmentvalue=(self.assessmentvaluepct*self.homevalue)
self.calculatedpropertytaxes=(self.propertytaxespct*self.homevalue)
#update the propertytaxes_label widget
self.propertytaxes.set(self.calculatedpropertytaxes)
#update the assessmentvalue_label widget
self.assessment.set(self.calculatedassessmentvalue)
#Run the PropertyTaxApp Class
property_tax_app = PropertyTaxApp()
Thanks so much in advance!
I'm trying to open a second window (defined by the function 'learn') from the main program - the window opens with no problem but the buttons/images don't show up. Does anyone know what I'm doing wrong? All the images are .gif files and sit in the same folder as the program.
I wrote the code under 'learn' in a separate python file. Initially I had tried to open that file as a separate program but it didn't work.
from tkinter import *
import linecache
import os
root = Tk()
root.geometry('1200x800') #Dimensions of the window
root.title("stud(y)ious") #title of the window
container1 = Frame(root)
container1.pack(side = TOP, anchor = W)
container2= Frame(root) #Bottom container
container2.pack(side = BOTTOM,pady = 50) #space between the bottom of the timetable and the two buttons; initially this was cropping the timetable too much so this value was DECREASED in order to shorten the amount of padding that exists around the two buttons at the bottom
#All the images used on the home page; keeping them all in one place so they can be eaisly replaced by anotehr programmer if need be
imgNote = PhotoImage(file='img_note.gif') #'N O T E'
imgHeader = PhotoImage(file='img_title.gif') #'stud(y)ious' 'T I M E T A B L E'
imgTimetable = PhotoImage(file='btn_timetable.gif') #replacable timetable image
imgCreateBtn = PhotoImage(file='btn_create.gif') #'create'
imgLearnBtn = PhotoImage(file='btn_learn.gif') #'learn'
toolbar = Canvas()
Header = Label(toolbar, image = imgHeader).pack() #creation of header, space for imgHeader; above and seperated from main buttons
toolbar.pack()
def destroy(): #closing the window
root.destroy()
def create(): #The window that appears when the 'create' button is clicked
toplevel = Toplevel()
labelCreateHeader = Label(toplevel, image=imgNote) #header graphic
labelCreateHeader.pack()
labelCreateText = Label(toplevel, text=txtCreate) #text (from variable noted below)
labelCreateText.pack()
def learn(): #The window that appears when the 'learn' button is clicked
window1 = Tk()
window1.geometry('1200x800')
window1.title("stud(y)ious: Learn") #title of the window, colon to show connection to studyious_main.py
#Opens the questions file (in read mode) and makes a list of them, one per line
with open('studyious_questions.txt', 'r+') as questionfile:
questions = questionfile.readlines()
#Takes off the '\n' from the end of each line so they are neatly presented and easy to read
questions = [i.strip('\n') for i in questions]
#reading answers; holds a string only - default value ""; type checking
ans1 = StringVar()
ans2 = StringVar()
ans3 = StringVar()
ans4 = StringVar()
ans5 = StringVar()
answers = []
for i in range(1,9):
answers.append(linecache.getline('studyious_answers.txt', i))
answers = [i.strip('\n') for i in answers]
def destroy2():
window1.destroy() #closes window, function attached to '⬅' button
def answering(answer, index): #The window that appears when the 'create' button is clicked
toplevel = Toplevel()
labelCorrectHeader = Label(toplevel, text=txtInfoCorrect, image=imgCorrect) #header graphic
labelCorrect = Label(toplevel, text=txtInfoCorrect) #text (from variable noted below)
labelIncorrectHeader = Label(toplevel, text=txtInfoIncorrect, image=imgIncorrect)
labelIncorrect = Label(toplevel, text=txtInfoIncorrect)
if answer == answers[index]: #selection structure to decide whether the 'correct' (if) or 'incorrect' (else) window pops up
labelCorrectHeader.pack()
labelCorrect.pack()
else:
labelIncorrectHeader.pack()
labelIncorrect.pack()
#The following two text variable were written using triple quotations so the program would register line breaks effectively
txtInfoCorrect = """
Keep up the good work!
Remember, for every 10 questions, take a lil' break <3
"""
txtInfoIncorrect = """
Better luck next time!
Keep going, you can do it!
"""
container01 = Frame(window1)
container01.pack(anchor = W)
ButtonQuit = Button(container01, command=destroy2) #FIXME should open the other python file, containing the homepage
ButtonQuit["text"] = "⬅"
ButtonQuit.pack(side = LEFT, padx = 10, pady = 8)
#Directory of images used in this program
imgCorrect = PhotoImage(file='img_correct.gif')
imgIncorrect = PhotoImage(file='img_incorrect.gif')
imgAnswer = PhotoImage(file='btn_answer.gif')
imgHeaderb = PhotoImage(file='img_header.gif')
toolbar1 = Canvas()
Header1 = Label(toolbar1, image = imgHeaderb).pack() #Placing the header image (img_header) at the top of the page
toolbar1.pack()
#THE QUESTIONS
question1 = Label(window1, text=questions[0]).pack(pady = 10) #states the question according to it's number in the list (e.g this one is 0 because it is the first item in the studyious_questions.txt file
#pady refers to the space between each of teh questions (so things dont look too cluttered and unprofessional)
entry1= Entry(window1, textvariable = ans1) #User can cnter answer to to entry box
entry1.pack()
ButtonAnswer1 = Button(image = imgAnswer,command=lambda:answering(ans1.get(), 0)).pack() #answer button, when clicked entered answer will be checked against teh answer recorded in studyious_answers.txt to see if it is correct
#For example, for the example above, the answer entered by the user is checked against the first answer in the list of answers (index of 0) to see if it correct; promopting a response from the variable 'answering' (which will either produce the 'correct' or 'incorrect dialogue window)
question2 = Label(window1, text=questions[1]).pack(pady = 10)
entry2= Entry(window1, textvariable = ans2)
entry2.pack()
ButtonAnswer2 = Button(image = imgAnswer,command=lambda:answering(ans2.get(), 1)).pack()
question3 = Label(window1, text=questions[2]).pack(pady = 10)
entry3= Entry(window1, textvariable = ans3)
entry3.pack()
ButtonAnswer3 = Button(image = imgAnswer,command=lambda:answering(ans3.get(), 2)).pack()
question4 = Label(window1, text=questions[3]).pack(pady = 10)
entry4= Entry(window1, textvariable = ans4)
entry4.pack()
ButtonAnswer4 = Button(image = imgAnswer,command=lambda:answering(ans4.get(), 3)).pack()
question5 = Label(window1, text=questions[4]).pack(pady = 10)
entry5= Entry(window1, textvariable = ans5)
entry5.pack()
ButtonAnswer5 = Button(image = imgAnswer,command=lambda:answering(ans5.get(), 4)).pack()
window1.mainloop()
txtInfo = """
text
"""
txtCreate = """
text
"""
def timetable():
toplevel = Toplevel() #Ensure window pops up above the main window as a pop up window
labelTimetableHeader = Label(toplevel, image=imgNote) #header graphic to match aesthetic of the rest of the program
labelTimetableHeader.pack()
labelTimetableText = Label(toplevel, text=txtInfo) #The main body of text (as seen above in txtInfo)
labelTimetableText.pack()
btnQuit = Button(container1,command=destroy) #Quit button, closes window
btnQuit["text"] = "Quit"
btnQuit.pack(side = LEFT, padx = 10, pady = 8) #the difference between the top and left padding is that there is automatically two points of padding from the top of the window
TimetableButton = Button(image = imgTimetable,command=timetable).pack() #a replacable image that allows users to enter place their own timetable on the home page
#Initially the button sat squished in the corner whih made the finishing of the home page look very rough, cluttered and unprofessional
#Button 1; opens a small window giving the user details of how to enter the questions and answers they wish to test themselves on
btnCreate = Button(container2, image = imgCreateBtn,command=create).pack(side = LEFT, padx =100) #padding around teh sides seperates the two buttons - 'create' and 'learn'
#Button 2; redirect to the quiz program, opening another window with the quiz program
btnLearn = Button(container2, image = imgLearnBtn,command=learn).pack(side = BOTTOM, padx = 100)
root.mainloop()
You forgot to put window1 as the master of any of your buttons like this one:
ButtonAnswer1 = Button(image = imgAnswer,command=lambda:answering(ans1.get(), 0)).pack()
add window1 to all your ButtonAnswer1-5:
ButtonAnswer1 = Button(window1, image = imgAnswer,command=lambda:answering(ans1.get(), 0)).pack()
I want to present several questions, one after another. The first question is shown as I like, with the cursor set in the entry field. Then I destroy the window and call the function again to create a new window. This time the window is not shown in the front and therefore I first have to click on the screen in order to have the cursor set to the entry field. Also the escape key does not work until I click on the screen to bring the window to the top. I'd be very happy for your help!
Thank you in advance!
Here's my code:
from Tkinter import *
def text_input_restricted(fn,question, nr_letters, limit, len_min, len_max,keys, justify):
class MyApp():
def validate(root, S):
return all(c in keys for c in S)
def __init__(self, q= None):
#save response after "next"-button has been clicked
def okClicked():
lines = e.get()
if len_min < len(lines) < len_max:
lines = unicode(lines).encode('utf-8')
datFile = open(fn, "a")
datFile.write(" '%s'"%(lines))
datFile.close()
self.root.destroy()
self.root = Tk()
vcmd = (self.root.register(self.validate), '%S')
#quit if escape-key has been pressed
self.root.bind('<Escape>', lambda q: quit())
#colors
color = '#%02x%02x%02x' % (200, 200, 200)
self.root.configure(bg=color)
#set window size to screen size
RWidth=MAXX
RHeight=MAXY
self.root.geometry(("%dx%d")%(RWidth,RHeight))
#remove buttons (cross, minimize, maximize)
self.root.overrideredirect(1)
#remove title
self.root.title("")
#item
labelWidget = Label(self.root,text=question, font=("Arial", int(0.02*MAXX)), bd=5, bg=color, justify="center")
labelWidget.place(x=0, y=RHeight/40,width=RWidth)
#"next"-button
ok_width = RWidth/15
ok_height = RWidth/15
okWidget = Button(self.root, text= "next", command = okClicked, font=("Arial",int(0.015*MAXX)), bd=5, justify="center")
okWidget.place(x=RWidth/2-ok_width/2,y=13*RHeight/40, width=ok_width,height=ok_height)
def callback(sv):
c = sv.get()[0:limit]
sv.set(c)
sv = StringVar()
width=nr_letters * int(0.02*MAXX)*1.3
sv.trace("w", lambda name, index, mode, sv=sv: callback(sv))
e = Entry(self.root, textvariable=sv,font=("Arial", int(0.02*MAXX)),justify=justify,validate="key", validatecommand=vcmd)
e.place(x=RWidth/2-width/2, y=9*RHeight/40, width=width)
#show cursor
e.focus_set()
self.root.mainloop()
MyApp()
MAXX=1366
MAXY=768
fn = "D:/test.dat"
text_input_restricted(fn = fn, question=u"f for female, m for male", nr_letters=1, limit =1, len_min =0, len_max=2, keys = 'fm', justify="center")
text_input_restricted(fn = fn, question="How old are you?", nr_letters=2,limit=2, len_min = 1, len_max = 3, keys = '1234567890',justify="center")
In Tk you use the raise command to bring a window to the front of the Z-order. However, raise is a keyword in Python so this has been renamed to lift. Provided your application is still the foreground application you can call the lift() method on a toplevel widget. If the application is not the foreground application then this will raise the window but only above other windows from the same application. On Windows this causes the taskbar icon for your application to start flashing.
You might do better to destroy the contents of the toplevel and replace them. Or even better - create a number of frames holding each 'page' of your application and toggle the visibility of each frame by packing and pack_forgetting (or grid and grid forget). This will avoid loosing the focus completely - you can just set the focus onto the first widget of each frame as you make it visible.