I want to add a horizontal scroll bar to the particular tree-view table since I have not used Tkinter before so please help!
import tkinter
def __create_tree_view(self):
""" Creates a TreeView Layout with req Headers """
style = it.Style()
style.configure("Custom.Treeview.Heading",foreground="green", relief="flat")
style.map("Custom.Treeview.Heading", relief=[('active','groove'),('pressed','sunken')])
style.configure('Treeview', rowheight=20)
#
self.tree_view = ttk.Treeview(self.right_frame, selectmode ='browse',\
style="Custom.Treeview")
self.tree_view.grid(row=1, column=1, sticky=tk.NSEW)
self.verticalscrollba = ttk.Scrollbar(self.right_frame, orient="vertical", \
command=self.tree_view.view)
self. verticalscrollbar.grid(row=1,column=1,sticky='nse')
self.tree_view.configure(yscrollcommand = self.verscrlbar.set)
# Defining number of columns
self.tree_view["columns"] = ("1", "2", "3", "4")
# Defining heading
self.tree_view['show'] = 'headings'
# Assigning the width and anchor to the respective columns
self.tree_view.column("1", width = int(self.window_width/5), anchor ='ca, stretch=False)
self.tree_view.column("2", width = int(self.window_width/4)-30, anchor ='ca, stretch=False)
self.tree_view.column("3", width = int(self.window_width/6)-30, anchor ='ca, stretch=False)
self.tree_view.column("4", width = int(self.window_width/3), anchor ='ca, stretch=False)
# Assigning the heading names to the respective columns
self.tree_view.heading("1", text ="Brand/Model/Type")
self.tree_view.heading("2", text ="Device_Id")
self.tree_view.heading("3", text ="Device_Ip")
self.tree_view.heading("4", text ="GUID")
where the brand is the brand of the device IP, is IP address and
so here in this code how to add a horizontal scroll bar without overwriting the last line of the treeview table I tried to add the scrollbar but it's displaying on the last row of the table it should display below the last row of the table
Try this an example.
import tkinter as tk
from tkinter import ttk
class Chrisdb1(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.tvw_results = ttk.Treeview(self, style = 'mystyle.Treeview')
self.insert = self.tvw_results.insert
self.tvw_results.grid(row = 0, column = 0, sticky='nsew')
self.tvw_results.column("#0", minwidth = 1150)
self.tvw_results.heading('#0', text = 'Found results', anchor = tk.W)
# Scrollbars + attach scrollbars to TreeView
sb_vertical = tk.Scrollbar(self, orient = "vertical", command = self.tvw_results.yview)
sb_horizontal = tk.Scrollbar(self, orient = "horizontal", command = self.tvw_results.xview)
self.tvw_results.configure(yscrollcommand = sb_vertical.set, xscrollcommand = sb_horizontal.set)
sb_vertical.grid(row = 0, column = 1, sticky = "ns")
sb_horizontal.grid(row = 1, column = 0, sticky = "ew")
# Configure and position grid for TreeView
self.grid_rowconfigure(0, weight = 1)
self.grid_columnconfigure(0, weight = 1)
def main():
'''test code for Chrisdb1 class'''
root = tk.Tk()
cnt_treeview = Chrisdb1(root)
for i in range(20):
cnt_treeview.insert('', tk.END, text = f'Row {i}: Some very long texxxxxxxt.....'*6)
cnt_treeview.pack(expand=True, fill=tk.BOTH)
root.mainloop()
if __name__ == '__main__':
main()
Related
from tkinter import *
#Root
root = Tk()
root.title('A WINDOW')
#Frame
main_frame = Frame(root)
main_frame.pack(fill=BOTH, expand = True)
#Canvas
main_canvas = Canvas(main_frame)
main_canvas.pack(side = LEFT, fill = BOTH, expand = True)
#Scrollbar
scrollbar = Scrollbar(main_frame, orient = VERTICAL, command = main_canvas.yview)
scrollbar.pack(side = RIGHT, fill = 'y')
#Configure the Canvas
main_canvas.configure(yscrollcommand=scrollbar.set)
#Frame#2
Frame2 = Frame(main_canvas)
main_canvas.create_window((0, 0), window = Frame2, anchor = 'nw')
main_canvas.bind('<Configure>', lambda e :main_canvas.configure(scrollregion=main_canvas.bbox('all')))
for i in range(2000):
Button(Frame2, text = str(i)).grid(row = i, column = 0)
root.mainloop()
and when I execute the program, it works until the 1080th one then scrollbar moves but buttons don't go down anymore I hope you understood me and have an idea about what must I do...
This is a slight modification of your code. It demonstrates the limitation of the window object in tk.Canvas with a maximum height of 32768. It can be shown by changing variable offset to some arbitrary value and scrolling to the end of canvas. The last button will still be visible even though its position is 32768+offset.
Function bookmark finds frame2 in the window object and finds all objects in frame2 then changes background color. This makes it easy to confirm first and last buttons are visible.
import tkinter as tk
root = tk.Tk()
frame = tk.LabelFrame(root, labelanchor = tk.S, text = '0|0')
frame.grid(row = 0, column = 0, sticky = tk.NSEW)
for a in [root, frame]:
a.rowconfigure(0, weight = 1)
a.columnconfigure(0, weight = 1)
main_canvas = tk.Canvas(frame)
main_canvas.grid(row = 0, column = 0, sticky = tk.NSEW)
scrollbar = tk.Scrollbar(frame, orient = tk.VERTICAL, command = main_canvas.yview)
scrollbar.grid(row = 0, column = 1, sticky = tk.NS)
main_canvas.configure(yscrollcommand = scrollbar.set)
def location(event):
x, y = main_canvas.canvasx(event.x), main_canvas.canvasy(event.y)
frame['text'] = f'{x} | {y}'
# bind mouse
main_canvas.bind('<Motion>', location)
frame2 = tk.Frame(main_canvas)
# frame is positioned at offset
offset = 0
main_canvas.create_window(0, offset, window = frame2, anchor = tk.NW)
def bookends(x):
# Find reference to frame2
C = main_canvas.winfo_children()[0]
# find all objects in frame2
D = C.winfo_children()
print(len(D))
# change colors of first and last buttons
D[0]['background'] = 'red'
D[x]['background'] = 'red'
for i in range(2000):
tk.Button(
frame2,
text = str(i),
font = '{Courier New} 6',
padx=0, pady=0).grid(
row = i, column = 0, ipadx = 0, ipady = 0)
bookends(1999)
# main_canvas['scrollregion'] = f'0 0 40 {32768+offset}'
main_canvas.bind('<Configure>', lambda e :main_canvas.configure(scrollregion=main_canvas.bbox('all')))
root.mainloop()
I cannot get x and y scrollbars to work in Tkinter with Python, although I have followed multiple examples:
How to add 2 scrollbars with tkinter in python 3.4
Adding a scrollbar to a group of widgets in tkinter
How to make a proper double scrollbar frame in tkinter
Vertical and Horizontal Scrollbars on Tkinter Widget
Scrolling a Canvas widget horizontally and vertically
The scrollbars appear, but do not activate when the window is smaller than the frame. How can I get this to work (see image below)?
Below is the minimal code that is producing my problem (Python 3.7)
import tkinter as tk
from tkinter import ttk
big_font = ("Arial", 50)
class DoubleScrollbarFrame(ttk.Frame):
def __init__(self,
parent,
*args,
**kwargs):
self.parent = parent
super().__init__(self.parent,
*args,
**kwargs)
#Set widgets to fill main window such that they are
#all the same size
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.create_widgets()
self.position_widgets()
def create_widgets(self):
self.canvas = tk.Canvas(self)
self.frame = ttk.Frame(self.canvas)
self.scroll_x = ttk.Scrollbar(self,
orient = tk.HORIZONTAL,
command = self.canvas.xview)
self.scroll_y = ttk.Scrollbar(self,
orient = tk.VERTICAL,
command = self.canvas.yview)
self.canvas.config(xscrollcommand = self.scroll_x.set,
yscrollcommand = self.scroll_y.set)
self.canvas.create_window((0,0),
window = self.frame,
anchor = 'nw')
self.frame.bind('<Configure>',
self.set_scrollregion)
self.sizegrip = ttk.Sizegrip(self)
#Test
self.test1 = tk.Label(self.frame,
text = 'Test 1',
font = big_font)
self.test2 = tk.Label(self.frame,
text = 'Test 2',
font = big_font)
self.test3 = tk.Label(self.frame,
text = 'Test 3',
font = big_font)
def position_widgets(self,
**kwargs):
self.test1.grid(row = 0,
column = 0,
sticky = 'w')
self.test2.grid(row = 1,
column = 0,
sticky = 'w')
self.test3.grid(row = 2,
column = 0,
sticky = 'w')
self.scroll_x.grid(row = 1,
column = 0,
sticky = 'ew')
self.scroll_y.grid(row = 0,
column = 1,
sticky = 'ns')
self.canvas.grid(row = 0,
column = 0,
sticky = 'nsew')
self.frame.grid(row = 0,
column = 0,
sticky = 'nsew')
self.sizegrip.grid(row = 1,
column = 1,
sticky = 'se')
def set_scrollregion(self,
event):
print('Frame Dimensions: {} x {}'.format(self.frame.winfo_width(),
self.frame.winfo_height()))
print('Canvas Dimensions: {} x {}'.format(self.canvas.winfo_width(),
self.canvas.winfo_height()))
self.canvas.configure(scrollregion = self.canvas.bbox('all'))
class MainApp(tk.Tk):
def __init__(self,
*args,
**kwargs):
super().__init__(*args,
**kwargs)
#Set widgets to fill main window such that they are
#all the same size
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.create_widgets()
self.position_widgets()
def create_widgets(self):
self.frame = DoubleScrollbarFrame(self)
def position_widgets(self):
self.frame.grid(row = 0,
column = 0,
sticky = 'nsew')
def exit(self):
self.destroy()
if __name__ == '__main__':
#Create GUI
root = MainApp()
#Run program
root.mainloop()
The problem is in these lines of code inside DoubleScrollbarFrame.position_widgets:
self.frame.grid(row = 0,
column = 0,
sticky = 'nsew')
This removes control of the widget from the canvas and gives control to grid. It is no longer a canvas object, so self.canvas.bbox("all") is returning (0, 0, 1, 1). If the scrollregion is set incorrectly, the scrollbars don't know how much to scroll.
The solution is simple: don't call grid on self.frame.
Running Python 3.4.2 and Tkinter 8.6 on a Raspberry Pi. I want to create a Text widget that fills a fixed sized frame using the grid layout manager.
If you run the code below, you'll see the Text widget doesn't fill the 800x600 frame. I realize I could set the Text's width and height attributes to fill the frame, but this would only work default font and wouldn't fill the frame exactly.
from tkinter import *
class Test(Tk):
def __init__(self):
super().__init__()
self.text = frameText(self)
self.geometry('{}x{}'.format(800, 600))
def frameText(frame, **kw):
ysb = Scrollbar(frame)
xsb = Scrollbar(frame, orient = HORIZONTAL)
text = Text(frame, **kw)
ysb.configure(command = text.yview)
xsb.configure(command = text.xview)
text.configure(yscrollcommand = ysb.set, xscrollcommand = xsb.set)
text.grid(row = 0, column = 0, sticky = N+E+S+W)
ysb.grid(row = 0, column = 1, sticky = N+S)
xsb.grid(row = 1, column = 0, sticky = E+W)
return text
if __name__ == '__main__':
Test().mainloop()
You need to configure the grid to give the row and column a nonzero weight so that they expand
from tkinter import *
class Test(Tk):
def __init__(self):
Tk.__init__(self)
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.text = frameText(self)
self.geometry('{}x{}'.format(800, 600))
def frameText(frame, **kw):
ysb = Scrollbar(frame)
xsb = Scrollbar(frame, orient = HORIZONTAL)
text = Text(frame, **kw)
ysb.configure(command = text.yview)
xsb.configure(command = text.xview)
text.configure(yscrollcommand = ysb.set, xscrollcommand = xsb.set)
text.grid(row = 0, column = 0, sticky = N+E+S+W)
ysb.grid(row = 0, column = 1, sticky = "ns")
xsb.grid(row = 1, column = 0, sticky = E+W)
return text
if __name__ == '__main__':
Test().mainloop()
I am making a maze where the user enters the dimensions and can then click on a button to change the colour of that button to black. What i eventually want is to be making an ai which will try to navigate the maze the user created with the black rectangle the ai not being allowed to go on.
The problem is i dont know how to change the properties of the button clicked as due to a nested loop being used for creation they all have the same name.
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.frame1 = tk.LabelFrame(self, text="entering diemsions", width=300, height=130, bd=5)
self.frame1.grid(row=0, column=0, columnspan=3, padx=8)
self.frame2 = tk.LabelFrame(self, text="creating maze", width=300, height=130, bd=5)
self.frame2.grid(row=1, column=0, columnspan=3, padx=8)
self.create_GUI()
def create_GUI(self):
self.width_lbl = Label(self.frame1, text = "width:")
self.width_lbl.grid(row = 1 , column = 1)
self.width_txt = Entry(self.frame1)
self.width_txt.grid(row = 1, column = 2)
self.getdimensions_btn = Button(self.frame1, text = "enter dimensions",command = lambda:self.createmaze())
self.getdimensions_btn.grid(row = 1 , column = 3)
self.height_lbl = Label(self.frame1, text = "height:")
self.height_lbl.grid(row = 1 , column = 4)
self.height_txt = Entry(self.frame1)
self.height_txt.grid(row = 1, column = 5)
def createmaze(self):
width = int(self.width_txt.get())
height = int(self.height_txt.get())
for widthcount in range (width):
for heightcount in range(height):
self.maze_btn = Button(self.frame2, text = "",width = 4, height = 2)
self.maze_btn.grid(row = heightcount , column = widthcount)
self.maze_btn.bind("<Button-1>", self.disablebtn)
def disablebtn(self,event):
grid_info = event.widget.grid_info()
col = grid_info["column"]
col = int(col)
row = grid_info["row"]
row = int(row)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()
i'm trying to make this simple gui using grid layout where i have in one row a label an entry and a button, but for some reason the first button always takes the rowspan equal to the number of rows in previous column, even if i try to force it to have rowspan 1 it has no effect which makes me really confused.
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.grid()
#LABELS
self.l1 = tk.Label(self, text = "Source")
self.l1.grid(column = 0, row = 0, sticky = "E")
self.l2 = tk.Label(self, text = "Text files destination")
self.l2.grid(column = 0, row = 1, sticky = "E")
self.l3 = tk.Label(self, text = "Image files destination")
self.l3.grid(column = 0, row = 2, sticky = "E")
#ENTRIES
self.e1 = tk.Entry(self)
self.e1.grid(column = 1, row = 0)
self.e2 = tk.Entry(self)
self.e2.grid(column = 1, row = 1)
self.e3 = tk.Entry(self)
self.e3.grid(column = 1, row = 2)
#BUTTONS
self.b3 = tk.Button(text = "Select dir", command = self.cb2)
self.b3.grid(column = 2, row = 0)
self.b4 = tk.Button(text = "Select dir", command = self.cb2)
self.b4.grid(column = 2, row = 1)
self.b5 = tk.Button(text = "Select dir", command = self.cb2)
self.b5.grid(column = 2, row = 2)
if __name__ == "__main__":
root = tk.Tk()
app = MainApplication(root)
root.mainloop()
output:
http://i.imgur.com/AdWkHwi.png
You don't specify a parent for the buttons, so their parent is the root window. The labels and entries, on the other hand, have their parent attribute set to the frame. What happens is that in the root, the frame is in row zero, and the first button is in row zero, and the height of the row is determined by the height of the frame.
The solution is to make the parent of the buttons be the frame.
self.b3 = tk.Button(self, ...)
self.b4 = tk.Button(self, ...)
self.b5 = tk.Button(self, ...)