Get OptionMenu value after selection and store in array - python-3.x

Here is the code:
from tkinter import *
class Window(Canvas):
def __init__(self,master=None,**kwargs):
Canvas.__init__(self,master,**kwargs)
self.frame = Frame(self)
self.create_window(0,0,anchor=N+W,window=self.frame)
self.row = 1
self.input_n_or_s = []
self._init_entries()
def _init_entries(self):
n_or_s = Label(self.frame, text='N or S', font='Helvetica 10 bold').grid(row = self.row, column = 1)
self.row += 1
def add_entry(self):
n_or_s = ['N', 'S']
variable = StringVar(self.frame)
variable.set(n_or_s[0])
option_n_or_s = OptionMenu(self.frame, variable, *n_or_s)
option_n_or_s.grid(row = self.row, column = 1)
self.row += 1
#def save_entry(self):
if __name__ == "__main__":
root = Tk()
root.resizable(0,0)
root.title('Lot')
lot = Window(root)
lot.grid(row=0,column=0)
scroll = Scrollbar(root)
scroll.grid(row=0,column=1,sticky=N+S)
lot.config(yscrollcommand = scroll.set)
scroll.config(command=lot.yview)
lot.configure(scrollregion = lot.bbox("all"), width=1000, height=500)
def add_points():
lot.add_entry()
lot.configure(scrollregion = lot.bbox("all"))
b1 = Button(root, text = "Add points", command = add_points)
b1.grid(row=1,column=0)
def get_value():
b1.destroy()
lot.save_entry()
b2 = Button(root, text = "Get value!", command = get_value)
b2.grid(row=2,column=0)
root.mainloop()
Can someone help me on what to put inside the 'save_entry()' function to get each values of the OptionMenus (assuming that the 'add entry' button has been clicked more than 5 times), and then put each values in the 'input_n_or_s' array for later use?
For example:
Here's the GUI wherein the user clicked the 'Add points' button 10 times, and then changed some default values to 'S':
My expected output should look like this:
['S', 'N', 'N', 'S', 'N', 'N', 'N', 'S', 'N', 'S']

Here you go I think this is what you want.
from tkinter import *
class Window(Canvas):
def __init__(self,master=None,**kwargs):
Canvas.__init__(self,master,**kwargs)
self.frame = Frame(self)
self.create_window(0,0,anchor=N+W,window=self.frame)
self.row = 1
self.input_n_or_s = []
self._init_entries()
def _init_entries(self):
n_or_s = Label(self.frame, text='N or S', font='Helvetica 10 bold').grid(row = self.row, column = 1)
self.row += 1
def add_entry(self):
n_or_s = ['N', 'S']
self.variable = StringVar(self.frame)
self.variable.set(n_or_s[0])
self.menu = option_n_or_s = OptionMenu(self.frame, self.variable, *n_or_s)
option_n_or_s.grid(row = self.row, column=1)
self.row += 1
def save_entry(self):
print(self.variable.get())
if __name__ == "__main__":
root = Tk()
root.resizable(0, 0)
root.title('Lot')
lot = Window(root)
lot.grid(row=0,column=0)
scroll = Scrollbar(root)
scroll.grid(row=0,column=1,sticky=N+S)
lot.config(yscrollcommand = scroll.set)
scroll.config(command=lot.yview)
lot.configure(scrollregion = lot.bbox("all"), width=1000, height=500)
root.cnt = 0
def add_points():
root.cnt += 1
if root.cnt < 5:
return
root.cnt = 0
lot.add_entry()
lot.configure(scrollregion = lot.bbox("all"))
lot.input_n_or_s.append(lot.variable.get())
b1 = Button(root, text = "Add points", command = add_points)
b1.grid(row=1,column=0)
def get_value():
b1.destroy()
lot.save_entry()
b2 = Button(root, text = "Get value!", command = get_value)
b2.grid(row=2, column=0)
root.mainloop()

I finally figured it out. The reason that I can't manage to make it work before is that I'm trying to get the output from the OptionMenu instead of the variable.
def add_entry(self):
....
self.input_n_or_s.append(variable)
def save_entry(self):
for entry in self.input_n_or_s:
x = str(entry.get())
self.north_or_south.append(x)
print(self.north_or_south)
So here's the whole working code:
from tkinter import *
class Window(Canvas):
def __init__(self,master=None,**kwargs):
Canvas.__init__(self,master,**kwargs)
self.frame = Frame(self)
self.create_window(0,0,anchor=N+W,window=self.frame)
self.row = 1
self.input_n_or_s = []
self.north_or_south = []
self._init_entries()
def _init_entries(self):
n_or_s = Label(self.frame, text='N or S', font='Helvetica 10 bold').grid(row = self.row, column = 1)
self.row += 1
def add_entry(self):
n_or_s = ['N', 'S']
variable = StringVar(self.frame)
variable.set(n_or_s[0])
option_n_or_s = OptionMenu(self.frame, variable, *n_or_s)
option_n_or_s.grid(row = self.row, column = 1)
self.row += 1
self.input_n_or_s.append(variable)
def save_entry(self):
for entry in self.input_n_or_s:
x = str(entry.get())
self.north_or_south.append(x)
print(self.north_or_south)
if __name__ == "__main__":
root = Tk()
root.resizable(0,0)
root.title('Lot')
lot = Window(root)
lot.grid(row=0,column=0)
scroll = Scrollbar(root)
scroll.grid(row=0,column=1,sticky=N+S)
lot.config(yscrollcommand = scroll.set)
scroll.config(command=lot.yview)
lot.configure(scrollregion = lot.bbox("all"), width=1000, height=500)
def add_points():
lot.add_entry()
lot.configure(scrollregion = lot.bbox("all"))
b1 = Button(root, text = "Add points", command = add_points)
b1.grid(row=1,column=0)
def get_value():
b1.destroy()
lot.save_entry()
b2 = Button(root, text = "Get value!", command = get_value)
b2.grid(row=2,column=0)
root.mainloop()
Still, thanks for the effort on helping me, Daniel Huckson. And Bryan Oakley, thanks for your concern also.

Related

how to delete a specific item in the list after a button is clicked in tkinter python

Below is a small code where if you click add button a pop-up will appear where you write desired number. The number in the bottom represents the sum of all numbers you entered.
What I am trying to achieve is to update the sum_lbl and index_no as I delete any of the labels.
Code:
from tkinter import *
root = Tk()
root.geometry('400x400')
add_room_area_var= StringVar(None)
area_lst = []
index_no = 0
def destroy(widget):
widget.destroy()
def add_():
add_room_area = Toplevel(root)
add_room_area.title('Add Room area')
add_room_area.wm_minsize(200, 50)
add_room_area.resizable(False, False)
add_room_area.transient(root)
add_r_area_frame = LabelFrame(add_room_area, text=' Room area ', labelanchor=N)
add_r_area_frame.config(padx=3, pady=3)
add_r_area_frame.pack(fill=X, padx=10, pady=10)
add_r_area_entry = Entry(add_r_area_frame, textvariable=add_room_area_var)
add_r_area_entry.pack(fill=X)
add_r_area_entry.focus_set()
while True:
def ok_():
global index_no
name = add_room_area_var.get()
index_no += 1
entry_frame = Frame(root)
index_lbl = Label(entry_frame, text=index_no)
add_room_lbl = Label(entry_frame, text=name, width=12, bg='gray30', fg='white', pady=5)
close_button = Button(entry_frame, text='X', command=lambda:destroy(entry_frame))
entry_frame.pack(anchor=N, padx=1)
index_lbl.pack(side=LEFT, padx=3)
add_room_lbl.pack(fill=X, side=LEFT)
close_button.pack(side=RIGHT)
area_lst.append(int(name))
add_room_area.destroy()
area_sum = sum(area_lst)
sum_lbl.config(text=area_sum)
break
ok_button = Button(add_room_area, text='Ok', command=ok_)
ok_button.pack()
btn = Button(root, text='Add', command=add_)
btn.pack()
sum_lbl = Label(root, font=25)
sum_lbl.pack(side=BOTTOM, pady=15)
root.mainloop()
Output:
After deleting the 3rd and 4th label the output is:
I would suggest to change area_lst to dictionary using the frame as the key and the two labels as the value for each row.
Then update destroy() to use area_lst to update the total and indexes:
from tkinter import *
root = Tk()
root.geometry('400x400')
add_room_area_var= StringVar(None)
area_lst = {} # dictionary to hold labels of each row using frame as the key
def destroy(frame):
frame.destroy()
del area_lst[frame]
update_total()
# update index of remaining rows
for idx, (lbl, _) in enumerate(area_lst.values(), 1):
lbl['text'] = idx
# function to update the total label
def update_total():
area_sum = sum(int(room['text']) for _, room in area_lst.values())
sum_lbl.config(text=area_sum)
def add_():
add_room_area = Toplevel(root)
add_room_area.title('Add Room area')
add_room_area.wm_minsize(200, 50)
add_room_area.resizable(False, False)
add_room_area.transient(root)
add_r_area_frame = LabelFrame(add_room_area, text=' Room area ', labelanchor=N)
add_r_area_frame.config(padx=3, pady=3)
add_r_area_frame.pack(fill=X, padx=10, pady=10)
add_r_area_entry = Entry(add_r_area_frame, textvariable=add_room_area_var)
add_r_area_entry.pack(fill=X)
add_r_area_entry.focus_set()
def ok_():
name = add_room_area_var.get()
entry_frame = Frame(root)
index_lbl = Label(entry_frame, text=len(area_lst)+1)
add_room_lbl = Label(entry_frame, text=name, width=12, bg='gray30', fg='white', pady=5)
close_button = Button(entry_frame, text='X', command=lambda:destroy(entry_frame))
entry_frame.pack(anchor=N, padx=1)
index_lbl.pack(side=LEFT, padx=3)
add_room_lbl.pack(fill=X, side=LEFT)
close_button.pack(side=RIGHT)
# store current row to area_lst
area_lst[entry_frame] = (index_lbl, add_room_lbl)
add_room_area.destroy()
update_total()
ok_button = Button(add_room_area, text='Ok', command=ok_)
ok_button.pack()
btn = Button(root, text='Add', command=add_)
btn.pack()
sum_lbl = Label(root, font=25)
sum_lbl.pack(side=BOTTOM, pady=15)
root.mainloop()
You can allow buttons to call multiple commands, so for your 'close_button' button, I added two more commands: remove the name from 'area_lst' and update the 'sum_lbl' text with the new sum for 'area_lst'
Like this:
from tkinter import *
root = Tk()
root.geometry('400x400')
add_room_area_var= StringVar(None)
area_lst = []
index_no = 0
def destroy(widget):
widget.destroy()
def add_():
add_room_area = Toplevel(root)
add_room_area.title('Add Room area')
add_room_area.wm_minsize(200, 50)
add_room_area.resizable(False, False)
add_room_area.transient(root)
add_r_area_frame = LabelFrame(add_room_area, text=' Room area ', labelanchor=N)
add_r_area_frame.config(padx=3, pady=3)
add_r_area_frame.pack(fill=X, padx=10, pady=10)
add_r_area_entry = Entry(add_r_area_frame, textvariable=add_room_area_var)
add_r_area_entry.pack(fill=X)
add_r_area_entry.focus_set()
while True:
def ok_():
global index_no
name = add_room_area_var.get()
index_no += 1
entry_frame = Frame(root)
index_lbl = Label(entry_frame, text=index_no)
add_room_lbl = Label(entry_frame, text=name, width=12, bg='gray30', fg='white', pady=5)
close_button = Button(entry_frame, text='X', command=lambda:[destroy(entry_frame), area_lst.remove(int(name)), sum_lbl.config(text=sum(area_lst))])
entry_frame.pack(anchor=N, padx=1)
index_lbl.pack(side=LEFT, padx=3)
add_room_lbl.pack(fill=X, side=LEFT)
close_button.pack(side=RIGHT)
area_lst.append(int(name))
add_room_area.destroy()
area_sum = sum(area_lst)
sum_lbl.config(text=area_sum)
break
ok_button = Button(add_room_area, text='Ok', command=ok_)
ok_button.pack()
btn = Button(root, text='Add', command=add_)
btn.pack()
sum_lbl = Label(root, font=25)
sum_lbl.pack(side=BOTTOM, pady=15)
root.mainloop()

python how to select printer for print receipt

the following code is working successfully, i need to print receipts. i want to select printer to print receipts. in this code how can i add printer function. I need to printer selecting option separately.
i don't know which function using in this code.
i hope you will help for this,
Thanks im advance.
from tkinter import ttk
import tkinter as tk
from tkinter import*
def update():
listBox.insert('','end',value=('APL', t1.get(),t2.get(),t3.get()))
listBox.insert('','end',value=('cPL', t4.get(),t5.get(),t6.get()))
def update():
if t1.get() == '' or t2.get() == '' or t3.get() == '':
pass
else:
listBox.insert('','end',value=('APL', t1.get(),t2.get(),t3.get()))
listBox.insert('','end',value=('cPL', t4.get(),t5.get(),t6.get()))
total = 0.0
try:
for child in listBox.get_children():
total += float(listBox.item(child, 'values')[3])
totText.set(total)
except:
pass
lbl = Label(root,text=total,font=('helvetica',21))
lbl.grid(row=5)
def print():
tott = float(totText.get())
top = Toplevel()
top.geometry("300x300")
top.config(bg="white")
l = Label(top, text='-------RECEIPT-------')
l.pack()
l.config(bg="white")
heading = Label(top, text='\tItem\tPRICE\tQTY\tTotal')
heading.pack()
heading.config(bg="white")
for child in listBox.get_children():
item = (listBox.item(child, 'values')[0])
price = float(listBox.item(child, 'values')[1])
qty = float(listBox.item(child, 'values')[2])
tot = float(listBox.item(child, 'values')[3])
item1 = Label(top, text=f'{item}\t{price}\t{qty}\t{tot}')
item1.config(bg="white")
item1.pack()
tot = Label(top, text=f'Total\t{tott}')
tot.config(bg="white")
tot.pack()
root = tk.Tk()
root.geometry('1000x600')
e8 = tk.Label(root,text="APL").grid(row=1,column=0)
t1 = tk.Entry(root)
t1.grid(row=1,column=1)
t2 = tk.Entry(root)
t2.grid(row=1,column=2)
t3 = tk.Entry(root)
t3.grid(row=1,column=3)
e9 = tk.Label(root,text="cPL").grid(row=2,column=0)
t4 = tk.Entry(root)
t4.grid(row=2,column=1)
t5 = tk.Entry(root)
t5.grid(row=2,column=2)
t6 = tk.Entry(root)
t6.grid(row=2,column=3)
global totText
totText = StringVar()
cols = ('Item', 'PRICE', 'QTY', 'Total')
listBox = ttk.Treeview(root, columns=cols, show='headings')
for col in cols:
listBox.heading(col, text=col)
listBox.grid(row=1, column=0, columnspan=2)
listBox.place(x=10, y=300)
b = tk.Button(root,text='Update Listbox',command=update)
b.grid(row=3)
Button(root, text="print", command=print, height=3, width=13).place(x=850, y=120)
root.mainloop()

How to edit information in tkinter

I'm trying to write a code to get the name, salary, and age and show it in a list. I want this code have the feature of deleteing and editing the information.
But in this step I don't know how delete or edit a particular information.
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import *
i = 2
table_row = []
def getting():
global i
i = i + 1
data = []
var = IntVar()
c = Checkbutton(window, variable=var)
c.val = var
data.append(c)
c.grid(row=i, column=0)
value1=e11.get()
data.append(value1)
value2 = e22.get()
data.append(value2)
value3 = e33.get()
data.append(value3)
lblq = Label(window, text=data[1:])
lblq.grid(row=i, column=1)
table_row.append(data)
# print(table_row)
def delete_row():
for Noo, row in reversed(list(enumerate(table_row))):
if row[0].val.get() == 1:
for i in row:
i.destroy()
table_row(Noo)
window = Tk()
window.title("Table with add, edit and delete")
window.geometry('600x600')
def Closing():
res = messagebox.askokcancel("warning", "Are You sure!!!!!")
if res == True:
sys.exit()
############################################### #menu inside winodow
menu = Menu(window)
new_item = Menu(menu)
new_item.add_command(label="Exit", command=Closing)
menu.add_cascade(label='File', menu=new_item)
window.config(menu=menu)
###############################################
lblname =Label(window, text="Name")
lblname.place(x = 440,y = 130)
e11 = Entry(window, width=20)
e11.place(x = 440,y = 150)
lblsurname =Label(window, text="Salary")
lblsurname.place(x = 440,y = 180)
e22 = Entry(window, width=20)
e22.place(x = 440,y = 200)
lblage =Label(window, text="Age")
lblage.place(x = 440,y = 240)
e33 = Entry(window, width=20)
e33.place(x = 440,y = 260)
dl = Button(window, text='Delete',command=delete_row)
dl.place(x = 440,y = 10)
dl = Button(window, text='Edit')
dl.place(x = 440,y = 50)
B2 = Button(window, text="+ add emplyoee", command=getting)
B2.place(x = 440,y = 90)
v0 = StringVar()
e0 = Entry(window, textvariable=v0, state='readonly')
v0.set('Select')
e0.grid(row=1, column=0)
v1 = StringVar()
e1 = Entry(window, textvariable=v1, state='readonly')
v1.set('Information')
e1.grid(row=1, column=1)
window.mainloop()
Maybe I should use Class in my code, but I is difficult for me to use Class and tkinter simultaneously
You could use dictionary to keep single row - it would be more readable
When I add row I create dictionary with widgets and text from Entry, I add to list of rows and clear Entry.
If there is selected row in table then I don't create new row but replace text in selected row.
The same way I search selected row to copy text from row to Entry.
The same way I search selected row to remove row - destroy widgets and delete row on the list.
It is more easier to do it because I use dictionary to keep row and it is more readable.
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import *
# --- functions ---
def closing():
res = messagebox.askokcancel("warning", "Are You sure!!!!!")
if res == True:
sys.exit()
def add_row():
global row_number
# check if there is selected row to update
update = None
for row in table_row:
if row['var'].get() == 1:
update = row
break # dont search next selected row
if update:
row['data'] = [e11.get(), e22.get(), e33.get()]
row['label']['text'] = row['data']
else:
row_number += 1
row = dict()
row['row_number'] = row_number
row['var'] = IntVar()
row['checkbutton'] = Checkbutton(window, variable=row['var'])
row['checkbutton'].grid(row=row_number, column=0)
row['data'] = [e11.get(), e22.get(), e33.get()]
row['label'] = Label(window, text=row['data'])
row['label'].grid(row=row_number, column=1)
table_row.append(row)
# clear entry
e11.delete('0', 'end')
e22.delete('0', 'end')
e33.delete('0', 'end')
lblnumber["text"] = "Row number: -"
def delete_row():
for row in reversed(table_row):
if row['var'].get() == 1:
# remove widgets
row['checkbutton'].destroy()
row['label'].destroy()
# remove row from list
del row
def edit_row():
for row in table_row:
if row['var'].get() == 1:
# remove all text
e11.delete('0', 'end')
e22.delete('0', 'end')
e33.delete('0', 'end')
# put text from row
e11.insert('end', row['data'][0])
e22.insert('end', row['data'][1])
e33.insert('end', row['data'][2])
lblnumber["text"] = "Row number: {}".format(row['row_number'])
break # dont search next selected row
# --- main ---
row_number = 2
table_row = []
window = Tk()
window.title("Table with add, edit and delete")
window.geometry('600x600')
menu = Menu(window)
new_item = Menu(menu)
new_item.add_command(label="Exit", command=closing)
menu.add_cascade(label='File', menu=new_item)
window.config(menu=menu)
lblnumber = Label(window, text="Row Number: -")
lblnumber.place(x=440, y=330)
e00 = Label(window, width=20)
e00.place(x=440, y=150)
lblname = Label(window, text="Name")
lblname.place(x=440, y=130)
e11 = Entry(window, width=20)
e11.place(x=440, y=150)
lblsurname = Label(window, text="Salary")
lblsurname.place(x=440, y=180)
e22 = Entry(window, width=20)
e22.place(x=440, y=200)
lblage = Label(window, text="Age")
lblage.place(x=440, y=240)
e33 = Entry(window, width=20)
e33.place(x=440, y=260)
dl = Button(window, text='Delete', command=delete_row)
dl.place(x=440, y=10)
dl = Button(window, text='Edit', command=edit_row)
dl.place(x=440, y=50)
B2 = Button(window, text="+ add emplyoee", command=add_row)
B2.place(x=440, y=90)
v0 = StringVar()
e0 = Entry(window, textvariable=v0, state='readonly')
v0.set('Select')
e0.grid(row=1, column=0)
v1 = StringVar()
e1 = Entry(window, textvariable=v1, state='readonly')
v1.set('Information')
e1.grid(row=1, column=1)
window.mainloop()

Toggling variables from for loop in python and tkinter

I'm new with python and stack overflow so sorry if this question is below average. Anyway, I'm trying to make a Registration Software with python and tkinter, and I want to make it so that the buttons toggle between the purple colour: #ff4dd2. It is made hard because the buttons are created from a loop, I can't assign a variable to the buttons. If you could take the time to take a look at this it would be really appreciated :) (The current code works as expected, hopefully you can understand what I mean)
from tkinter import *
import time
import datetime
import re
root = Tk()
root.title("Attendence Register")
root.geometry('1350x650+0+0')
root.resizable(False, False)
nameframe = Frame(root, height=650, width=300)
nameframe.pack(side='left')
saveframe = Frame(root, height=650, width=300)
saveframe.pack(side='right')
outlist = []
def saveDataPresent(line):
present[line].configure(bg='#ff4dd2')
line = (line + ' is present')
outlist.append(line)
#print(outlist)
def saveDataAbsent(line):
absent[line].configure(bg='#ff4dd2')
line = (line + ' is absent')
outlist.append(line)
#print(outlist)
def saveDataIll(line):
ill[line].configure(bg='#ff4dd2')
line = (line + ' is ill')
outlist.append(line)
#print(outlist)
def saveDataHoliday(line):
holiday[line].configure(bg='#ff4dd2')
line = (line + ' is on holiday')
outlist.append(line)
#print(outlist)
def saveData():
now = datetime.datetime.now()
now = str(now)
dire = 'logs/'
now = dire + now
now = re.sub(':', '', now)
now += '.txt'
log = open(now, "w+")
log.close()
log = open(now, "a")
for i in outlist:
i = (i + '\n')
log.write(i)
log.close()
text = open('names.txt','r')
line = text.readline()
count = 0
present = {}
absent = {}
ill = {}
holiday = {}
for line in text:
count+= 1
name = Label(nameframe, text=line)
name.grid(row=count, column = 0)
present[line] = Button(nameframe, text='/', pady = 20, padx=20, bg ='#66ff66', command=lambda line=line: saveDataPresent(line))
present[line].grid(row=count, column = 2)
holiday[line] = Button(nameframe, text='H', pady=20, padx=20, bg='light blue', command=lambda line=line: saveDataHoliday(line))
holiday[line].grid(row=count, column=3)
ill[line] = Button(nameframe, text='ill', pady=20, padx=20, bg ='#ffa31a', command=lambda line=line: saveDataIll(line))
ill[line].grid(row=count, column=4)
absent[line] = Button(nameframe, text='NA', pady=20, padx=20, bg ='#ff6666', command=lambda line=line: saveDataAbsent(line))
absent[line].grid(row=count, column=5)
savebut = Button(saveframe, text='Save', pady = 20, padx=20, command=saveData)
savebut.pack()
root.mainloop()
I put this in the comments but it didnt look nice:
def saveDataHoliday(line):
holidaycount[line] += 1
if holidaycount[line] % 2 == 1:
holiday[line].configure(bg='#ff4dd2')
line = (line + ' is holiday')
outlist.append(line)
#print(outlist)
else:
holiday[line].configure(bg='light blue')
line = (line + ' is holiday')
outlist.remove(line)
#print(outlist)enter code here
holidaycount was defined earlier as a dictionary:
holidaycount = {}
I did this for each button(absent, present etc) Then after that:
for line in text:
count+= 1
name = Label(nameframe, text=line)
name.grid(row=count, column = 0)
presentcount[line] = 0
absentcount[line] = 0
illcount[line] = 0
holidaycount[line] = 0

Display of a large amount of data in a Canvas with a Scrollbar

I'm having a problem trying to display a large table in tkinter.
First, I tried to display all label at once in the canvas, but over few hundred rows, the program shut down. So I tried to create a scrollable canvas that updates everytime I scroll: I collect the position of the scrollbar and depending on the position of it, I display the 10 values corresponding.
But I can't get this code working. For now it only displays a black background with the scrollbar on the right.
Here is the code:
from tkinter import *
class Application(object):
def __init__(self, parent):
self.x = []
for i in range(1, 1000):
self.x.append(i)
self.parent = parent
self.mainFrame = Frame(self.parent)
self.mainFrame.pack()
self.canvas = Canvas(self.mainFrame, width = 200, height = 500, bg = "black")
self.canvas.grid(row = 0, column = 0)
self.scroll = Scrollbar(self.mainFrame, orient = VERTICAL, command = self.update)
self.scroll.grid(row = 0, column = 1)
self.canvas.configure(yscrollcommand = self.scroll.set)
self.tabCursor = 0
self.scrollPosition = self.scroll.get()
def update(self):
self.tabCursor = round(self.scrollPosition[0]*len(self.x))
if ((len(self.x) - self.tabCursor) < 10):
self.tabCursor = len(self.x) - 10
for i in range(0, 10): #display 10 values
label = Label(self.canvas, text = str(self.x[tabCursor + i]), width = 50)
label.grid(column = 0, row = i)
if __name__ == '__main__':
root = Tk()
app = Application(root)
root.mainloop()
EDIT :
I finally had time to implement your answer. It looks fine but I can't get the scrollbar working and i don't know why.
class TableauDeDonnees(object):
"Tableau de données -- Onglet Tableau de données"
def __init__(self, data, parent):
self.parent = parent
self.data = data
print(self.data[0], self.data[1])
print(len(self.data[0]), len(self.data[1]))
self.labels = []
self.navigationFrame = Frame(self.parent)
self.canvas = Canvas(self.parent, bg = "black", width = 200, height = 500)
self.mainFrame = Frame(self.canvas)
self.navigationFrame.pack()
print(len(data))
for row in range(50):
for column in range(len(data)):
self.labels.append(Label(self.canvas, text = str(data[column][row])))
for i in range(len(self.labels)):
self.labels[i].grid(row = i // 2, column = i % 2, sticky = NSEW)
self.boutonRetour = Button(self.navigationFrame, text = "Retour", command = lambda: self.move(-2))
self.quickNav = Entry(self.navigationFrame, width = 3)
self.quickNav.bind('<Return>', lambda x: self.move(self.quickNav.get()))
self.boutonSuivant = Button(self.navigationFrame, text = "Suivant", command = lambda: self.move(0))
temp = divmod(len(data[0]), len(self.labels) // 2)
self.pages = temp[0] + (1 if temp[1] else 0)
self.position = Label(self.navigationFrame, text='Page 1 sur ' + str(self.pages))
self.pageCourante = 1
self.boutonRetour.grid(row = 0, column = 0)
self.quickNav.grid(row = 0, column = 1)
self.boutonSuivant.grid(row = 0, column = 2)
self.position.grid(row = 0, column = 3)
self.scroll = Scrollbar(self.parent, orient = VERTICAL, command = self.canvas.yview)
self.canvas.configure(yscrollcommand = self.scroll.set)
self.scroll.pack(side = RIGHT, fill='y')
self.canvas.pack(side = LEFT, fill = 'both')
self.canvas.create_window((4,4), window = self.mainFrame, anchor = "nw", tags = "frame")
self.canvas.configure(yscrollcommand = self.scroll.set)
self.mainFrame.bind("<Configure>", self.update)
self.canvas.configure(scrollregion = self.canvas.bbox("all"))
def update(self, event):
self.canvas.configure(scrollregion = self.canvas.bbox("all"))
def move(self, direction):
if (self.pageCourante == 1 and direction == -2) or (self.pageCourante == self.pages and direction == 0):
return
if direction in (-2, 0):
self.pageCourante += direction + 1
else:
try:
temp = int(direction)
if temp not in range(1, self.pages + 1):
return
except ValueError:
return
else:
self.pageCourante = temp
for i in range(len(self.labels)):
try:
location = str(self.data[i % 2][len(self.labels)*(self.pageCourante - 1) + i])
except IndexError:
location = ''
self.labels[i].config(text = location)
self.position.config(text = 'Page ' + str(self.pageCourante) + ' sur ' + str(self.pages))
I don't understand why the scrollbar isn't working properly. Note, that my parent is a notebook.
Also, there is a problem with the number of items displayed. The number of pages is right but it seems it displays more than it should cause last pages are empty and the last values displayed seems right.
Thank you for your attention
The scrollbar doesn't work by continuously creating new widgets ad infinitum. You were also missing some key parts - unfortunately, Scrollbar isn't as straightforward as most tkinter widgets.
from tkinter import *
class Application(object):
def __init__(self, parent):
self.parent = parent
self.canvas = Canvas(self.parent, bg='black', width = 200, height = 500)
self.mainFrame = Frame(self.canvas)
self.scroll = Scrollbar(self.parent, orient = VERTICAL, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side='right', fill='y')
self.canvas.pack(side='left', fill='both')
self.canvas.create_window((4,4), window=self.mainFrame, anchor="nw", tags="frame")
self.canvas.configure(yscrollcommand = self.scroll.set)
self.mainFrame.bind("<Configure>", self.update)
self.x = []
for i in range(1000):
self.x.append(Label(self.mainFrame, text=str(i)))
self.x[i].grid()
def update(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == '__main__':
root = Tk()
app = Application(root)
root.mainloop()
If you'd like to show only a few at a time and provide a forum-like interface, you can use Buttons to navigate between pages. This example allows the user to navigate with Back and Forward buttons, as well as by entering a page number in the box and pressing Enter.
from tkinter import *
class Application(object):
def __init__(self, parent):
self.x = list(range(1000))
self.labels = []
self.parent = parent
self.navigation_frame = Frame(self.parent)
self.canvas = Canvas(self.parent, bg='black', width = 200, height = 500)
self.mainFrame = Frame(self.canvas)
self.navigation_frame.pack()
for i in range(100):
self.labels.append(Label(self.mainFrame, text=str(i)))
self.labels[i].grid()
self.back_button = Button(self.navigation_frame, text='Back', command=lambda: self.move(-2))
self.quick_nav = Entry(self.navigation_frame, width=3)
self.quick_nav.bind('<Return>', lambda x: self.move(self.quick_nav.get()))
self.forward_button = Button(self.navigation_frame, text='Forward', command=lambda: self.move(0))
temp = divmod(len(self.x), len(self.labels))
self.pages = temp[0] + (1 if temp[1] else 0)
self.you_are_here = Label(self.navigation_frame, text='Page 1 of ' + str(self.pages))
self.current_page = 1
self.back_button.grid(row=0, column=0)
self.quick_nav.grid(row=0, column=1)
self.forward_button.grid(row=0, column=2)
self.you_are_here.grid(row=0, column=3)
self.scroll = Scrollbar(self.parent, orient = VERTICAL, command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side='right', fill='y')
self.canvas.pack(side='left', fill='both')
self.canvas.create_window((4,4), window=self.mainFrame, anchor="nw", tags="frame")
self.canvas.configure(yscrollcommand = self.scroll.set)
self.mainFrame.bind("<Configure>", self.update)
def update(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def move(self, direction):
if (self.current_page == 1 and direction == -2) or (self.current_page == self.pages and direction == 0):
return
if direction in (-2, 0):
self.current_page += direction + 1
else:
try:
temp = int(direction)
if temp not in range(1, self.pages+1):
return
except ValueError:
return
else:
self.current_page = temp
for i in range(len(self.labels)):
try:
location = str(self.x[len(self.labels)*(self.current_page - 1) + i])
except IndexError:
location = ''
self.labels[i].config(text=location)
self.you_are_here.config(text='Page ' + str(self.current_page) + ' of ' + str(self.pages))
if __name__ == '__main__':
root = Tk()
app = Application(root)
root.mainloop()

Resources