How to get a horizontal scrollbar in Tkinter? - python-3.x

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')

Related

Paned Window Resizing Issues

I've been trying out panedWindows for my app layout, but I'm having issues when the window resizes. This is the layout I've started out with:
The panes drag as I want them too, but I want to specify what panes expand to fill the root window, and which ones stay a specific width. For example, when I drag the window to the right or left, the pane on the expanding size extends to fill the extra space. I want only the centre pane to expand, and the right and left only when the sash is dragged:
like this:
When the panes were managed with the pack geometry manager, I could tell the edge panes to stay a specific width, and tell the centre pane to expand. How can I achieve a similar layout with paned windows?
Heres a minimal working example:
import tkinter
root = tkinter.Tk()
root.geometry("480x200+200+200")
root.title("Paned Window Example")
main = tkinter.PanedWindow()
main.pack(expand = 1, fill = "both")
pane1 = tkinter.Frame(width = 90, bg = "red")
pane2 = tkinter.Frame(width = 310, bg = "blue")
pane3 = tkinter.Frame(width = 90, bg = "red")
for pane in pane1, pane2, pane3 : main.add(pane)
root.mainloop()
You can use the stretch option when adding the panes to the PanedWindow. It takes the following values: 'always', 'first', 'last', 'middle', and 'never'.
You can get a more complete description in the tcl/tk documentation.
In your case, use 'never' for the side panes and 'always' for the middle one:
import tkinter
root = tkinter.Tk()
root.geometry("480x200+200+200")
root.title("Paned Window Example")
main = tkinter.PanedWindow()
main.pack(expand=True, fill="both")
pane1 = tkinter.Frame(width=90, bg="red")
pane2 = tkinter.Frame(width=310, bg="blue")
pane3 = tkinter.Frame(width=90, bg="red")
main.add(pane1, stretch='never')
main.add(pane2, stretch='always')
main.add(pane3, stretch='never')
root.mainloop()
Note that the above solution works only for tkinter.PanedWindow and not for ttk version of the widget. The .add() method of ttk.PanedWindow accepts only one option: weight. But we can achieve the same result by setting the side panes' weight to 0 and the middle pane's to 1:
import tkinter
from tkinter import ttk
root = tkinter.Tk()
root.geometry("480x200+200+200")
root.title("Paned Window Example")
main = ttk.PanedWindow(orient='horizontal')
main.pack(expand=True, fill="both")
pane1 = tkinter.Frame(width=90, bg="red")
pane2 = tkinter.Frame(width=310, bg="blue")
pane3 = tkinter.Frame(width=90, bg="red")
main.add(pane1, weight=0)
main.add(pane2, weight=1)
main.add(pane3, weight=0)
root.mainloop()

I want to display image dynamically in Tkinter using Pillow

I want to be able to display photos dynamically in Tkinter I have one button that will find the paths to the photos I want to display and as I add photos I want them to be displayed at the top of the canvas
I have already tried going through a for loop of the array after I upload the photos but that doesn't seem to do what I want, and now I am trying to iterate with a while loop but that doesn't work. I am kind of at a loss now. Below is my code
import tkinter as tk
from tkinter import filedialog as tkfd
from PIL import ImageTk, Image
import time
photo_name_list = []
def find_photos():
photo = tkfd.askopenfile()
photo_name_list.append(photo.name)
window = tk.Tk()
#creates the canvas
canvas = tk.Canvas(window, width = WINDOW_WIDTH,
height = WINDOW_HEIGHT, bg="green")
canvas.pack()
b1 = tk.Button(canvas, text="Click me to add 5 photos of yourself",
height = 5, width = 30, command = find_photos)
canvas.create_window(WINDOW_WIDTH//3, WINDOW_HEIGHT//3, window = b1)
while True:
if len(photo_name_list) > 0:
for image in photo_name_list:
img = Image.open(image)
tkimage = ImageTk.PhotoImage(img)
tk.Label(window, image=tkimage).pack()
canvas.update()
time.sleep(1/60)
window.mainloop()
So as you can see in the code I have one button that does that takes the path to an image as a string and appends it to the list. I want to display photos as they are appended.
This should work
import tkinter as tk
from tkinter import filedialog as tkfd
from PIL import ImageTk, Image
import time
WINDOW_WIDTH = 500
WINDOW_HEIGHT = 500
phat_list = []
images_reference_list = []
def find_photos():
photo = tkfd.askopenfile()
file_path = photo.name
img = Image.open(file_path)
photo_image = ImageTk.PhotoImage(img)
tk.Label(window, image=photo_image).pack(side=tk.TOP)
images_reference_list.append(photo_image)
phat_list.append(file_path)
window = tk.Tk()
#creates the canvas
canvas = tk.Canvas(window, width = WINDOW_WIDTH,
height = WINDOW_HEIGHT, bg="green")
canvas.pack(side=tk.BOTTOM)
b1 = tk.Button(canvas, text="Click me to add 5 photos of yourself",
height = 5, width = 30, command = find_photos)
canvas.create_window(WINDOW_WIDTH//3, WINDOW_HEIGHT//3, window = b1)
window.mainloop()
I've added the code lines that display the photo inside the function find_photos().
The while statement was causing some troubles i assume, you have always to check if the while will ever end for have a working code
and if you want to display an image you have always to keep a solid reference of it , the best way is to add it into a list

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()

Removing background from a label in Tkinter

from tkinter import *
from tkinter import messagebox
import tkinter
import hashlib
from PIL import Image, ImageTk
from win32api import GetSystemMetrics
#===========================================================================================
#functions to center windows
def center_window_x(width):
x_coordinate = (GetSystemMetrics(0)/2) - (width/2)
return x_coordinate
def center_window_y(height):
y_coordinate = (GetSystemMetrics(1)/2) - (height/2)
return y_coordinate
#===========================================================================================
#function to create setup page
def first_time_setup(width, height):
setup_window = Tk()
#===========================================================================================
#remove window border and position in center
setup_window.overrideredirect(1)
setup_frame = Frame(setup_window)
setup_frame.pack_propagate(False)
setup_window.geometry('%dx%d+%d+%d' % (width, height, center_window_x(width), center_window_y(height)))
#===========================================================================================
#background image for setup window
canvas = Canvas(setup_window, width=width, height=height)
canvas.grid(columnspan=2)
image = Image.open("setup_background.jpg")
canvas.image = ImageTk.PhotoImage(image)
canvas.create_image(0, 0, image=canvas.image, anchor="nw")
#===================================================================================================
#add username label
start_title = Label(setup_window, text="Username")
start_title.place(x=430,y=225)
#===================================================================================================
#add admin user entry box
admin_user_ent = Entry(setup_window)
admin_user_ent.place(x=500,y=225)
first_time_setup(650, 300)
Is there a way to remove the white background behind the username label? I know how to change the colour of it, but how do I remove it all together.
Is there a way to remove the white background behind the username label? I know how to change the colour of it, but how do I remove it all together.
sorry for posting twice, apparently there wasn't enough text and too much code.
It sounds like you are asking how to make your Label have a transparent background. From my understanding at the moment tkinter does not have this feature for widgets like labels and buttons. However it is still possible to create your own see-through label with Canvas
Here is an example of using Canvas to achieve something similar to what you are looking to do.
import tkinter as tk
root = tk.Tk()
mycanvas = tk.Canvas(root, width = 200, height = 25)
mycanvas.create_rectangle(0, 0, 100, 40, fill = "green")
mycanvas.pack(side = "top", fill = "both", expand = True)
text_canvas = mycanvas.create_text(10, 10, anchor = "nw")
mycanvas.itemconfig(text_canvas, text="Look no background! Thats new!")
root.mainloop()

Generate 10 balls in tkinter canvas

Ok guys.
I am trying to generate 10 balls of random color in Tkinter canvas when I click the generate button.
Program works, and random color choice works for the ball, but I only get one ball generated at a time.
Every time I click the button it randomly moves the ball around, but all I want is 10 balls in 10 random positions at a time. I am using Python 3.4 on a Linux box.
This is a code I've got:
from tkinter import *
import random # to generate random balls
colors = ["red", "blue", "purple", "green", "violet", "black"]
class RandomBalls:
"""
Boilerplate code for window in Tkinter
window = Tk()
window.title("Random title")
window.mainloop()
"""
def __init__(self):
"""
Initialize the window and add two frames, one with button, and another one with
canvas
:return:
"""
window = Tk()
window.title("Random balls")
# A canvas frame
frame1 = Frame(window)
frame1.pack()
self.canvas = Canvas(frame1, width = 200, height = 300, bg = "white")
self.canvas.pack()
# A button frame
frame2 = Frame(window)
frame2.pack()
displayBtn = Button(frame2, text = "Display", command = self.display)
displayBtn.pack()
window.mainloop()
def display(self):
for i in range(0, 10):
self.canvas.delete("circle") # delete references to the old circle
self.x1 = random.randrange(150)
self.y1 = random.randrange(200)
self.x2 = self.x1 + 5
self.y2 = self.y1 + 5
self.coords = self.x1, self.y1, self.x2, self.y2
self.canvas.create_oval(self.coords, fill = random.choice(colors), tags = "circle")
self.canvas.update()
RandomBalls()
Every time through your loop you are deleting everything you created before, including what you created the previous iteration. Move the delete statement outside of the loop:
def display(self):
self.canvas.delete("circle")
for i in range(0, 10):
...

Resources