Scrollbar in tree view in tkinter - python-3.x

I am trying to implement treeview in tkinter with scrollbar. I have got success in placing scrollbar but unable to place it in proper place. Following is full code:
from tkinter import*
from tkinter import ttk
import sqlite3
class Product:
db_name = 'Gateway_Log.db'
def __init__(self,wind):
self.wind=wind
self.wind.title('Device details')
self.tree = ttk.Treeview (height=25, columns=2)
self.tree.heading('#0',text = 'Name', anchor=W)
self.tree.heading(2, text='Price', anchor=W)
vsb = ttk.Scrollbar(wind, orient="vertical")
vsb.configure(command=self.tree.yview)
self.tree.configure(yscrollcommand=vsb.set)
self.tree.pack()
vsb.pack()
self.viewing_records()
def run_query(self, query, parameters =()):
with sqlite3.connect (self.db_name) as conn:
cursor = conn.cursor()
query_result=cursor.execute(query, parameters)
conn.commit()
return query_result
def viewing_records(self):
records = self.tree.get_children()
for element in records:
self.tree.delete(element)
query= 'SELECT * FROM Device_Status'
db_rows=self.run_query(query)
for row in db_rows:
self.tree.insert('',0, text = row[0], values = row[1])
if __name__ == '__main__':
wind=Tk()
application = Product(wind)
wind.mainloop()
Following output I am getting:
I want scrollbar after price field not at bottom side.

You need to indicate the side where you want to pack your widget and also which direction it should fill.
self.tree.pack(side="left")
vsb.pack(side="right",fill="y")

Related

In tkinter entry widget, failed to type in Indian language using sanskrit/hindi keyboard

from tkinter import *
from tkinter import ttk
lst = ['रामायणसारः', 'देवयाज्ञिकपद्धतिः', 'तर्कसङ्ग्रहः',]
def check_input(event):
value = event.widget.get()
if value == '':
data = lst
else:
data = []
for item in lst:
if value.lower() in item.lower():
data.append(item)
update(data)
def update(data):
# Clear the Combobox
menu.delete(0, END)
# Add values to the combobox
for value in data:
menu.insert(END, value)
def fillout(event):
combo_box.delete(0, END)
combo_box.insert(0, menu.get(menu.curselection()))
combo_box = Entry(root, width=10, font=("Times", 12))
combo_box.place(relx=0.20, rely=0.4, relwidth=0.45, relheight=0.1)
combo_box.bind('<KeyRelease>', check_input)
menu = Listbox(root)
menu.place(relx=0.20, rely=0.5, relwidth=0.45, relheight=0.1)
menu.bind("<<ListboxSelect>>", fillout)
update(lst)
while typing Indian language(Sanskrit/Hindi) text in entry box using sanskrit/hindi keyboard, it shows question mark, please help to rectify the issue.
ref
I have also tried encoding('utf-8') with entry widget, but it doesn't worked.

Hovertip/Tooltip for each item in Python ttk combobox

This is about ttk combobox.
I need to show help-info via Tooltip for each item (text) in ttk.combobox.
The minimum example is following:
import tkinter as tk
from tkinter import ttk
from idlelib.tooltip import Hovertip
names =["One", "Two", "Three"]
root = tk.Tk()
root.title("Combo Test GUI")
Frame1 = ttk.Frame(root, padding="3 3 12 12")
Frame1.grid(column= 0, row = 0)
label_1 = ttk.Label(Frame1, text="Select Item:", anchor=tk.W)
label_1.grid(column= 0, row = 1)
item1 = ttk.Combobox(Frame1, state="readonly", values=names, width=35)
item1.grid(column= 0, row = 2)
m1 = Hovertip(item1, "One test")
m2 = Hovertip(label_1, "Another test")
root.mainloop()
The problem: I want to bind the Hovertip to the text in the combo list, i.e. "One", "Two", "Three".
When the user hovers mouse over "One", the description "This is option One", should be shown in the Hovertip/Tooltip; and same for the other items "Two" and "Three" also.
I have searched everywhere, on Stackoverflow, in the reference docs, other websites, but it seems that Hovertip/Tooltip can only be used with widget, and not with simple text in the combobox.
Is there any way at all to make it possible?
The idea is to make a class similar to Hovertip but that works with listbox items instead of widgets. The current item is stored in self._current_item and when the mouse moves in the listbox, the displaying of the tooltip is rescheduled if the item changes. The text for each item is stored in a dictionary self.tips = {item index: text, ...}.
The main issue is that the Listbox displaying the Combobox's choices is not directly accessible with python. So I had to use some Tcl commands to do it:
proc callback {y} {
event generate .!combobox <<OnMotion>> -y $y
}
set popdown [ttk::combobox::PopdownWindow .!combobox]
bind $popdown.f.l <Motion> {callback %y}
The above code generates a virtual event <<OnMotion>> in the combobox when the mouse moves (where .!combobox is the name of the Combobox widget and y is the mouse relative y coordinate in the widget).
Then I bind the _on_motion() method of the combobox to this <<OnMotion>> event to check if the current item has changed. To get the current item I use the Listbox method nearest(y) but from Tcl.
I also modified the get_position() method to display the tooltip just below the current item and showcontents() to display the text corresponding to the item.
Here is the full code:
import tkinter as tk
from tkinter import ttk
from idlelib.tooltip import OnHoverTooltipBase
class ComboboxTip(OnHoverTooltipBase):
def __init__(self, combobox_widget, hover_delay=1000):
super(ComboboxTip, self).__init__(combobox_widget, hover_delay=hover_delay)
self.tips = {}
self._current_item = 0
combobox_widget.tk.eval("""
proc callback {y} {
event generate %(cb)s <<OnMotion>> -y $y
}
set popdown [ttk::combobox::PopdownWindow %(cb)s]
bind $popdown.f.l <Motion> {callback %%y}
""" % ({"cb": combobox_widget}))
self._id4 = combobox_widget.bind("<<OnMotion>>", self._on_motion)
def _on_motion(self, event):
current_item = int(self.anchor_widget.tk.eval("$popdown.f.l nearest %i" % event.y))
if current_item != self._current_item:
self._current_item = current_item
self.hidetip()
if current_item in self.tips:
self.schedule()
else:
self.unschedule()
def __del__(self):
try:
self.anchor_widget.unbind("<<OnMotion>>", self._id4)
except tk.TclError:
pass
super(ComboboxTip, self).__del__()
def add_tooltip(self, index, text):
self.tips[index] = text
def get_position(self):
"""choose a screen position for the tooltip"""
try:
h = self.anchor_widget.winfo_height()
bbox = self.anchor_widget._getints(self.anchor_widget.tk.eval("$popdown.f.l bbox %i" % self._current_item))
return bbox[0] + bbox[2], bbox[1] + bbox[-1] + h
except Exception:
return 20, self.anchor_widget.winfo_height() + 1
def showcontents(self):
label = tk.Label(self.tipwindow, text=self.tips[self._current_item], justify=tk.LEFT,
background="#ffffe0", relief=tk.SOLID, borderwidth=1)
label.pack()
names = ["One", "Two", "Three"]
root = tk.Tk()
cb = ttk.Combobox(root, values=names)
cb.pack()
t = ComboboxTip(cb)
t.add_tooltip(0, "This is One")
t.add_tooltip(1, "This is Two")
t.add_tooltip(2, "This is Three")
root.mainloop()

Tkcalendar DateEntry - Allow Widget to Return No Selection as Blank

I have created a GUI where the user can select a date from a drop down using the tkcalendar DateEntry widget. I would like to allow the user the option of not selecting a date and leaving this widget blank. However, even if no date is selected the widget returns the current date.
Is there a way to configure the DateEntry to allow for no selection rather than defaulting to the current date if the user does not select a date?
Below is a subset of my code:
import pandas as pd
from tkinter import *
from tkinter.ttk import *
import tkinter as tk
from tkcalendar import DateEntry
class Window(Frame):
def __init__(self, master):
Frame.__init__(self,master)
master.title('Solar Master Project Tracking')
# create canvas for scrollable window
canvas = Canvas(root)
canvas.grid(row=1,column=0, columnspan=2)
# create vertical scrollbar and connect it to the canvas
scrollBar = tk.Scrollbar(root, orient='vertical', command = canvas.yview)
scrollBar.grid(row=1, column=2, sticky = 'ns')
canvas.configure(yscrollcommand=scrollBar.set)
def update_scroll_region(event):
canvas.configure(scrollregion=canvas.bbox("all"))
def _on_mousewheel(event):
canvas.yview_scroll(int(-1*(event.delta/120)), "units")
# create a frame for the widgets in the scrollable canvas
scroll_frame = Frame(canvas)
scroll_frame.bind("<Configure>", update_scroll_region)
canvas.create_window(0,0, anchor='nw', window = scroll_frame)
canvas.bind_all("<MouseWheel>", _on_mousewheel)
# Proposal Date
self.L18 = Label(scroll_frame, text="Proposal Date:",font=('TKDefaultFont', 8, 'bold'))
self.L18.grid(row=21, column=0, sticky=W)
self.prop_date_selection = DateEntry(scroll_frame, width = 25, background = 'LightCyan3',
foreground ='white',borderwidth=2)
self.prop_date_selection.grid(row=21, column=1,sticky=E)
self.prop_date_selection.delete(0,"end")
# SUBMIT INFORMATION
self.button = tk.Button(root, text="Insert / Update Project",font=('TKDefaultFont', 10, 'bold'),
relief=RAISED, command = self.store_user_inputs, bg = "gray80")
self.button.grid(row=25, column = 0, columnspan=8, sticky = 'EW')
# STORE USER INPUT
def store_user_inputs(self):
prop_date_selection = self.prop_date_selection.get_date()
global params
params = [prop_date_selection]
root.destroy()
if __name__ == "__main__":
root = Tk()
Window(root)
root.mainloop()
You can create a class inheriting from tkcalendar.DateEntry and modify the get_date() method to return None when the DateEntry is empty:
import tkcalendar
class DateEntry(tkcalendar.DateEntry):
def get_date(self):
if not self.get():
return None
self._validate_date()
return self.parse_date(self.get())
For those who find this post.
Modifying get_date() didn't change anything in my case. But the following did:
class MyDateEntry(tkcalendar.DateEntry):
def _validate_date(self):
if not self.get():
return True # IMPORTANT!!! Validation must return True/False otherwise it is turned off by tkinter engine
return super()._validate_date()

Populate Treeview with info from sql?

I would like to ask for some advice on the code I have below:
from tkinter import *
from tkinter import ttk
import sqlite3
root = Tk()
root.geometry("500x500")
root.title("Inventory Balance")
def db():
global conn, mycursor
conn = sqlite3.connect('MyStock.sql3')
mycursor = conn.cursor()
def data():`
tree.delete(*tree.get_children())
mycursor.execute("SELECT * FROM ItemCode")
for row in myscursor:
tree.insert('', 'end', values=row[1:6])
conn.close()
frame = Frame(root)
frame.pack()
tree = ttk.Treeview(frame, columns = (1,2,3,4,5), height = 20, show = "headings")
tree.pack(side = 'top')
tree.heading(1, text="ItemCode")
tree.heading(2, text="Description")
tree.heading(3, text="Category")
tree.heading(4, text="Unit")
tree.heading(5, text="Quantity")
tree.column(1, width = 100)
tree.column(2, width = 100)
tree.column(3, width = 100)
tree.column(4, width = 100)
tree.column(5, width = 100)
# Inserting Scrollbar
scroll = ttk.Scrollbar(frame, orient="vertical", command=tree.yview)
scroll.pack(side = 'right', fill = 'y')
tree.configure(yscrollcommand=scroll.set)
root.mainloop()
I will later have to use this as a main screen, add buttons and have a constantly updating treeview showing as stock is used and then updated via another python tkinter script.
My main issue is that it reads the correct column (ItemCode, Description, Category, Unit, Quantity) but the information contained in the database does not display in the treeview.
Please help and do not hesitate to ask for any more information where required.
I edited the script as recommended and still end up with this:
enter image description here
Thank you again
There are two issues in your code:
using info when inserting record into treeview. row should be used
treeview.insert(...) expects two positional arguments: parent and index
So change:
info = mycursor.fetchall()
for row in info:
tree.insert(values=(info[1], info[2], info[3], info[4], info[5]))
to:
for row in mycursor:
tree.insert('', 'end', values=row[1:6])

Horizontal scroll bar not scrolling tkinter

Having trouble with this horizontal scroll bar... I've pieced this much together but could be completely wrong. The scroll bar is there where I want it to be it's just unusable and wont scroll anywhere.
There are about 83 columns and I can only see 15 of them.
import databasefile
import sqlite3
from tkinter import *
from tkinter.ttk import *
conn = sqlite3.connect("test_db.db")
cursor = conn.cursor()
returns = cursor.execute("SELECT * FROM Order_Number ORDER BY id DESC")
variables = [1,2,3,4,5,6,7,8,9,0,11,12,13,14,15,16,17,18,19,20]
class App(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.CreateUI()
self.grid(sticky = (N,S,W,E))
parent.grid_rowconfigure(1, weight = 1)
parent.grid_columnconfigure(1, weight = 1)
parent.wm_title("Database")
parent.maxsize(width=1200,height=600)
parent.resizable(width=0,height=0)
def CreateUI(self):
tv = Treeview(self)
tv['columns'] = variables
# Scroll Bar section
vsb = Scrollbar(root,orient="horizontal",command=tv.xview)
tv.configure(xscrollcommand=vsb.set)
vsb.place(x=0,y=210,height=20, width=1200)
tv.column("#0", anchor="w",width=25)
for item in variables:
tv.heading(str(item),text=str(item))
tv.column(str(item),anchor='center',width=75)
tv.grid(sticky = (N,S,W,E))
self.grid_rowconfigure(index=1, weight = 1)
self.grid_columnconfigure(index=1, weight = 1)
for row in returns:
tv.insert('','end',values=(row))
root = Tk()
App(root)
root.mainloop()

Resources