Tkinter Add/Remove "windows" within current window - python

Basically below is what I have right now. The problem is that each of these buttons opens a new window and I would prefer that in the top right I have the current function such as add course shown and then when I click the "add time" the add course would be removed and the add time be shown. Is there a way I could do this for each of the "editing" dict operations and also have an "up-to-date" table printed in the bottom right of this window? Thanks.
class menu():
def __init__(self, master):
self.master = master
self.table = {}
self.createButtons()
# creates buttons with alignment and their functions
def createButtons(self):
load = Button(self.master, text = "Load Table",
command = self.loadTable)
load.grid(row =0, column =0, pady = 30)
course = Button(self.master, text = "Add Course",
command = self.addCourse)
course.grid(row =1, column =0, pady = 30)
time = Button(self.master, text = "Add Time",
command = self.addTime)
time.grid(row =2, column =0, pady = 30)
reset = Button(self.master, text = "Reset Time",
command = self.resetTime)
reset.grid(row =3, column =0, pady = 30)
comment = Button(self.master, text = "Change Comment",
command = self.changeComment)
comment.grid(row =4, column =0, pady = 30)
view = Button(self.master, text = "View Table",
command = self.viewTable)
view.grid(row =5, column =0, pady = 30)
def addCourse(self):
#creates addCourse window and text boxes for input
toplevel = Toplevel()
toplevel.title('Add Course')
Label (toplevel, text='Enter the course name').grid()
courseBox = Entry(toplevel, width=10)
courseBox.grid()
label =Label (toplevel, text='Enter the hours per week spent on course')
label.grid(padx=10,pady=10)
weekHoursBox = Entry(toplevel, width=10)
weekHoursBox.grid()
#function to accept input from boxes into dict
def callback():
course = courseBox.get()
weekHours = weekHoursBox.get()
string = "0 "+ str(weekHours) + " "
self.table[course] = string
enterB = Button(toplevel, text='Enter Information', command = callback)
enterB.grid(pady=10)

Working example - I hope it is what you expected.
from Tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.master = master
self.table = {}
self.rightFrame = None # for first "grid_forget()"
self.createButtons()
#-----------------------------
def run(self):
self.master.mainloop()
#-----------------------------
# creates buttons with alignment and their functions
def createButtons(self):
self.menuFrame = Frame(self.master)
self.menuFrame.grid(row=0, column=0)
load = Button(self.menuFrame, text="Load Table", command=self.loadTable)
load.grid(row=0, column=0, pady=30)
course = Button(self.menuFrame, text="Add Course", command=self.addCourse)
course.grid(row=1, column=0, pady=30)
time = Button(self.menuFrame, text="Add Time", command=self.addTime)
time.grid(row=2, column=0, pady=30)
reset = Button(self.menuFrame, text="Reset Time", command=self.resetTime)
reset.grid(row=3, column=0, pady=30)
comment = Button(self.menuFrame, text="Change Comment", command=self.changeComment)
comment.grid(row=4, column=0, pady=30)
view = Button(self.menuFrame, text="View Table", command=self.viewTable)
view.grid(row=5, column=0, pady=30)
#-----------------------------
def loadTable(self):
# remove previous content
if self.rightFrame:
self.rightFrame.grid_forget()
# create new content
self.rightFrame = Frame(self.master)
self.rightFrame.grid(row=0, column=1, sticky=N)
title = Label(self.rightFrame, text='load Table')
title.grid(row=0, column=0)
#-----------------------------
def addCourse(self):
# remove previous content
if self.rightFrame:
self.rightFrame.grid_forget()
# create new content
self.rightFrame = Frame(self.master)
self.rightFrame.grid(row=0, column=1, sticky=N)
#creates addCourse window and text boxes for input
title = Label(self.rightFrame, text='Enter the course name')
title.grid(row=0, column=0)
courseBox = Entry(self.rightFrame, width=10)
courseBox.grid(row=1, column=0)
label = Label (self.rightFrame, text='Enter the hours per week spent on course')
label.grid(row=2, column=0)
weekHoursBox = Entry(self.rightFrame, width=10)
weekHoursBox.grid(row=3, column=0)
#function to accept input from boxes into dict
def callback():
course = courseBox.get()
weekHours = weekHoursBox.get()
string = "0 "+ str(weekHours) + " "
self.table[course] = string
enterB = Button(self.rightFrame, text='Enter Information', command=callback)
enterB.grid(row=4, column=0)
#-----------------------------
def addTime(self):
# remove previous content
if self.rightFrame:
self.rightFrame.grid_forget()
# create new content
self.rightFrame = Frame(self.master)
self.rightFrame.grid(row=0, column=1, sticky=N)
title = Label(self.rightFrame, text='Add Time')
title.grid(row=0, column=0)
#-----------------------------
def resetTime(self):
# remove previous content
if self.rightFrame:
self.rightFrame.grid_forget()
# create new content
self.rightFrame = Frame(self.master)
self.rightFrame.grid(row=0, column=1, sticky=N)
title = Label(self.rightFrame, text='Reset Time')
title.grid(row=0, column=0)
#-----------------------------
def changeComment(self):
# remove previous content
if self.rightFrame:
self.rightFrame.grid_forget()
# create new content
self.rightFrame = Frame(self.master)
self.rightFrame.grid(row=0, column=1, sticky=N)
title = Label(self.rightFrame, text='Change Comment')
title.grid(row=0, column=0)
#-----------------------------
def viewTable(self):
# remove previous content
if self.rightFrame:
self.rightFrame.grid_forget()
# create new content
self.rightFrame = Frame(self.master)
self.rightFrame.grid(row=0, column=1, sticky=N)
title = Label(self.rightFrame, text='View Table')
title.grid(row=0, column=0)
#----------------------------------------------------------------------
Application(Tk()).run()

Related

Python Tkinter how to list down, but the newest element is on top

I am working on a little finance project. When I add to my balance, the entry gets listed among themselves. But I want to "change direction", so the newest entry is always on row 3 and the others lists among themselves. The problem is I don't know how to access to the other Elements to add to their row.
It should be something like that:
I entry a amount to add to the main balance- for example 40$
It gets shown on column 0, row 3
If I add another amount it should show on row 3- for example 20$, and the 40$ should move to row 4.
It should get listed like that:
row 3: 20$ ,
row 4: 40$
and so on..
Sorry for beginner mistakes, Im new to python :)
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class App():
def __init__(self):
self.window = tk.Tk()
self.window.title("Expenses")
self.window.geometry("700x600")
self.window.resizable(0,0)
self.username_list = ["a"]
self.password_list = ["a"]
self.balace = 90
self.row_first_column = 2
self.start_frame()
self.window.mainloop()
def start_frame(self):
self.window.columnconfigure(0, weight=1)
self.window.columnconfigure(1, weight=1)
self.window.columnconfigure(2, weight=1)
self.heading_label = ttk.Label(self.window, text="Log-In", font=("", 25))
self.heading_label.grid(column=1, row=0, sticky=tk.NS, pady=40)
self.username = ttk.Label(self.window, text="Username:")
self.username.grid(column=1, row=1, sticky=tk.W, pady=30)
self.password = ttk.Label(self.window, text="Password:")
self.password.grid(column=1, row=2, sticky=tk.W)
self.entry1 = ttk.Entry(self.window)
self.entry1.grid(column=1, row=1)
self.entry2 = ttk.Entry(self.window)
self.entry2.grid(column=1, row=2)
self.warning = ttk.Label(self.window, text="")
self.warning.grid(column=1, row=3, sticky= tk.NS, pady=10)
self.button1 = ttk.Button(self.window, text="Submit", command= self.check_data)
self.button1.grid(column=1, row=4, sticky=tk.NS)
def check_data(self):
username_check = self.entry1.get()
password_check = self.entry2.get()
if username_check in self.username_list and password_check in self.password_list:
self.main_frame()
else:
self.warning.configure(text="Incorrect data! Try again")
self.entry2.delete(0, tk.END)
def main_frame(self):
self.username.destroy()
self.password.destroy()
self.entry1.destroy()
self.entry2.destroy()
self.warning.destroy()
self.button1.destroy()
self.heading_label.configure(text="Finance", font=("", 25))
#First Column
self.sub_heading1 = ttk.Label(self.window, text="Overview", font=("", 15))
self.sub_heading1.grid(column=0, sticky=tk.NS, row=1, pady=20)
self.balance_label = ttk.Label(self.window, text=f"{self.balace}$")
self.balance_label.grid(column=0, row=2, pady=20, sticky=tk.NS)
#Second Column
self.sub_heading2 = ttk.Label(self.window, text="Add", font=("", 15))
self.sub_heading2.grid(column=1, sticky=tk.NS, row=1, pady=20)
self.add_balance = ttk.Entry(self.window, width=5)
self.add_balance.grid(column=1, row=2, pady=20, sticky=tk.NS)
self.add_button = ttk.Button(self.window, text="Add",width=3, command= self.entry_add_balance)
self.add_button.grid(column=1, row=3, pady=10, sticky=tk.NS)
#Third Column
self.sub_heading3 = ttk.Label(self.window, text="Minus", font=("", 15))
self.sub_heading3.grid(column=2, sticky=tk.NS, row=1, pady=20)
def entry_add_balance(self):
addjust_balance_user = int(self.add_balance.get())
self.add_balance.delete(0, tk.END)
self.balace += addjust_balance_user
self.balance_label.configure(text=f"{self.balace}$")
#First Column
self.row_first_column += 1
new_add_label = ttk.Label(self.window, text=f"+{addjust_balance_user}$")
new_add_label.grid(column=0, row=self.row_first_column, pady=5,padx=15, sticky=tk.E)
app = App()

Python classes with tkinter unable to parse object items

I am wanting to use a class as normal and parse through data use the self instance. My aim is to be able to create many displays/screens that show graph data using matplotlib. I want a user to be able to select a csv file and a view of the data is listed.
I am having trouble returning the data from another file. I have a csv upload class that gets the data from a csv. The data is then put into a text variable and is called by a class. I am wanting to return this data to the DES class so that the data can be viewed but I am finding that I need to know the instance in order to access the class. Any help is appreciated. Please feel free to ask questions.
DES Class
i = 0
class DES(Frame):
def __init__(self, master, summary):
global i
self.master = master
self.frame = tk.Frame(self.master, width=750, height=968,bg='white')
self.summary = summary
self.upload_button = tk.Button(
self.frame,
text="Options",
fg="DodgerBlue4",
font=("Graph Type", 15),
height=1, width=12,
borderwidth=2,
relief="groove",
command=self.menu)
self.des_button = tk.Button(
self.frame,
text="New DES",
fg="DodgerBlue4",
font=("Graph Type", 15),
height=1, width=12,
borderwidth=2,
relief="groove",
command=self.new_des)
self.logout_buttotn = tk.Button(
self.frame,
text="Logout",
font=("Arial", 15),
height=1, width=12,
borderwidth=2,
relief="groove",
fg="red",
command = self.close)
self.chat_submit_button = tk.Button(
self.frame,
text="Submit",
font=("Arial", 9),
height=1, width=12,
# command=self.set_chat_text,
borderwidth=2,
relief="groove")
self.chat_input = tk.Entry(
self.frame,
width=55,
font=("Arial", 14), highlightthickness=0,
bg="white", borderwidth=1, relief="solid")
self.summary_output = tk.Text(
self.frame,
height=8,
width=78,
bg="gray95",
borderwidth=2,
relief="groove",
font=("Arial", 12))
self.summary_output.configure(state='disabled')
self.chat_output = tk.Text(
self.frame,
height=8,
width=78,
bg="gray95",
borderwidth=2,
relief="groove",
font=("Arial", 12))
self.chat_output.insert(INSERT, "Chat: \n")
self.chat_output.configure(state='disabled')
self.combo_box_graph = ttk.Combobox(
self.frame,
width=12,
justify='center',
font=("Arial", 22),
state="readonly")
self.combo_box_graph['values'] = (
'Select',
'Line Graph',
'Bar Graph',
'Histogram',
'Scatter Graph')
# s = tk.StringVar()
self.combo_box_graph.current(0)
# self.combo_box_graph.bind("<<ComboboxSelected>>", view_graph)
font = Font(family = "Helvetica", size = 12)
self.frame.option_add("*TCombobox*Listbox*Font", font)
# IMPLEMENTING GRAPH ------------------------------------------------------
fig = Figure(figsize=(5, 4), dpi=130) # Create graph figure
plt.ax = fig.add_subplot(111) # Add plots
self.canvas = FigureCanvasTkAgg(fig, self.master) # tk implementation
self.canvas.draw() # Create the graph canvas
# # IMPLEMENTING TOOLBAR ----------------------------------------------------
toolbarFrame = Frame(self.master)
toolbarFrame.pack(side=TOP, fill=BOTH) # Place toolbar at top of screen
toolbar = NavigationToolbar2Tk(self.canvas, toolbarFrame)
self.upload_button.place(x=20, y=560)
self.combo_box_graph.place(x=170, y=560)
self.summary_output.place(x=20, y=610)
self.chat_output.place(x=20, y=770)
self.chat_input.place(x=20, y=920)
self.chat_submit_button.place(x=633, y=920)
self.logout_buttotn.place(x=585, y=560)
self.canvas.get_tk_widget().place(x=50, y=30)
if i == 0:
self.des_button.place(x=395, y=560)
i += 1
self.frame.pack()
def new_des(self):
self.newWindow = tk.Toplevel(self.master)
self.app = DES(self.newWindow)
def menu(self):
self.newWindow = tk.Toplevel(self.master)
self.app = upload_csv(self.newWindow)
def close(self):
self.master.destroy()
def set_chat_text(self):
self.chat_output.configure(state='normal')
self.chat_output.insert('end', self.chat_input.get() + '\n')
self.chat_output.configure(state='disabled')
self.chat_input.delete(0, END)
def set_summary_text(self):
self.summary_output.configure(state='normal')
self.summary_output.delete('1.0', END) # Remote all text
self.summary_output.insert('end', self.summary)
self.summary_output.configure(state='disabled') #Make text widget read only
def main():
root = tk.Tk()
app = DES(root, "")
root.mainloop()
if __name__ == '__main__':
main()
Upload CSV file:
text = ""
class upload_csv(Frame):
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master, width=250, height=160, bg='white')
self.upload_csv_btn = Button(
self.frame,
text="Add Data Source",
fg="DodgerBlue4",
font=("Graph Type", 15),
height=1, width=20,
borderwidth=2,
relief="groove",
command=self.upload)
self.merge_btn = Button(
self.frame,
text="Combine CSV Files",
command=merge_csv,
font=("Arial", 15),
height=1, width=20,
borderwidth=2,
relief="groove",
fg="DodgerBlue4")
self.close_btn = Button(
self.frame,
text="Close",
font=("Arial", 15),
height=1, width=20,
borderwidth=2,
relief="groove",
fg="red",
command=self.close_windows)
self.upload_csv_btn.place(x=10, y=10)
self.merge_btn.place(x=10, y=60)
self.close_btn.place(x=10, y=110)
self.frame.pack()
def close_windows(self):
self.master.destroy()
def upload(self):
global text
self.xvalues = []
self.yvalues = []
self.xyvalues = []
self.header = []
self.xvalues.clear()
self.yvalues.clear()
self.xyvalues.clear()
self.header.clear()
# csv_quit()
filename = filedialog.askopenfilename()
if len(filename) != 0:
print('Selected:', filename)
with open(filename) as file:
csvreader = csv.reader(file)
self.header.append(next(csvreader))
for row in csvreader:
if len(row) == 3:
self.xvalues.append(int(row[0]))
self.yvalues.append(int(row[1]))
self.xyvalues.append(int(row[2]))
text = (
self.header[0][0]+ ": " + str(self.xvalues).replace('[','').replace(']','') +
"\n\n" + self.header[0][1] + ": " + str(self.yvalues).replace('[','').replace(']','') +
"\n\n" + self.header[0][2] + ": " + str(self.xyvalues).replace('[','').replace(']',''))
elif len(row) == 2:
self.xvalues.append(row[0])
self.yvalues.append(row[1])
text = (
self.header[0][0] + ": " + str(self.xvalues).replace('[','').replace(']','') +
"\n\n" + self.header[0][1] + ": " + str(self.yvalues).replace('[','').replace(']',''))
s = Set(text)
s.set_summary()
My set class:
class Set:
def __init__ (self, summary):
self.summary = summary
def set_summary(self):
print(self.summary)
s = DES(self.summary)
DES.set_summary_text()
When I get the text variable I am calling a function in the set class, I am then wanting to use that to call the set_summary function in the DES class but I cant due to not proving an instance. Please help.

Python/Tkinter: How to display a blank bottom frame when the application is run first?

When the application is run first, the last frame's widgets are displayed on the screen. What i wanted to do is, displaying the related frames when the user clicks their buttons. So, i want to display a blank frame with the top buttons. In order to do that, what should i do? (I removed the button functions, because they are not related to the question.) Thanks in advance.
import tkinter as tk
class TopFrame(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.grid(row=0, column=0, sticky="nsew")
self.BottomFrame = tk.Frame(master=master)
self.BottomFrame.grid(row=1, column=0, sticky="nsew")
self.f1 = tk.Frame(master=self.BottomFrame)
self.f2 = tk.Frame(master=self.BottomFrame)
self.f3 = tk.Frame(master=self.BottomFrame)
for f in (self.f1, self.f2, self.f3):
f.grid(row=0, column=0, sticky="nsew")
self.b1 = tk.Button(master=self, text="Add Words")
self.b2 = tk.Button(master=self, text="Add From File")
self.b3 = tk.Button(master=self, text="Change Words")
self.add_button = tk.Button(master=self.f1, text="Add")
self.open_button = tk.Button(master=self.f2, text="Open File")
self.change_button = tk.Button(master=self.f3, text="Change")
self.l1 = tk.Label(master=self.f1, text="English")
self.l2 = tk.Label(master=self.f1, text="Turkish")
self.l3 = tk.Label(master=self.f3, text="Old word")
self.l4 = tk.Label(master=self.f3, text="New word")
self.e1 = tk.Entry(master=self.f1)
self.e2 = tk.Entry(master=self.f1)
self.e3 = tk.Entry(master=self.f3)
self.e4 = tk.Entry(master=self.f3)
self.configure_buttons()
self.configure_labels()
self.configure_entries()
def configure_buttons(self):
self.b1.grid(row=0, column=0)
self.b1.configure(command=lambda: self.f1.tkraise())
self.b2.grid(row=0, column=1)
self.b2.configure(command=lambda: self.f2.tkraise())
self.b3.grid(row=0, column=2)
self.b3.configure(command=lambda: self.f3.tkraise())
self.add_button.grid(row=2, columnspan=2)
#self.add_button.configure(command=self.add_word)
self.open_button.pack(side="top")
#self.open_button.configure(command=self.add_from_file)
self.change_button.grid(row=2, columnspan=2)
def configure_labels(self):
self.l1.grid(row=0, column=0)
self.l2.grid(row=0, column=1)
self.l3.grid(row=0, column=0)
self.l4.grid(row=0, column=1)
def configure_entries(self):
self.e1.grid(row=1, column=0)
self.e2.grid(row=1, column=1)
self.e3.grid(row=1, column=0)
self.e4.grid(row=1, column=1)
if __name__ == "__main__":
root = tk.Tk()
example = TopFrame(master=root)
example.mainloop()
Instead of having 3 widgets in the same location, it's better to have only the one you need.
First, get rid of this code:
for f in (self.f1, self.f2, self.f3):
f.grid(row=0, column=0, sticky="nsew")
Now the frame will start in a blank state.
Then, instead of calling .tkraise() on the frames, we will remove the current frame (if any) and add another one in its place. So
self.b1.configure(command=lambda: self.f1.tkraise())
self.b2.configure(command=lambda: self.f2.tkraise())
self.b3.configure(command=lambda: self.f3.tkraise())
becomes:
self.b1.configure(command=lambda: self._activate(self.f1))
self.b2.configure(command=lambda: self._activate(self.f2))
self.b3.configure(command=lambda: self._activate(self.f3))
with
def _activate(self, frame):
# remove the current frame
for child in self.BottomFrame.winfo_children():
child.grid_forget()
# add the new frame in its place
frame.grid(row=0, column=0, sticky='nsew')

Tkinter displaying button instead of Label

I am creating a little app that will take in details from the user about a bank transaction and then display it in a table.
I am currently using a CSV file to store the data and then when a new piece of data is put in, it will display that too.
I have a list of labels and then a button at the bottom of them to submit new entry. The problem I am getting is when the length of the table exceeds what it was to begin with there is a display error.
class accountant(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
master.title("Accountant")
self.pack()
self.numIncoming = 0
self.numOutgoing = 0
self.incoming = fs.fileStore("incoming", "csv")
print("log: incoming.csv opened sucessfully")
self.outgoing = fs.fileStore("outgoing", "csv")
print("log: outgoing.csv opened sucessfully")
self.setup()
def setup(self):
self.paint()
self.incomingData()
self.outgoingData()
self.newEntryButtons()
def paint(self):
tk.Label(self, width=45, text="incoming").grid(row=1, column=0, columnspan=45)
tk.Label(self, width=45, text="outgoing").grid(row=1, column=45, columnspan=45)
tk.Label(self, width=15, text="Date").grid(row=2, column=0, columnspan=15)
tk.Label(self, width=15, text="Transaction Name").grid(row=2, column=15, columnspan=15)
tk.Label(self, width=15, text="Amount").grid(row=2, column=30, columnspan=15)
tk.Label(self, width=15, text="Date").grid(row=2, column=45, columnspan=15)
tk.Label(self, width=15, text="Transaction Name").grid(row=2, column=60, columnspan=15)
tk.Label(self, width=15, text="Amount").grid(row=2, column=75, columnspan=15)
def incomingData(self):
self.incoming.closeFile()
self.incoming.openFile()
i = 3
for cell in self.incoming.reader:
#cell[0] = Date, cell[1]= Transaction Name, cell[2] =amount
tk.Label(self, width=15, text=cell[0]).grid(row=i, column=0, columnspan=15)
tk.Label(self, width=15, text=cell[1]).grid(row=i, column=15, columnspan=15)
tk.Label(self, width=15, text=cell[2]).grid(row=i, column=30, columnspan=15)
i += 1
self.numIncoming = i
print("incoming:", self.numIncoming-3)
print("outgoing:", self.numOutgoing-3)
def outgoingData(self):
self.outgoing.closeFile()
self.outgoing.openFile()
i = 3
for cell in self.outgoing.reader:
#cell[0] = Date, cell[1]= Transaction Name, cell[2] =amount
tk.Label(self, width=15, text=cell[0]).grid(row=i, column=45, columnspan=15)
tk.Label(self, width=15, text=cell[1]).grid(row=i, column=60, columnspan=15)
tk.Label(self, width=15, text=cell[2]).grid(row=i, column=75, columnspan=15)
i += 1
self.numOutgoing = i
print("incoming:", self.numIncoming-3)
print("outgoing:", self.numOutgoing-3, '\n\n')
def newEntryButtons(self):
if(self.numIncoming < self.numOutgoing):
tk.Button(self, text="new incoming", width=45, command=lambda: self.newEntry(self.incoming)).grid(row=self.numOutgoing, column=0, columnspan=45)
tk.Button(self, text="new outgoing", width=45, command=lambda: self.newEntry(self.outgoing)).grid(row=self.numOutgoing, column=45, columnspan=45)
else:
tk.Button(self, text="new incoming", width=45, command=lambda: self.newEntry(self.incoming)).grid(row=self.numIncoming, column=0, columnspan=45)
tk.Button(self, text="new outgoing", width=45, command=lambda: self.newEntry(self.outgoing)).grid(row=self.numIncoming, column=45, columnspan=45)
def newEntry(self, inFile):
win = tk.Toplevel()
self.newName = tk.StringVar()
self.newDate = tk.StringVar()
self.newAmount = tk.StringVar()
tk.Label(win, width=5, text="Name:").grid(row=0, column=0, columnspan=5)
tk.Entry(win, textvariable=self.newName).grid(row=0, column=5, columnspan=5)
tk.Label(win, width=5, text="date:").grid(row=1, column=0, columnspan=5)
tk.Entry(win, textvariable = self.newDate).grid(row=1, column=5, columnspan=5)
tk.Label(win, width=5, text="amount: £").grid(row=2, column=0, columnspan=5)
tk.Entry(win, textvariable=self.newAmount).grid(row=2, column=5, columnspan=5)
button = tk.Button(win, text="submit", width=5, command= lambda: self.submit(win, inFile))
button.grid(row=5, column=5, columnspan=5)
def submit(self, win, inFile):
with open(inFile.file, 'a') as f:
string= '\n'+self.newName.get() + ',' + self.newDate.get() + ',' + self.newAmount.get()
f.write(string)
if inFile.fileName == "incoming":
self.numIncoming += 1
# print("incoming:", self.numIncoming-3)
# print("outgoing:", self.numOutgoing-3)
else:
self.numOutgoing += 1
print("outgoing:", self.numOutgoing-3)
win.destroy()
self.setup()
filestore is just a class that basically opens the csv using
reader = csv.reader(open(file+'.'fileExt)) where file and fileExt are the parameters passed in.
Here is the image after a new entry. the bottom two buttons should stay as they are and the top two should be d e f in the left column and just whitespace in the right column
Replace self.pack() with self.grid(). To change a Label to Button you will, in addition, have to define a command function that executes when the Button is pressed, see the code below
bttn = tk.Button(self, text = "buttontitle", command = self.do_function )
bttn.grid(row = 14, column = 4, sticky = W)
def do_function():
print "HI"

Adding a scrollbar to a frame using Tkinter (Python)

I've a simple GUI thats shows the users some options, after putting the number of the initial options to be shown. In this case, 4:
By clicking on Add row you can add a row to the GUI. The thing is that if the user wants 100 options, the GUI becomes extra big and all the options are not shown.
So I would like to have a scrollbar only on the options space, not the rest parts. Sorry for the bad Photoshop, but I would like to have something like this:
The options space is the FrameTwo, so I would like to have the entire FrameTwo inside of scrollbar like the image above.
# -*- coding: utf-8 -*-
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import datetime
class Planificador(Frame):
def __init__(self,master):
Frame.__init__(self, master)
self.master = master
self.initUI()
def initUI(self):
self.master.title("Plan")
self.frameOne = Frame(self.master)
self.frameOne.grid(row=0,column=0)
self.frameTwo = Frame(self.master)
self.frameTwo.grid(row=1, column=0)
self.frameThree = Frame(self.master)
self.frameThree.grid(row=2, column=0)
# Borrar esto?
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
self.piezastext = Label(self.frameOne, text = " Amount of pieces ", justify="center")
self.piezastext.grid(row=1, column=0)
self.entrypiezas = Entry(self.frameOne,width=3)
self.entrypiezas.grid(row=2, column=0, pady=(5,5))
self.aceptarnumpiezas = Button(self.frameOne,text="Click me", command=self.aceptar_piezas,width=8)
self.aceptarnumpiezas.grid(row=6, column=0, pady=(5,5))
def aceptar_piezas(self):
try:
val = int(self.entrypiezas.get())
self.aceptar_piezas_ok()
except ValueError:
showerror('Error', "Introduce un numero")
def aceptar_piezas_ok(self):
self.num_piezas = self.entrypiezas.get()
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
self.optionmenus_piezas = list()
self.numpiezas = []
self.numerolotes = []
self.optionmenus_prioridad = list()
self.lotes = list()
self.mispiezas = ['One', 'Two', 'Three', 'Four', 'Five']
self.n = 1
while self.n <= int(self.num_piezas):
self.textopieza = Label(self.frameTwo, text = "Pieza: ", justify="left")
self.textopieza.grid(row=self.n, column=0)
var = StringVar()
menu = OptionMenu(self.frameTwo, var, *self.mispiezas)
menu.config(width=10)
menu.grid(row=self.n, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.frameTwo, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=self.n, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.frameTwo,width=6)
self.entrynumpiezas.grid(row=self.n, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.frameTwo, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=self.n, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.frameTwo, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=self.n, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.frameTwo, text = "Por lotes?", justify="center")
self.lotestext.grid(row=self.n, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.frameTwo, variable=self.var1)
self.entrynumlotes.grid(row=self.n, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.n += 1
self.anadirpiezas = Button(self.frameThree, text="Add row", command=self.addpieza, width=10)
self.anadirpiezas.grid(row=0, column=2, pady=(10,10))
self.calculotext = Label(self.frameThree, text = "Other stuff ")
self.calculotext.grid(row=1, column=2, padx=(10,0), pady=(10,10))
self.graspbutton = Button(self.frameThree, text="OPT 1", width=10)
self.graspbutton.grid(row=2, column=1)
self.parettobutton = Button(self.frameThree, text="OPT 2",width=10)
self.parettobutton.grid(row=2, column=2, pady=(10,10), padx=(10,0))
self.parettoEvolbutton = Button(self.frameThree, text="OPT 2", width=10)
self.parettoEvolbutton.grid(row=2, column=3, pady=(10,10), padx=(10,0))
def addpieza(self):
self.textopiezanuevo = Label(self.frameTwo, text = "Pieza: ", justify="left")
self.textopiezanuevo.grid(row=int(self.num_piezas)+1, column=0)
var = StringVar()
menu = OptionMenu(self.frameTwo, var, *self.mispiezas)
menu.grid(row=self.n, column=1)
menu.config(width=10)
menu.grid(row=int(self.num_piezas)+1, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.frameTwo, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=int(self.num_piezas)+1, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.frameTwo,width=6)
self.entrynumpiezas.grid(row=int(self.num_piezas)+1, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.frameTwo, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=int(self.num_piezas)+1, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.frameTwo, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=int(self.num_piezas)+1, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.frameTwo, text = "Por lotes?", justify="center")
self.lotestext.grid(row=int(self.num_piezas)+1, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.frameTwo, variable=self.var1)
self.entrynumlotes.grid(row=int(self.num_piezas)+1, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.num_piezas = int(self.num_piezas)+1
if __name__ == "__main__":
root = Tk()
aplicacion = Planificador(root)
root.mainloop()
FrameOne is used to put an image I removed to make this example more simple. And FrameThree are the buttons you can see at the bottom of the GUI.
So it would be very helpful if someone could give me a hand and tell me how to put the entire FrameTwo inside of a scrollbar as you can see on the third image.
Thanks in advance.
One of your problems, is that "frameTwo" has no limits to it's size. If you don't limit it's size, any scrollbar you add, never will act. But limiting the size of you frame have the inconvenient of limit the number of lines you can grid, making the scrollbar useless again.
A solution is creating a frame inside the "frameTwo", to receive the pieces you create. This way, by one hand, allow you to limit the size of "frameTwo" and attach the scrollbar to it, and by other hand, allow you to grid the pieces you add to the frame located inside "frameTwo", named, let's say, "ListFrame". when "ListFrame" size becomes bigger than "frameTwo" size, you can now make the scrollbar work.
I change your code with the changes mentioned above. Check it out.
The changes are commented in the code.
Sorry for the short explanation, but i'm a bit hurry. I may edit this answer when I have more time.
PS: Sorry if my english is not the best
# -*- coding: utf-8 -*-
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import datetime
class Planificador(Frame):
def __init__(self,master):
Frame.__init__(self, master)
self.master = master
self.initUI()
def initUI(self):
self.master.title("Plan")
self.frameOne = Frame(self.master)
self.frameOne.grid(row=0,column=0)
self.frameTwo = Frame(self.master)
self.frameTwo.grid(row=1, column=0)
#Creating of a new frame, inside of "frameTwo" to the objects to be inserted
#Creating a scrollbar
#The reason for this, is to attach the scrollbar to "FrameTwo", and when the size of frame "ListFrame" exceed the size of frameTwo, the scrollbar acts
self.canvas=Canvas(self.frameTwo)
self.listFrame=Frame(self.canvas)
self.scrollb=Scrollbar(self.master, orient="vertical",command=self.canvas.yview)
self.scrollb.grid(row=1, column=1, sticky='nsew') #grid scrollbar in master, but
self.canvas['yscrollcommand'] = self.scrollb.set #attach scrollbar to frameTwo
self.canvas.create_window((0,0),window=self.listFrame,anchor='nw')
self.listFrame.bind("<Configure>", self.AuxscrollFunction)
self.scrollb.grid_forget() #Forget scrollbar because the number of pieces remains undefined by the user. But this not destroy it. It will be "remembered" later.
self.canvas.pack(side="left")
self.frameThree = Frame(self.master)
self.frameThree.grid(row=2, column=0)
# Borrar esto?
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
self.piezastext = Label(self.frameOne, text = " Amount of pieces ", justify="center")
self.piezastext.grid(row=1, column=0)
self.entrypiezas = Entry(self.frameOne,width=3)
self.entrypiezas.grid(row=2, column=0, pady=(5,5))
self.aceptarnumpiezas = Button(self.frameOne,text="Click me", command=self.aceptar_piezas,width=8)
self.aceptarnumpiezas.grid(row=6, column=0, pady=(5,5))
def AuxscrollFunction(self,event):
#You need to set a max size for frameTwo. Otherwise, it will grow as needed, and scrollbar do not act
self.canvas.configure(scrollregion=self.canvas.bbox("all"),width=600,height=500)
def aceptar_piezas(self):
#IMPORTANT!!! All the objects are now created in "ListFrame" and not in "frameTwo"
#I perform the alterations. Check it out
try:
val = int(self.entrypiezas.get())
self.aceptar_piezas_ok()
self.scrollb.grid(row=1, column=1, sticky='nsew') #grid scrollbar in master, because user had defined the numer of pieces
except ValueError:
showerror('Error', "Introduce un numero")
def aceptar_piezas_ok(self):
self.num_piezas = self.entrypiezas.get()
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
self.optionmenus_piezas = list()
self.numpiezas = []
self.numerolotes = []
self.optionmenus_prioridad = list()
self.lotes = list()
self.mispiezas = ['One', 'Two', 'Three', 'Four', 'Five']
self.n = 1
while self.n <= int(self.num_piezas):
self.textopieza = Label(self.listFrame, text = "Pieza: ", justify="left")
self.textopieza.grid(row=self.n, column=0)
var = StringVar()
menu = OptionMenu(self.listFrame, var, *self.mispiezas)
menu.config(width=10)
menu.grid(row=self.n, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.listFrame, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=self.n, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.listFrame,width=6)
self.entrynumpiezas.grid(row=self.n, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.listFrame, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=self.n, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.listFrame, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=self.n, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.listFrame, text = "Por lotes?", justify="center")
self.lotestext.grid(row=self.n, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.listFrame, variable=self.var1)
self.entrynumlotes.grid(row=self.n, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.n += 1
self.anadirpiezas = Button(self.frameThree, text="Add row", command=self.addpieza, width=10)
self.anadirpiezas.grid(row=0, column=2, pady=(10,10))
self.calculotext = Label(self.frameThree, text = "Other stuff ")
self.calculotext.grid(row=1, column=2, padx=(10,0), pady=(10,10))
self.graspbutton = Button(self.frameThree, text="OPT 1", width=10)
self.graspbutton.grid(row=2, column=1)
self.parettobutton = Button(self.frameThree, text="OPT 2",width=10)
self.parettobutton.grid(row=2, column=2, pady=(10,10), padx=(10,0))
self.parettoEvolbutton = Button(self.frameThree, text="OPT 2", width=10)
self.parettoEvolbutton.grid(row=2, column=3, pady=(10,10), padx=(10,0))
def addpieza(self):
self.textopiezanuevo = Label(self.listFrame, text = "Pieza: ", justify="left")
self.textopiezanuevo.grid(row=int(self.num_piezas)+1, column=0)
var = StringVar()
menu = OptionMenu(self.listFrame, var, *self.mispiezas)
menu.grid(row=self.n, column=1)
menu.config(width=10)
menu.grid(row=int(self.num_piezas)+1, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.listFrame, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=int(self.num_piezas)+1, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.listFrame,width=6)
self.entrynumpiezas.grid(row=int(self.num_piezas)+1, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.listFrame, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=int(self.num_piezas)+1, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.listFrame, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=int(self.num_piezas)+1, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.listFrame, text = "Por lotes?", justify="center")
self.lotestext.grid(row=int(self.num_piezas)+1, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.listFrame, variable=self.var1)
self.entrynumlotes.grid(row=int(self.num_piezas)+1, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.num_piezas = int(self.num_piezas)+1
if __name__ == "__main__":
root = Tk()
aplicacion = Planificador(root)
root.mainloop()
You have option menus, labels, entry boxes, and checkbuttons in FrameTwo. How would you expect a scrollbar for the entire frame would work? Would it scroll all widgets at the same time? Tkinter scrollbars are generally attached to listboxes, canvases, entry widgets, and text fields. http://effbot.org/zone/tkinter-scrollbar-patterns.htm Come up with a simple example that illustrates the problem for further help.

Categories