Tkinter horizontal Scrollbar not working as expected with Treeview - python

I have created a Treeview widget to be filled later, with file names and paths. The horizontal and vertical scrollbars are created.
But when I load the Treeview with a line that exceeds its width, the cursor in the horizontal Scrollbar does not show up (can't scroll to the right). When several lines are loaded the vertical Scrollbar works as expected.
Here is a sample code to test what I have done:
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
"""Root window of tkinter app"""
def __init__(self):
super().__init__()
self.title('Test')
Output(self)
class Output(ttk.Frame):
"""Tab frame displaying analysis output"""
def __init__(self, parent):
super().__init__(parent)
self.grid(row=0, column=0, columnspan=2, rowspan=6, padx=5, pady=5, sticky=tk.NSEW)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=3)
self.results = None
self.files_panel = FilesPanel(self)
self.previous = CommandPanel(self)
self.previous.load_btn['command'] = self.load_treeview
def load_treeview(self):
dummy_path = ['dummy_path', 'Long/path/to/file/somewhere/requires/scrollbar/to/be/read']
self.files_panel.tv.insert('', tk.END, values=dummy_path)
class FilesPanel(ttk.LabelFrame):
def __init__(self, parent):
super().__init__(parent)
self.config(text='Analysed files')
self.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW)
columns = ('file_name', 'path')
self.tv = ttk.Treeview(self, columns=columns, show='headings')
self.tv.heading('file_name', text='File')
self.tv.column('file_name', width=100)
self.tv.heading('path', text='Path')
self.tv.column('path', width=200)
self.tv.grid(row=0, column=0, padx=5, pady=5, sticky=tk.NSEW)
self.add_scrollbars(self)
def add_scrollbars(self, container):
self.sb_x = ttk.Scrollbar(container, orient=tk.HORIZONTAL, command=self.tv.xview)
self.sb_y = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.tv.yview)
self.tv.configure(xscrollcommand=self.sb_x.set, yscrollcommand=self.sb_y.set)
self.sb_x.grid(row=1, column=0, sticky=tk.EW)
self.sb_y.grid(row=0, column=1, sticky=tk.NS)
class CommandPanel(ttk.LabelFrame):
def __init__(self, parent):
super().__init__(parent)
self.output = parent
self.config(text='Previous results')
self.grid(row=1, column=0, padx=5, pady=5, sticky=tk.EW)
self.load_btn = ttk.Button(self, text='Load')
self.load_btn.grid(column=0, row=0, sticky=tk.W, padx=5, pady=5)
if __name__ == '__main__':
app = App()
app.mainloop()
NB:

Related

Tkinter - Disable button on click made in a for loop

I need to change the background color and disable the button that is clicked in the following code. I have tried to pass button in the command for the button but it doesn't seem to work.
I tried adding to my lambda call on the button variable: btn=button and then passing that through my function call, but I get the error "UnboundLocalError: local variable 'button' referenced before assignment"
How can i add to my disable_btn() function to disable the button and turn it grey.
Thanks
import tkinter as tk
from tkinter import font as tkfont
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
self.frames["StartPage"] = StartPage(parent=container, controller=self)
self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.grid(columnspan=5, rowspan=5)
self.populate = tk.Button(self, text='Populate Data', command=lambda : self.data())
self.populate.pack(side='top')
self.frame = tk.Frame(self)
self.frame.pack()
self.canvas = tk.Canvas(self.frame, borderwidth=0)
self.canvas.pack(side='left', fill='both', expand=True)
def data(self):
row = 1
for x in range(5):
print(x)
label = tk.Label(self.canvas, text='Line {}'.format(row))
label.grid(row=row, column=1, padx=15, pady=15)
text = tk.Text(self.canvas, width=5, height=1)
text.grid(row=row, column=2, padx=15, pady=15)
button = tk.Button(self.canvas, text='Click me', bg='white', command=lambda line=row:stored_functions.disable_btn(self, line))
button.grid(row=row, column=3, padx=15, pady=15)
row+=1
class stored_functions():
def disable_btn(self, line):
print('Disabled the button on line {}'.format(line))
btn.configure(state='disabled', bg='grey')
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
You need to pass the button widget as an argument to the function associated with its command. However you can't do it in the same call as the one that creates the Button because it doesn't exist yet. A simple way to workaround that impediment is to do it in two steps:
def data(self):
row = 1
for x in range(5):
print(x)
label = tk.Label(self.canvas, text='Line {}'.format(row))
label.grid(row=row, column=1, padx=15, pady=15)
text = tk.Text(self.canvas, width=5, height=1)
text.grid(row=row, column=2, padx=15, pady=15)
button = tk.Button(self.canvas, text='Click me', bg='white')
button.grid(row=row, column=3, padx=15, pady=15)
button.config(command=lambda btn=button, line=row: disable_btn(btn, line))
row += 1
def disable_btn(btn, line):
print('Disabled the button on line {}'.format(line))
btn.configure(state='disabled', bg='grey')

tkinter: How to get value from ComboBox in one frame with button in different frame

The goal is to allow the user to select from the combobox dropdown and then click Select Files button. The button will get the product type (the value from the combobox) and will open the correct directory based on what is chosen in the combobox. Problem is, I cannot seem to get this value since the button and combobox are in different frames. I feel like I'm missing something basic here.
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
def select_files(prod_type):
path = f"\\\\10.10.3.7\\Production\\Test_Folder\\{prod_type}"
filetypes = (
('PDF Files', '*.pdf'),
)
filenames = fd.askopenfilenames(
title='Open files',
initialdir=path,
filetypes=filetypes)
for file in filenames:
print(file)
class InputFrame(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# setup the grid layout manager
self.columnconfigure(0, weight=1)
self.columnconfigure(0, weight=3)
self.__create_widgets()
def __create_widgets(self):
# Product
ttk.Label(self, text='Product:').grid(column=0, row=0, sticky=tk.W)
self.product_type = tk.StringVar()
self.product_combo = ttk.Combobox(self, width=30, textvariable=self.product_type)
self.product_combo['values'] = ('Notepad', 'Flat Notecard', 'Folded Notecard', 'Journal')
self.product_combo.set('Notepad')
self.product_combo['state'] = 'readonly'
self.product_combo.grid(column=1, row=0, sticky=tk.W)
# Algorithm:
ttk.Label(self, text='Algorithm:').grid(column=0, row=1, sticky=tk.W)
algo_var = tk.StringVar()
algo_combo = ttk.Combobox(self, width=30)
algo_combo['values'] = ('panel', 'fuzzy')
algo_combo.set('panel')
algo_combo.grid(column=1, row=1, sticky=tk.W)
# Orientation:
ttk.Label(self, text='Orientation:').grid(column=0, row=2, sticky=tk.W)
orientation_var = tk.StringVar()
orientation_combo = ttk.Combobox(self, width=30, textvariable=orientation_var)
orientation_combo['values'] = ('auto', 'portrait', 'landscape')
orientation_combo.set('auto')
orientation_combo.grid(column=1, row=2, sticky=tk.W)
# Margin:
ttk.Label(self, text='Margin:').grid(column=0, row=3, sticky=tk.W)
margin = ttk.Entry(self, width=30)
margin.grid(column=1, row=3, sticky=tk.W)
# Gap:
ttk.Label(self, text='Gap:').grid(column=0, row=4, sticky=tk.W)
gap = ttk.Entry(self, width=30)
gap.grid(column=1, row=4, sticky=tk.W)
# Repeat:
ttk.Label(self, text='Repeat:').grid(column=0, row=5, sticky=tk.W)
repeat_number = tk.StringVar()
repeat = ttk.Spinbox(self, from_=1, to=10, width=30, textvariable=repeat_number)
repeat.set(1)
repeat.grid(column=1, row=5, sticky=tk.W)
for widget in self.winfo_children():
widget.grid(padx=0, pady=5)
class ButtonFrame(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# setup the grid layout manager
self.columnconfigure(0, weight=1)
self.__create_widgets()
def __create_widgets(self):
ttk.Button(self, text='Select Files', command=self.on_go_pressed).grid(column=0, row=0)
ttk.Button(self, text='Generate PDF').grid(column=0, row=1)
for widget in self.winfo_children():
widget.grid(padx=0, pady=3)
def on_go_pressed(self):
select_files(InputFrame.product_type.get())
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("PDF n-up")
self.eval('tk::PlaceWindow . center')
self.geometry('400x200')
self.resizable(0, 0)
self.attributes('-toolwindow', True)
# layout on the root window
self.columnconfigure(0, weight=4)
self.columnconfigure(1, weight=1)
self.__create_widgets()
def __create_widgets(self):
# create the input frame
input_frame = InputFrame(self)
input_frame.grid(column=0, row=0)
# create the button frame
button_frame = ButtonFrame(self)
button_frame.grid(column=1, row=0)
if __name__ == '__main__':
app = App()
app.mainloop()
You can pass the product type variable to ButtonFrame when you create it, since you create the ButtonFrame after creating the InputFrame. Here is the code, with changed and added lines marked accordingly:
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog as fd
def select_files(prod_type):
path = f"/home/sam/Pictures/Test/{prod_type}"
filetypes = (
('PDF Files', '*.pdf'),
)
filenames = fd.askopenfilenames(
title='Open files',
initialdir=path,
filetypes=filetypes)
for file in filenames:
print(file)
class InputFrame(ttk.Frame):
def __init__(self, parent):
super().__init__(parent)
# setup the grid layout manager
self.columnconfigure(0, weight=1)
self.columnconfigure(0, weight=3)
self.__create_widgets()
def __create_widgets(self):
# Product
ttk.Label(self, text='Product:').grid(column=0, row=0, sticky=tk.W)
self.product_type = tk.StringVar()
self.product_combo = ttk.Combobox(self, width=30, textvariable=self.product_type)
self.product_combo['values'] = ('Notepad', 'Flat Notecard', 'Folded Notecard', 'Journal')
self.product_combo.set('Notepad')
self.product_combo['state'] = 'readonly'
self.product_combo.grid(column=1, row=0, sticky=tk.W)
# Algorithm:
ttk.Label(self, text='Algorithm:').grid(column=0, row=1, sticky=tk.W)
algo_var = tk.StringVar()
algo_combo = ttk.Combobox(self, width=30)
algo_combo['values'] = ('panel', 'fuzzy')
algo_combo.set('panel')
algo_combo.grid(column=1, row=1, sticky=tk.W)
# Orientation:
ttk.Label(self, text='Orientation:').grid(column=0, row=2, sticky=tk.W)
orientation_var = tk.StringVar()
orientation_combo = ttk.Combobox(self, width=30, textvariable=orientation_var)
orientation_combo['values'] = ('auto', 'portrait', 'landscape')
orientation_combo.set('auto')
orientation_combo.grid(column=1, row=2, sticky=tk.W)
# Margin:
ttk.Label(self, text='Margin:').grid(column=0, row=3, sticky=tk.W)
margin = ttk.Entry(self, width=30)
margin.grid(column=1, row=3, sticky=tk.W)
# Gap:
ttk.Label(self, text='Gap:').grid(column=0, row=4, sticky=tk.W)
gap = ttk.Entry(self, width=30)
gap.grid(column=1, row=4, sticky=tk.W)
# Repeat:
ttk.Label(self, text='Repeat:').grid(column=0, row=5, sticky=tk.W)
repeat_number = tk.StringVar()
repeat = ttk.Spinbox(self, from_=1, to=10, width=30, textvariable=repeat_number)
repeat.set(1)
repeat.grid(column=1, row=5, sticky=tk.W)
for widget in self.winfo_children():
widget.grid(padx=0, pady=5)
class ButtonFrame(ttk.Frame):
def __init__(self, parent, product_type): ### EDITED THIS LINE
super().__init__(parent)
# setup the grid layout manager
self.columnconfigure(0, weight=1)
self.product_type = product_type ### ADDED THIS LINE
self.__create_widgets()
def __create_widgets(self):
ttk.Button(self, text='Select Files', command=self.on_go_pressed).grid(column=0, row=0)
ttk.Button(self, text='Generate PDF').grid(column=0, row=1)
for widget in self.winfo_children():
widget.grid(padx=0, pady=3)
def on_go_pressed(self):
select_files(self.product_type.get()) ### EDITED THIS LINE
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("PDF n-up")
self.eval('tk::PlaceWindow . center')
self.geometry('400x200')
self.resizable(0, 0)
# self.attributes('-toolwindow', True)
# layout on the root window
self.columnconfigure(0, weight=4)
self.columnconfigure(1, weight=1)
self.__create_widgets()
def __create_widgets(self):
# create the input frame
input_frame = InputFrame(self)
input_frame.grid(column=0, row=0)
# create the button frame
button_frame = ButtonFrame(self, input_frame.product_type) ### EDITED THIS LINE
button_frame.grid(column=1, row=0)
if __name__ == '__main__':
app = App()
app.mainloop()
Notice how in the line button_frame = ButtonFrame(self, input_frame.product_type), I give it input_frame.product_type as an argument, so that it can access it any time it wants.
The changes to ButtonFrame required for this: I changed the __init__() method so that it can receive another argument. It then assigns the value of the product_type argument to a variable so that it can use it later. When it calls select_files(), it simply uses self.product_type.
As to why calling select_files(InputFrame.product_type.get()) doesn't work: product_type is a variable that is created only when InputFrame is initialized. In the line above, you reference the class itself, not an instance of the class, so it has not been initialized. Therefore, anything that is created in InputFrame.__init__() is not defined, becuase __init__() wasn't called.

Is It possible to create multiple form fields in tkinter & python and then submit it to a out to an output textbox in a table column format

So my problem is that I want to create multiple entry fields like over 30, but every time I reformat it using .pack or .grid it keeps throwing off the formatting. is there a way to fit nearly 30 entry boxes on one window without using anything like SQLite? As we can see from this code, we have 4 fields, how would you go on with shrinking the boxes to put in more entry fields like over 30.
Secondly, I want to output all the typed data entry fields to the Listbox is there a way to add a table column to the list box to show a breakdown of each entry field.
The third is it possible to move the Listbox to another tab on the same window to show all entry fields that were typed in, if so how would you do so.
Here is my current code so far
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from datetime import *
# Import Packages
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import *
import tkinter.filedialog
from tkcalendar import Calendar, DateEntry
from tkinter import messagebox
from tkintertable import TableCanvas, TableModel
from tkinter import ttk
# Database
#import sqlite3
import csv
window = Tk()
window.title("TESTTEST")
window.geometry("750x450")
window.config(background='black')
#style = ttk.Style(window)
#style.configure('lefttab.TNotebook', tabposition='wn',)
# TAB LAYOUT
#tab_control = ttk.Notebook(window,style='righttab.TNotebook')
#tab1 = ttk.Frame(tab_control)
#tab2 = ttk.Frame(tab_control)
#tab3 = ttk.Frame(tab_control)
#tab4 = ttk.Frame(tab_control)
#tab5 = ttk.Frame(tab_control)
#tab6 = ttk.Frame(tab_control)
# ADD TABS TO NOTEBOOK
#tab_control.add(tab1, text=f'{"Home":^20s}')
#tab_control.add(tab2, text=f'{"View":^20s}')
#tab_control.add(tab3, text=f'{"Search":^20s}')
#tab_control.add(tab4, text=f'{"Edit":^20s}')
#tab_control.add(tab5, text=f'{"Export":^20s}')
#tab_control.add(tab6, text=f'{"About ":^20s}')
#label1 = Label(tab1, text= 'Python RPA APP',padx=1, pady=1)
#label1.grid(column=0, row=0)
#label2 = Label(tab2, text= 'View',padx=5, pady=5)
#label2.grid(column=0, row=0)
#label3 = Label(tab3, text= 'Search',padx=5, pady=5)
#label3.grid(column=0, row=0)
#label4 = Label(tab4, text= 'Edit/Update',padx=5, pady=5)
#label4.grid(column=0, row=0)
#label5 = Label(tab5, text= 'Export',padx=5, pady=5)
#label5.grid(column=0, row=0)
#label6 = Label(tab6, text= 'About',padx=5, pady=5)
#label6.grid(column=0, row=0)
#tab_control.pack(expand=1, fill='both')
class Main(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.punches_list = []
self.ent1 = tk.StringVar()
self.ent2 = tk.StringVar()
self.ent3 = tk.StringVar()
self.ent4 = tk.StringVar()
self.init_ui()
def init_ui(self):
f = ttk.Frame()
# ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
## ttk.Label(f, text = "Entry1").pack(side=LEFT, padx=5, pady=5, anchor=NW)
## self.txTest = ttk.Entry(f,textvariable=self.ent).pack(fill=X, padx=5, expand=True, anchor=NW)
# ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW)
# self.txTest1 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW)
ttk.Label(f, text = "Entry1").pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest1 = ttk.Entry(f, textvariable=self.ent1).pack(side=TOP, anchor=NW, fill=tk.BOTH, pady=5, padx=5, expand=0)
ttk.Label(f, text = "Entry2").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest2 = ttk.Entry(f, textvariable=self.ent2).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
ttk.Label(f, text = "Entry3").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest3 = ttk.Entry(f, textvariable=self.ent3).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
#tkinter.Label(window, text = "Username").grid(row = 0) #'username' is placed on position 00 (row - 0 and column - 0)
#tkinter.Entry(window).grid(row = 0, column = 1) # first input-field is placed on position 01 (row - 0 and column - 1)
ttk.Label(f, text = "Entry4").pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.txTest4 = ttk.Entry(f, textvariable=self.ent4).pack(side=TOP, anchor=NW,fill=tk.BOTH, pady=5, padx=5, expand=0)
self.lstItems = self.get_listbox(f, 140,140).pack(anchor=N)
w = ttk.Frame()
ttk.Button(w, text="Add",command=self.add_In).pack(side=TOP, anchor=NE)
ttk.Button(w, text="Clear", command=self.clear_Out).pack(side=TOP, anchor=NE)
ttk.Button(w, text="Close", command=self.on_close).pack(side=TOP, anchor=NE)
#f.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
#w.pack(side=tk.RIGHT, fill=tk.BOTH, expand=1)
f.pack(side=tk.LEFT, fill=tk.BOTH, pady=5, padx=5, expand=1)
w.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
def add_In(self,):
#s = "IN {0:>30} {1}".format(str(datetime.now()), self.ent.get())
s = self.ent1.get()
self.set_list(s)
s = self.ent2.get()
self.set_list(s)
s = self.ent3.get()
self.set_list(s)
s = self.ent4.get()
self.set_list(s)
self.ent1.set('')
self.ent2.set('')
self.ent3.set('')
self.ent4.set('')
def clear_Out(self):
#s = "OUT {0:>29} {1}".format(str(datetime.now()), self.ent1.get())
#field_name.set('')
self.ent1.set('')
self.ent2.set('')
self.ent3.set('')
self.ent4.set('')
#self.set_list(s)
def set_list(self,s):
self.punches_list.append(s)
self.lstItems.delete(0, tk.END)
for i in self.punches_list:
self.lstItems.insert(tk.END, i)
def on_set(self):
self.check.set(1)
def on_close(self):
#self.destroy()
self.parent.on_exit()
def get_listbox(self, container, height=750, width=600):
sb = tk.Scrollbar(container,orient=tk.VERTICAL)
w = tk.Listbox(container,
relief=tk.GROOVE,
selectmode=tk.BROWSE,
height=height,
width=width,
background = 'white',
font='TkFixedFont',
yscrollcommand=sb.set,)
sb.config(command=w.yview)
w.pack(side=tk.LEFT,fill=tk.BOTH, expand =1)
sb.pack(fill=tk.Y, expand=1)
return w
class App(tk.Tk):
"""Start here"""
def __init__(self):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_style()
self.set_title()
Main(self,)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("vista") #change to your liking :)
def set_title(self):
s = "{0}".format('Employee Time-Clock')
self.title(s)
self.destroy()
def on_exit(self):
window.destroy()
#self.destroy()
#sys.exit()
#"""Close all"""
#if messagebox.askokcancel( self.title(), "Do you want to quit?", parent=self):
# self.destroy()
if __name__ == '__main__':
app = App()
app.mainloop()
Your code is a giant mess, brah ;D. What I gather from your question is that you need some kind of table. What I gather from your code is the table should have cells comprised of Label and Entry. You also want an interface to create entries. Below is an example of all of that. I don't really see anything to explain. It's just a bunch of Frame, Label, Entry and Button. The only real action is in Table. All that action is, is mathematically figuring out where to put the next Item. This is all really basic stuff.
import tkinter as tk
from tkinter import ttk
#the entire bottom row of the app.
#has a dependency on self.master.table ~ not good OOP
class EntryManager(tk.Frame):
def __init__(self, master, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid_columnconfigure(5, weight=1)
font='Helvetica 10 bold'
tk.Label(self, text='Label', font=font, width=5).grid(row=0, column=0, padx=2)
lbl = tk.Entry(self, width=10, font=font)
lbl.grid(row=0, column=1, padx=2)
tk.Label(self, text='Entry', font=font, width=5).grid(row=0, column=2, padx=2)
ent = tk.Entry(self, width=25, font=font)
ent.grid(row=0, column=3, padx=2)
tk.Button(self, text='add', font=font, command=lambda: self.master.table.addItem(lbl.get(), ent.get())).grid(row=0, column=4, padx=2, sticky='w')
tk.Label(self, text='rows', font=font, width=4).grid(row=0, column=5, padx=2, sticky='e')
r = tk.Entry(self, width=4, font=font)
r.insert('end', self.master.table.rows)
r.grid(row=0, column=6, padx=2)
tk.Label(self, text='cols', font=font, width=4).grid(row=0, column=7, padx=2)
c = tk.Entry(self, width=4, font=font)
c.insert('end', self.master.table.cols)
c.grid(row=0, column=8, padx=2)
tk.Button(self, text='set', font=font, command=lambda: self.master.table.setDims(r.get(), c.get())).grid(row=0, column=9, padx=2, sticky='e')
#generic scrollable frame
class ScrollFrame(tk.Frame):
def __init__(self, master, row=0, column=0, scrollspeed=.02, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.grid(row=row, column=column, sticky='nswe')
self.scrollspeed = scrollspeed
self.canvas = tk.Canvas(self, highlightthickness=0)
self.canvas.grid(column=0, row=0, sticky='nswe')
self.v_scroll = tk.Scrollbar(self, orient='vertical', command=self.canvas.yview)
self.v_scroll.grid(row=0, column=1, sticky='ns')
self.canvas.configure(yscrollcommand=self.v_scroll.set)
self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)
self.frame = tk.Frame(self.canvas, height=0)
self.frame.grid_columnconfigure(0, weight=1)
self.frame.bind('<Configure>', lambda e:self.canvas.configure(scrollregion=self.canvas.bbox("all")))
self.canvas.create_window((0,0), window=self.frame, anchor="nw")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
def on_mousewheel(self, event):
self.canvas.yview_moveto(self.v_scroll.get()[0]+((-event.delta/abs(event.delta))*self.scrollspeed))
#a table cell
class Item(tk.Frame):
#property
def value(self):
return self.__value.get()
#value.setter
def value(self, text):
self.__value.set(text)
def __init__(self, master, text, value, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
tk.Label(self, text=text, width=10, font='none 8 bold').grid(row=0, column=0, pady=5, padx=5)
self.__value = tk.StringVar(value=value)
tk.Entry(self, textvariable=self.__value, width=25).grid(row=0, column=1, pady=5, padx=5)
#the table
class Table(ScrollFrame):
def __init__(self, master, rows=15, cols=3, **kwargs):
ScrollFrame.__init__(self, master, **kwargs)
self.entries = []
self.rows = rows
self.cols = cols
def addItem(self, text, value):
if len(self.entries) < self.rows*self.cols:
self.entries.append(Item(self.frame, text, value))
self.entries[-1].grid(row=(len(self.entries)-1)%self.rows, column=(len(self.entries)-1)//self.rows)
def getItem(self, row, column):
return self.entries[self.rows*column+row].value
def setDims(self, rows, cols):
if rows.isnumeric():
self.rows = int(rows)
if cols.isnumeric():
self.cols = int(cols)
for ent in self.entries:
ent.grid_forget()
for i, ent in enumerate(self.entries):
if i < self.rows*self.cols:
ent.grid(row=i%self.rows, column=i//self.rows)
class App(tk.Tk):
WIDTH, HEIGHT, TITLE = 770, 465, 'Application'
def __init__(self):
tk.Tk.__init__(self)
ttk.Style().theme_use("vista")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.table = Table(self, rows=20, cols=3)
self.table.grid(row=0, column=0, sticky='nswe')
EntryManager(self).grid(row=1, column=0, sticky='nswe', ipady=5)
#junk for testing
for i in range(12):
self.table.addItem(f'entry_{i}', f'data {i}')
if __name__ == '__main__':
app = App()
app.config(background='black')
app.title(App.TITLE)
app.geometry(f'{App.WIDTH}x{App.HEIGHT}')
#app.resizable(width=False, height=False)
app.mainloop()
Might as well dump the table keys in the table and see what happens. The sizes and alignments of things could use some work.

How can I make the "add task" button not accepting empty strings?

the following code has an error where the "add task" button will add an empty input into the listbox by creating spaces between 2 tasks. Is there a way by coding this where it can't happen? I want the list in the listbox to be sequential where each task appears one after another. I don't understand why this happens. Is it a part of python? Thanks again.
import tkinter as tk
def main():
root = tk.Tk()
root.geometry("350x450")
root.title("basic window")
root.config(background="azure")
app = Application (root)
root.mainloop()
class Application(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, bg="yellow", bd=2, relief=tk.RIDGE)
self.parent = parent
self.initUI()
def initUI(self):
self.pack(fill="both", expand=1)
#widget layout
self.listbox = tk.Listbox(self, bd=2, relief=tk.SUNKEN, height="15")
self.listbox.grid(row=0, column=0, sticky="w", padx=5, pady=5)
self.entry=tk.Entry(self, width=19)
self.entry.grid(row=1, stick="w", padx=5)
self.button1=tk.Button(self, text="add task", command=self.update)
self.button1.grid(row=1, column=1, sticky="w", padx=5)
self.label=tk.Label(self, text="stats", bg="yellow")
self.label.grid(row=0, column=1, sticky="n")
#programing
def update(self):
self.listbox.insert("end", self.entry.get())
self.entry.delete(0, "end")
if __name__ == '__main__':
main()
in update(self), you need to test if self.entry.get() contains an empty string; if it does, skip the update.
import tkinter as tk
class Application(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, bg="yellow", bd=2, relief=tk.RIDGE)
self.parent = parent
self.initUI()
def initUI(self):
self.pack(fill="both", expand=1)
#widget layout
self.listbox = tk.Listbox(self, bd=2, relief=tk.SUNKEN, height="15")
self.listbox.grid(row=0, column=0, sticky="w", padx=5, pady=5)
self.entry=tk.Entry(self, width=19)
self.entry.grid(row=1, stick="w", padx=5)
self.button1=tk.Button(self, text="add task", command=self.update)
self.button1.grid(row=1, column=1, sticky="w", padx=5)
self.label=tk.Label(self, text="stats", bg="yellow")
self.label.grid(row=0, column=1, sticky="n")
#programing
def update(self):
if self.entry.get() != '':
self.listbox.insert("end", self.entry.get())
self.entry.delete(0, "end")
def main():
root = tk.Tk()
root.geometry("350x450")
root.title("basic window")
root.config(background="azure")
app = Application (root)
root.mainloop()
if __name__ == '__main__':
main()
def update(self):
if not self.entry.get()== "": #.get gets the value thgat the entry contains
self.listbox.insert("end", self.entry.get())
self.entry.delete(0, "end")
Also on a side note i would suggest using better names for example instead of self.entry use something self.intput_txt, when i make object i tend to use _txt or _lbl ectra as it makes it easier to see at a glance what type of object it is

How can I place the output of different button functions in tkinter in a particular frame?

I'm new to Python.
On clicking the button "check connection", I want the message to be displayed in the tkinter window itself, rather than a message box... I want the output of every button function in the same place in the tkinter.
from Tkinter import *
import subprocess
root = Tk()
root.geometry("850x500+300+300")
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Windows")
#self.style = Style()
#self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = Label(self, text="Windows")
lbl.grid(sticky=W, pady=4, padx=5)
abtn = Button(self, text="Check Wired Connections",command = self.checkconnections)
abtn.grid(row=1, column=3)
cbtn = Button(self, text="Check Wireless Connections")
cbtn.grid(row=3, column=3, pady=4)
obtn = Button(self, text="OK")
obtn.grid(row=5, column=3)
self.v = StringVar()
messagelabel=Label(self, textvariable=self.v)
messagelabel.grid(row=1, column=0, pady=0)
def checkconnections(self):
p = subprocess.call('nm-tool')
print p
self.v.set(p)
def main():
app = Example(root)
root.mainloop()
main()
then create label in your class
class Example(Frame):
.....
self.v = StringVar()
messagelabel=Label(self, textvariable=v).pack()
self.v.set("")
......
def checkconnections():
p1 = subprocess.check_output('nm-tool' )
self.v.set('nm-tool', p1)
from Tkinter import *
import subprocess
root = Tk()
root.geometry("850x500+300+300")
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Windows")
#self.style = Style()
#self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
lbl = Label(self, text="Windows")
lbl.grid(sticky=W, pady=4, padx=5)
abtn = Button(self, text="Check Wired Connections",command = self.checkconnections)
abtn.grid(row=1, column=3)
cbtn = Button(self, text="Check Wireless Connections")
cbtn.grid(row=3, column=3, pady=4)
obtn = Button(self, text="OK")
obtn.grid(row=5, column=3)
self.v = StringVar()
messagelabel=Label(self, textvariable=self.v)
messagelabel.grid(row=1, column=0, pady=0)
def checkconnections(self):
self.v.set("hai")
def main():
app = Example(root)
root.mainloop()
main()

Categories

Resources