tkinter scrollbar attached to listbox in a grid - python-3.x

Been staring at this code for so long, I can't see what is wrong with it.
When I run it, I get the listbox and OK button as I expect, but the scrollbar appears in the middle
of the listbox widget and doesn't actually scroll.
import tkinter as tk
def confirm_selection():
selection = sensor_listbox.get(sensor_listbox.curselection())
print("Selected:", selection)
root = tk.Tk()
root.title("USGS Data To Download From Glovis Scenelist")
w = 730 # width for the Tk root
h = 500 # height for the Tk root
ws = root.winfo_screenwidth() # width of the screen
hs = root.winfo_screenheight() # height of the screen
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
#create listbox and scrollbar
sensor_listbox = tk.Listbox(root, height=3,width=20)
sensor_listbox.grid(row=0, column=2)#,columnspan=3)
sensor_scroll = tk.Scrollbar(root)
sensor_scroll.grid(row=0,column=2,sticky='ns')
sensor_scroll.configure(command=sensor_listbox.yview)
sensor_listbox.configure(yscrollcommand=sensor_scroll.set)
# Add items to the listbox
sensor_list = ["Sentinel-2", "Sentinel-1", "Landsat-8/9","Landsat-7","Landsat-4/5","ASTER (SWIR On)","ASTER (SWIR Off)"]
for item in sensor_list:
sensor_listbox.insert("end",item)
sensor_listbox.select_set(4)
button = tk.Button(root, text="OK", command=confirm_selection)
button.grid(row=3, column=2)#,columnspan=3)
root.mainloop()
I was expecting the listbox to have a scrollbar attached on the right side.

Change this:
sensor_scroll.grid(row=0,column=2,sticky='ns')
to:
sensor_scroll.grid(row=0,column=2,sticky='ne')

Related

TKinter Splashscreen not working for GUI based application for Python 3.6

I am trying to build a GUI based code, where there will be a splashcreen, a wait for 5 seconds and then the main GUI should show up. I am using Python 3.6. Here is my code:
from tkinter import Tk, PhotoImage, Canvas, Label
from time import sleep
root = Tk()
root.overrideredirect(True)
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
image_file = 'splash_fig.png'
splashImage = PhotoImage(file = image_file)
w = splashImage.width()
h = splashImage.height()
y = int((height - h) / 2)
x = int((width - w) / 2)
root.geometry('%dx%d+%d+%d' % (w,h,x,y))
canvas = Canvas(root,height = h, width = w, bg = "brown")
canvas.create_image(0,0,image = splashImage, anchor='nw')
canvas.pack()
root.after(5000, root.destroy)
root.mainloop()
root = Tk()
my_label = Label(root, text="Something something")
my_label.pack()
root.mainloop()
What is happening is that the splashscreen does not show up, but the second GUI does! Where is the exact problem here! My question is an extension to this question, where I have closely followed the solution proposed

Python 3: Positions of button and input text in a text box

I am new to python and learning to create a text box with two entries and one button.
I am able to set the position of my both entries, but I am not able to set the position of my button below them.
I tried to use:
b.place(anchor=S, bordermode=OUTSIDE, height=5, width=10)
but the button doesn't move at all. It stays at the lower right corner.
Following is my code:
from tkinter import *
root = Tk()
l1 = Label(root, text="Variable_1")
l1.pack( side = LEFT)
e1 = Entry(root, bd = 5)
e1.pack(side = LEFT)
l2 = Label(root, text="Variable_2")
l2.pack( side = LEFT)
e2 = Entry(root, bd = 5)
e2.pack(side = LEFT)
l = Label(root)
def callback():
x = e1.get()
y = e2.get()
print(x)
print(y)
b = Button(root, text="OK", command=callback)
for widget in (e1, e2, l, b):
widget.pack()
How can I place the button at the bottom-centre of the text box?
Also, any suggestions to change the positions of the entries?
Thanks!
The usual way to build complex layouts is to group associated widgets together with frames. In the example below I'm grouping the entrys in one frame and the button in another. This makes it easier to control the vertical positioning.
from tkinter import *
root = Tk()
top = Frame(root) # Create frame to hold entrys
top.pack() # Pack top frame
l1 = Label(top, text="Variable_1")
l1.pack(side=LEFT)
e1 = Entry(top, bd=5)
e1.pack(side=LEFT)
l2 = Label(top, text="Variable_2")
l2.pack(side=LEFT)
e2 = Entry(top, bd=5)
e2.pack(side=LEFT)
l = Label(root)
def callback():
x = e1.get()
y = e2.get()
print(x)
print(y)
bottom = Frame(root) # Create frame to hold button
bottom.pack() # Pack bottom frame
b = Button(bottom, text="OK", command=callback)
b.pack()
You can also use the grid() geometry manager. See The Tkinter Grid Geometry Manager

How to get a horizontal scrollbar in Tkinter?

I'm learning Tkinter at the moment. From my book, I get the following code for producing a simple vertical scrollbar:
from tkinter import * # Import tkinter
class ScrollText:
def __init__(self):
window = Tk() # Create a window
window.title("Scroll Text Demo") # Set title
frame1 = Frame(window)
frame1.pack()
scrollbar = Scrollbar(frame1)
scrollbar.pack(side = RIGHT, fill = Y)
text = Text(frame1, width = 40, height = 10, wrap = WORD,
yscrollcommand = scrollbar.set)
text.pack()
scrollbar.config(command = text.yview)
window.mainloop() # Create an event loop
ScrollText() # Create GUI
which produces the following nice output:
enter image description here
However, when I then try to change this code in the obvious way to get a horizontal scrollbar, it's producing a weird output. Here's the code I'm using
from tkinter import * # Import tkinter
class ScrollText:
def __init__(self):
window = Tk() # Create a window
window.title("Scroll Text Demo") # Set title
frame1 = Frame(window)
frame1.pack()
scrollbar = Scrollbar(frame1)
scrollbar.pack(side = BOTTOM, fill = X)
text = Text(frame1, width = 40, height = 10, wrap = WORD,
xscrollcommand = scrollbar.set)
text.pack()
scrollbar.config(command = text.xview)
window.mainloop() # Create an event loop
ScrollText() # Create GUI
and here's what I get when I run this:
enter image description here
You're assigning horizontal scrolling, xscrollcommand, to a vertical scrollbar. You need to modify Scrollbar's orient option to 'horizontal' which is by default 'vertical'.
Try replacing:
scrollbar = Scrollbar(frame1)
with:
scrollbar = Scrollbar(frame1, orient='horizontal')

How to attach my scrollbar to my listbox widget

here is a picture of what i want to be:
scrollbar
Actual code:
lb = Listbox(self.master, width=120, height=6)
scrollbar = Scrollbar(self.master, orient="vertical",command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=lb.yview)
lb.place(x=5,y=5)
Thanks!
You can create a new frame with listbox and scrollbar in it:
from tkinter import *
root = Tk()
root.geometry('500x300')
frame = Frame(root)
frame.place(x = 5, y = 5) # Position of where you would place your listbox
lb = Listbox(frame, width=70, height=6)
lb.pack(side = 'left',fill = 'y' )
scrollbar = Scrollbar(frame, orient="vertical",command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.config(yscrollcommand=scrollbar.set)
for i in range(10):
lb.insert(END, 'test'+str(i))
root.mainloop()
or since you're using place (which is not recommended), you can simply calculate the position of the scrollbar. grid would be the best layout manager in this case.
The problem is if you use only the 'place' positioning, the scrollbar doesn't appear.
The solution is to make two frames - one master frame with a widget scrollbar and
a second frame inside the master frame, where you can get the listbox. The frames can be positioned with place, the widget inside the frames with pack or grid.
Below is my source code, what works perfectly.
from tkinter import *
root = Tk()
root.geometry('500x300')
frame1 = Frame(root)
frame1.place(x = 10, y = 5,width=100,height=100) # Position of where you would place your listbox
frame1a=Frame(master=frame1)
frame1a.place(x=0,y=0,height=100,width=100)
lb = Listbox(frame1a, width=50, height=6)
lb.grid(row=0,column=0 )
scrollbar = Scrollbar(frame1, orient="vertical",command=lb.yview)
scrollbar.pack(side="right", fill="y")
lb.config(yscrollcommand=scrollbar.set)
for i in range(10):
lb.insert(END, 'test'+str(i))
root.mainloop()

Finding coordinates on a scrollable Tkinter canvas

I'm trying to make it so that when you right click, the row is highlighted blue and you can then edit or delete that entry. However, since adding a scrollbar, if the page is scrolled then the selection will be offset.
I have tried to suggested thing of finding the canvasx and canvasy and then using find_closest(0, however when i do that it always returns (1,) no matter what.
Canvasx and canvasy seem local to each label, not the canvas itself
from tkinter import *
def RightClick(event):
#Find widgets on the row that was right clicked
print(canvas.canvasy(event.y))
for widget in frame.winfo_children():
mouseClickY = event.y_root - root.winfo_y() - widget.winfo_height()
widgetTopY = widget.winfo_y()
widgetBottomY = widget.winfo_y() + widget.winfo_height()
if (widget.winfo_class() == "Label") and (mouseClickY > widgetTopY) and (mouseClickY < widgetBottomY):
#Highlight that row
if widget.cget("bg") != "#338fff":
widget.config(bg = "#338fff", fg="#FFFFFF")
#Deselect all rows
elif widget.winfo_class() == "Label":
widget.config(bg = "#FFFFFF", fg="#000000")
def onFrameConfigure(event):
canvas.configure(scrollregion=canvas.bbox("all"))
root = Tk()
root.bind("<Button-3>", RightClick)
canvas = Canvas(root, width = 1080, height=500)
frame = Frame(canvas)
scrollbar = Scrollbar(root, command=canvas.yview)
canvas.config(yscrollcommand=scrollbar.set)
canvas.grid(row=1,column=0,columnspan=5)
canvas.create_window((0,0), window=frame, anchor="nw",tags="frame")
scrollbar.grid(column=5,row=1,sticky="NS")
frame.bind("<Configure>", onFrameConfigure)
for countY in range(40):
for countX in range(6):
l = Label(frame, text=countX, width = 25, height = 1, bg="#FFFFFF")
l.grid(column=countX,row=countY+1)
Solved it, turns out
mouseClickY = event.y_root - root.winfo_y() - widget.winfo_height()
widgetTopY = widget.winfo_y()
widgetBottomY = widget.winfo_y() + widget.winfo_height()
should be
mouseClickY = event.y_root - root.winfo_y()
widgetTopY = widget.winfo_rooty()
widgetBottomY = widget.winfo_rooty() + widget.winfo_height()
OR
I should have used winfo_containing, which is a lot neater

Resources