Python tkinter navigation using grids - python

I am trying to navigate between two simple pages:-
Page 1:
root = tk.Tk()
root.minsize(230,300)
root.title("Page1")
label = tk.Label(root,text="File Path")
textBox = tk.Text(root,height=2,width=10)
textBox.config(state='disabled')
label.grid(row=0,column=0)
Page 2:
root = tk.Tk()
root.minsize(230,300)
root.title("Page2")
label = tk.Label(root,text="File Path")
textBox = tk.Text(root,height=2,width=10)
textBox.config(state='disabled')
label.grid(row=0,column=0)
I have searched for some solution but they involve hiding buttons using the pack methods which give me an error.

store the pages in a list and use grid_forget to hide the previous page and use page[index].grid to bring the next page.
In your case, you are switching between two Text Widgets so store those widgets in a list.
here is an example:
import tkinter as tk
def previousPage():
global index
if index > 0:
pages[index].grid_forget()
index -= 1
msg = index
pages[index].grid(row=1, column=1)
else:
msg = 'No more previous pages'
lbl.config(text=msg)
def nextPage():
global index
if index < len(pages)-1:
pages[index].grid_forget()
index += 1
msg = index
pages[index].grid(row=1, column=1)
else:
msg = 'Last Page Reached'
lbl.config(text=msg)
root = tk.Tk()
root.grid_columnconfigure((0, 1), weight=1)
root.grid_rowconfigure((0, 1, 2), weight=1)
index = 0
frame1 = tk.Frame(root)
tk.Label(frame1, text='Hello').pack()
tk.Text(frame1, state='disabled').pack()
frame2 = tk.Frame(root)
tk.Label(frame2, text='Welcome').pack()
tk.Entry(frame2).pack()
pages = [frame1, frame2]
pages[0].grid(row=1, column=1)
tk.Button(root, text='Next', command= nextPage).grid(row=2, column=2)
tk.Button(root, text='Previous', command= previousPage).grid(row=2, column=0)
lbl = tk.Label(root, text=f'Page: {index}')
lbl.grid(row=0, column=1)
root.mainloop()

Related

How can I either ignore blank pages in a pdf using python or add blank pages to a location without changing the total amnt of pages until doc saved?

So I'm using the tkinter and pymupdf libraries to add blank pages to a desired location. This is done by pressing a button which inserts the blank page below the page on the button. My issue is that once it inserts the blank page, the original page order now changes.
When you press a button corresponding to a page number, it inserts the blank page, but if you try with a second blank page, it inserts it at the wrong place because it messes up the button's assigned page number. Please help I'm losing my hair.
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from tkinter.filedialog import asksaveasfilename
import fitz
btnClick = 0
def launchInsert():
global root
global buttonframe
root = tk.Tk()
root.title("Bla bla bla")
root.geometry("800x600")
#Displays "text" name as title of program
label = tk.Label(root, text ="Insert Blank Page", font=('Arial',18))
label.pack(padx=20, pady=20)
#File Explorer Button
buttonframe = tk.Frame(root, padx=100, pady=25)
btn1 = tk.Button(buttonframe,text="Browse...", font=('Arial',18), command=browse_file)
btn1.grid(row=1, column=6, padx=225, sticky=tk.W+tk.E)
buttonframe.pack(side="bottom")
def save_file():
f = asksaveasfilename(initialfile = 'untitled.pdf',
defaultextension=".pdf",filetype=[("All Files","*.*"),("PDF Files","*.pdf")])
pdf2.save(f)
# with open(file, "wb") as pdfCombined:
# newPdf.write(pdfCombined)
def blank(i):
#program is recognizing blank page as document original page then counting it as pagenumber
#try to just ignore blank pages
pdf2.new_page(pno=i, width=595, height=842)
global btnClick
btnClick = btnClick + 1
if btnClick == 1:
pdf2.new_page(pno=i, width=595, height=842)
elif btnClick > 1:
print("This is button click: ", btnClick)
i = i + 1
pdf2.new_page(pno=i, width=595, height=842)
for slices in range(len(pdf2)):
print("This is new page - ", slices)
print("This is pageCount after addition", slices)
print("The page was added successfully")
print("This is ", i)
def browse_file():
global filename
filename = filedialog.askopenfilename(title="Select a File", filetype=(("PDF Files","*.pdf"),("All Files","*.*")))
global pdf2, pageCount, i
pdf2 = fitz.open(filename)
# Create A Main Frame
main_frame = Frame(root)
main_frame.pack(fill=BOTH, expand=1)
# Create A Canvas
my_canvas = Canvas(main_frame)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
# Add A Scrollbar To The Canvas
my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
# Configure The Canvas
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e: my_canvas.configure(scrollregion = my_canvas.bbox("all")))
# Create ANOTHER Frame INSIDE the Canvas
second_frame = Frame(my_canvas)
# Add that New frame To a Window In The Canvas
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
btn2 = tk.Button(buttonframe,text="Save", font=('Arial',18), command=save_file)
btn2.grid(row=1, column=7, pady=20, sticky=tk.W+tk.E)
buttonframe.pack(side="bottom")
for i in range(len(pdf2)):
insClick = tk.Button(second_frame, text=f'Insert\nbelow {i}', padx= 50, command= lambda i=i: blank(i)).grid(row=i, column=5, pady=25, padx=50)
numShow = Label(second_frame, text=f"Page number {i}",padx=200).grid(row=i, column=1)
launchInsert()
mainloop()

Python tkinter - problem with scrollbar after adding menu column

I'm working on my application connected with my database.
I had a working wersion of it but it didn't look good so I want to add a left side menu to it.
That's how 'show records' page looked like:
photo 1: https://imgur.com/a/egDQpLG
Code of this part:
def createTable(frame, row):
columns = ('IMIĘ','NAZWISKO','PESEL','EMAIL','NR TELEFONU','NR POLISY','DOSTAWCA','WYGASA\nZA (DNI)','NOTATKA','WYŚLIJ\nSMS','WYŚLIJ\nEMAIL')
column_counter = 0
for column in columns:
column_label = Label(frame, text=column, bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10")
column_label.grid(row=row,column=column_counter,padx=2)
column_counter += 1
def addRecord(frame, row, record):
column = 0
for i in range(13): #12 columns in database
if i in (6,7): #records from data base that I don't use
continue
elif i == 11 and notify==True:
send_sms = Button(frame, text="SMS", bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10", command=partial(sendSMSNotification, [], record[5])) #button that sends sms
send_sms.grid(row=row,column=9,padx=2)
elif i == 12 and notify==True:
send_email = Button(frame, text="EMAIL", bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10", command=partial(sendEmailNotification, [], record[5])) #button that sends EMAIL
send_email.grid(row=row,column=10,padx=2)
else:
result_label = Label(frame, text=record[i], bg=BG_COLOR, fg=TEXT_COLOR, font="Helvetica 10")
result_label.grid(row=row,column=column,padx=2)
column += 1
def showRecords():
destroyWidgets() #clears window
main_frame = Frame(root, bg=BG_COLOR)
main_frame.pack(fill=BOTH, expand=1)
my_canvas = Canvas(main_frame, bg=BG_COLOR)
my_canvas.pack(side=LEFT, fill=BOTH, expand=1)
my_scrollbar = ttk.Scrollbar(main_frame, orient=VERTICAL, command=my_canvas.yview)
my_scrollbar.pack(side=RIGHT, fill=Y)
my_canvas.configure(yscrollcommand=my_scrollbar.set)
my_canvas.bind('<Configure>', lambda e:
my_canvas.configure(scrollregion=my_canvas.bbox("all")))
second_frame = Frame(my_canvas, bg=BG_COLOR)
my_canvas.create_window((0,0), window=second_frame, anchor="nw")
conn = sqlite3.connect(dbname)
c = conn.cursor()
back_button_top = Button(second_frame, text='Powrót', width=135, command=lambda: returnMain())
back_button_top.grid(row=0, column=0, pady=20, padx=20)
result_frame = Frame(second_frame, bg=BG_COLOR)
result_frame.grid(row=1, column=0)
createTable(result_frame, 0) #creates a heading of the table ('IMIĘ, NAZWISKO, PESEL' etc)
c.execute("SELECT * FROM dane")
records = c.fetchall()
row_counter = 2
for record in records:
addRecord(result_frame, row_counter, record) #adds a line of data read from the database, looked like a excel
row_counter+=1
Then I added a simple left sided menu column. So I added these lines to the showrecords function.
showMenu creates a Frame in column 0 and adds some buttons
def showMenu():
menu_frame = Frame(root,bg=BG_COLOR)
menu_frame.grid(row=0,column=0, sticky='ew')
menu_frame.grid_columnconfigure(0, weight=1)
show_records_button = Button(....
def showRecords():
destroyWidgets()
showMenu()
record_frame = Frame(root, bg=BG_COLOR)
record_frame.grid(column=1, row=0,sticky='nsew')
main_frame = Frame(record_frame, bg=BG_COLOR)
main_frame.pack(fill=BOTH, expand=1)
......
photo 2: https://imgur.com/iaRIAd9
And now I'm getting the scrollbar in the center of records column. Do you know how can I move the scroll to the right side of window? I think I have tried to change every possible attribute and nothing helped.
Also the problem of small Frame appears if I add an addition (just like my new version of code but without line with showMenu() Frame without adding a menu. So probably something is wrong with the sizing, but I dont know what.

How to make a search from the position of cursor and select if I want to do it from that position to up or down

I'm coding a text editor as part of my learning Python. I can search the text in Text Widget from an Entry Widget with this piece of code bellow, but need how to make a search from the position of cursor and select if I want to do it from that position to up or down, I don't know how to do that.
I could add a Radiobutton for (up option) and other for (down option) just like Notepad in Windows, but I need the code to do that. Does anyone know?
And my code doesn't differentiate between upper case and lower case, I don´t know why.
from tkinter import *
from tkinter import messagebox as MessageBox
search_list = list()
s = ""
def reset_list():
if s != entry_widget_name.get():
search_list.clear()
text_widget_name.tag_remove(SEL, 1.0,"end-1c")
def search_words():
reset_list()
global search_list
global s
text_widget_name.focus_set()
s = entry_widget_name.get()
if s:
if search_list == []:
idx = "1.0"
else:
idx = search_list[-1]
idx = text_widget_name.search(s, idx, nocase=1, stopindex=END)
lastidx = '%s+%dc' % (idx, len(s))
try:
text_widget_name.tag_remove(SEL, 1.0,lastidx)
except:
pass
try:
text_widget_name.tag_add(SEL, idx, lastidx)
counter_list = []
counter_list = str(idx).split('.')
text_widget_name.mark_set("insert", "%d.%d" % (float(int(counter_list[0])), float(int(counter_list[1]))))
text_widget_name.see(float(int(counter_list[0])))
search_list.append(lastidx)
except:
MessageBox.showinfo("Search complete","No further matches")
search_list.clear()
text_widget_name.tag_remove(SEL, 1.0,"end-1c")
root = Tk()
root.geometry("540x460")
lbl_frame_entry = LabelFrame(root, text="Enter the text to search", padx=5, pady=5)
lbl_frame_entry.pack(padx=10, pady=5, fill="both")
entry_widget_name = Entry(lbl_frame_entry, width=50, justify = "left")
entry_widget_name.pack(fill="both")
lbl_frame_text = LabelFrame(root, text="Enter the text here", padx=5, pady=5, height=260)
lbl_frame_text.pack(padx=10, pady=5, fill="both", expand=True)
text_widget_name = Text(lbl_frame_text)
text_widget_name.pack(fill="both", expand=True)
scrollbar = Scrollbar(text_widget_name, orient="vertical", command=text_widget_name.yview, cursor="arrow")
scrollbar.pack(fill="y", side="right")
text_widget_name.config(yscrollcommand=scrollbar.set)
button_name = Button(root, text="Search", command=search_words, padx=5, pady=5)
button_name.pack()
root.mainloop()
First of all, your search is not case sensitive because you used the option nocase=1.
Secondly, if you want to do a up or down search, there are the backwards and forwards options (I found the documentation here). When you do a backward search, you also need to change the way you move the insert cursor too and the stopindex. Here is an example in which the text in the entry is searched in the text starting from the current insert position and moving upward / downward depending on the selected radiobutton:
from tkinter import *
from tkinter import messagebox as MessageBox
def search():
pattern = e.get()
if search_dir.get() == 'forwards':
res = txt.search(pattern, 'insert', forwards=True, stopindex='end')
else:
res = txt.search(pattern, 'insert', backwards=True, stopindex='1.0')
txt.tag_remove('sel', '1.0', 'end')
try:
txt.tag_add('sel', res, '%s+%ic' % (res, len(pattern)))
if search_dir.get() == 'forwards':
txt.mark_set('insert', '%s+%ic' % (res, len(pattern)))
else:
txt.mark_set('insert', '%s-1c' % (res))
except:
MessageBox.showinfo("Search complete","No further matches")
root = Tk()
txt = Text(root)
txt.pack(fill='both',expand=True)
e = Entry(root)
e.pack(fill='x')
search_dir = StringVar(root, 'forwards')
Radiobutton(root, text='▲', value='backwards', variable=search_dir).pack()
Radiobutton(root, text='▼', value='forwards', variable=search_dir).pack()
Button(root, text='Search', command=search).pack()
root.mainloop()

How to Get Iterations to Update with addition to list

So I've been struggling with an issue for a week or so, been googling around trying to find different solutions, etc and getting nowhere. I was advised to put functioning code on here so I've cut it down some while still showing the issue.
I want to have a main page listing a set of goals, then if you click on the "Goal Entry" button up top a new window opens where you can input additional goals. Then you type in your desired additions, hit enter, and it adds it to the list on the main page.
I've accomplished all of the above EXCEPT, after you add the goals (and I have the list printing before and after so I know they're being added) and the entry window closes, the list of labels (created by an iteration) hasn't updated accordingly.
How do I get the list on the main page to automatically update when a new item is added to the list?
from tkinter import *
pg = ["goal1","goal2"]
pgtotal=1
psum=len(pg)
class yeargoals():
global pg, hg, fg, rg, rgtotal
def __init__(self,master):
self.master = master
master.title("This Year's Goals")
self.buttonframe = Frame(root)
self.buttonframe.pack(side=TOP, padx = 150, fill=BOTH)
self.home = Button(self.buttonframe, text="Home Page")
self.home.grid(row=1, column=1, padx=10)
self.enter = Button(self.buttonframe, text="Goal Entry", command=self.winenter)
self.enter.grid(row=1, column=2, padx=10)
self.finalize = Button(self.buttonframe, text="Finalize for Year")
self.finalize.grid(row=1, column=3, padx=10)
self.dashboard = Button(self.buttonframe, text="Goal Dashboard")
self.dashboard.grid(row=1,column=4, padx=10)
self.goalframe = Frame(root)
self.goalframe.pack(side=TOP, padx=150, pady=50, fill=BOTH, expand = True)
#Makes the label Fram I want the Checkboxes to go in
self.LabelFramep= LabelFrame(self.goalframe,text="Professional Goals")
self.LabelFramep.pack(side=LEFT, padx=10, anchor = N, fill=BOTH, expand = True)
#Makes the from the list above
for goal in pg:
l = Checkbutton(self.LabelFramep, text=goal, variable=Variable())
l.config(font=("Courier",12))
l.grid(sticky=W)
self.ptotal=Label(self.LabelFramep,text="Progress so far: "+str(pgtotal)+"/"+str(psum))
self.ptotal.config(font=("Courier",12))
self.ptotal.grid(sticky=W)
self.pper=Label(self.LabelFramep, text=str(round((pgtotal/psum)*100))+"% Complete")
self.pper.config(font=("Courier",12))
self.pper.grid(sticky=W)
def winenter(self):
global pg
self.winenter = Toplevel(root)
options = ["Professional", "Health", "Financial", "Reward Items"]
variable = StringVar(self.winenter)
variable.set(options[0])
#Title of entry section
t1 = Label(self.winenter, text="New Goal Entry")
t1.grid(row=0, column=1, columnspan=2)
#dropdown menu
d = OptionMenu(self.winenter, variable, *options)
d.grid(row=1, column=2)
#entry fields
e1 = Entry(self.winenter)
e1.grid(row=2, column=2, padx = 10, pady=5)
e2 = Entry(self.winenter)
e2.grid(row=3, column=2, padx=10, pady=5)
e3 = Entry(self.winenter)
e3.grid(row=4, column=2, padx=10, pady=5)
e4 = Entry(self.winenter)
e4.grid(row=5, column=2, padx=10, pady=5)
e5 = Entry(self.winenter)
e5.grid(row=6, column=2, padx=10, pady=5)
#Label for entry fields
l1 = Label(self.winenter, text="Goal Number 1")
l1.grid(row=2, column=1)
l2 = Label(self.winenter, text="Goal Number 2")
l2.grid(row=3, column=1)
l3 = Label(self.winenter, text="Goal Number 3")
l3.grid(row=4, column=1)
l4 = Label(self.winenter, text="Goal Number 4")
l4.grid(row=5, column=1)
l5 = Label(self.winenter, text="Goal Number 5")
l5.grid(row=6, column=1)
def enter():
global pg, main
print (pg)
if variable.get() == "Professional":
pg.append(e1.get())
self.winenter.destroy()
print (pg)
#Goal entry execute button
b = Button(self.winenter, text="Enter Goals", command=enter)
b.grid(row=7, column = 1)
root = Tk()
Window = yeargoals(root)
root.mainloop()
In your callback function to button "Enter Goals", you have done nothing to update your main window. Maybe you think the main window will magically keep updated with the variable pg, no, you need to do all those updates manually in your callback function.
For example, change your callback enter() to:
def enter():
global pg, main
print (pg)
if variable.get() == "Professional":
pg.append(e1.get())
l = Checkbutton(self.LabelFramep, text=pg[-1], variable=Variable())
l.config(font=("Courier",12))
l.grid(sticky=W)
self.winenter.destroy()
print (pg)
You can find the main window is updated after you click "Enter Goals".

Creating new entry boxes with button Tkinter

How do i make the button to add two box (side by side) below when it is being clicked as the user decided to put more input?
def addBox():
labelframe = Tkinter.Frame()
labelframe.bind("<Add Input>", callback)
labelframe.pack()
labelframe = Tkinter.Frame()
labelFrom = Tkinter.Label(labelframe, text= "from")
labelFrom.grid(column=1, row=0)
e = Tkinter.Entry(labelframe)
e.grid(column=1, row=1)
labelTo = Tkinter.Label(labelframe, text= "to")
labelTo.grid(column=2, row=0)
e2 = Tkinter.Entry(labelframe)
e2.grid(column=2, row=1)
labelframe.pack()
addboxButton = Button( root,text='<Add Time Input>', fg="Red",command="addBox")
addboxButton.pack(side=Tkinter.TOP)
This is example how to add Entry.
Probably you get problem because you use quotation marks in command=addBox
Because you will have to get values from entries you have to remeber them on list.
I add button which print text from entries.
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
ent = Entry(root)
ent.pack()
all_entries.append( ent )
#------------------------------------
def showEntries():
for number, ent in enumerate(all_entries):
print number, ent.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
addboxButton = Button(root, text='<Add Time Input>', fg="Red", command=addBox)
addboxButton.pack()
root.mainloop()
#------------------------------------
EDIT:
Example with boxes side by side.
I use new frame to keep entries side by side using grid().
This way I don't mix grid() with pack() in main window/frame.
I use len(all_entries) to get number of next free column.
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
# I use len(all_entries) to get nuber of next free column
next_column = len(all_entries)
# add label in first row
lab = Label(frame_for_boxes, text=str(next_column+1))
lab.grid(row=0, column=next_column)
# add entry in second row
ent = Entry(frame_for_boxes)
ent.grid(row=1, column=next_column)
all_entries.append( ent )
#------------------------------------
def showEntries():
for number, ent in enumerate(all_entries):
print number, ent.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
addboxButton = Button(root, text='<Add Time Input>', fg="Red", command=addBox)
addboxButton.pack()
frame_for_boxes = Frame(root)
frame_for_boxes.pack()
root.mainloop()
#------------------------------------
EDIT:
Another example:
from Tkinter import *
#------------------------------------
def addBox():
print "ADD"
frame = Frame(root)
frame.pack()
Label(frame, text='From').grid(row=0, column=0)
ent1 = Entry(frame)
ent1.grid(row=1, column=0)
Label(frame, text='To').grid(row=0, column=1)
ent2 = Entry(frame)
ent2.grid(row=1, column=1)
all_entries.append( (ent1, ent2) )
#------------------------------------
def showEntries():
for number, (ent1, ent2) in enumerate(all_entries):
print number, ent1.get(), ent2.get()
#------------------------------------
all_entries = []
root = Tk()
showButton = Button(root, text='Show all text', command=showEntries)
showButton.pack()
addboxButton = Button(root, text='<Add Time Input>', fg="Red", command=addBox)
addboxButton.pack()
root.mainloop()
#------------------------------------
First of all, the indentation is a whole mess, so I don't know where does the addBox function end ..
Second, I don't think you need a button, I suppose a checkbutton will do the same thing and it's also more common and familiar to users, I once had this problem and I simply created an entry box and put above it a label indicating that it's optional, and as for code, I simply ignored it if it was empty and verified the input if I found any input ..Howerver, that was for only one entry box, and you probably will need something more complex ..
See this ..
class OptionsView(Frame):
"""Frame for options in main window"""
def __init__(self, x, y, parent):
Frame.__init__(self, parent)
self.x = x
self.y = y
self.placed = False
self.hidden = False
self.btn = Button(self, text = 'Button attached to the frame ..', command = lambda: print('Button in frame clicked ..')).pack()
def pack(self):
self.place(x = self.x, y = self.y)
self.placed = True
def toggle_view(self):
if self.hidden:
self.pack()
self.hidden = False
else:
self.place_forget()
self.hidden = True
if __name__ == '__main__':
def m_frame():
if val.get() and not options_frame.placed:
print('Showing Frame ..')
options_frame.pack()
else:
print('Toggling Frame ..')
options_frame.toggle_view()
root = Tk()
root.geometry('300x400+500+600')
root.title('Testing Hiding Frames ..')
options_frame = OptionsView(200, 300, root)
val = BooleanVar(value = False)
Checkbutton(text = 'View more Options ..', var = val, command = m_frame).place(x=root.winfo_height()/2, y=root.winfo_width()/2)
try: root.mainloop()
except e: showerror('Error!', 'It seems there\'s a problem ..', str(e))
Ofcourse you can also modify the length and the x axis of the main window if you want to be more realistic ..

Categories

Resources