Like the title says, I want to intersect a progress bar in Tkinter at some variable position. See the image for what I want to achieve, those red vertical lines that I edited into the image.
The idea is to put text like "||" inside the bar and color it differently so it should look like what I want to achieve. I have seen a couple of examples with text being put into the progress bar, but it was always right in the middle of the bar which doesn't work for me.
Here is the code that generates progress bars.
import ttk
from Tkinter import *
import random
master = Tk()
stl = ttk.Style()
stl.theme_use("winnative")
stl.configure("colour.Horizontal.TProgressbar", background="lime green")
for i in range(0,4):
prgb = ttk.Progressbar(master, orient = "horizontal", length = 150, mode = "determinate", style = "colour.Horizontal.TProgressbar")
prgb.grid(row=i, column=0, pady=10)
prgb["maximum"] = 1.0
x = random.random()
prgb["value"] = x
master.mainloop()
The ProgressBar widget doesn't support this. However you could create a small colored Frame and use place to put it on top of the progress bar.
Example:
for i in range(0,4):
prgb = ttk.Progressbar(...)
...
x = random.random()
...
marker = Frame(prgb, width=4, background="red")
position = random.uniform(0,x)
marker.place(relx=position, rely=.5, anchor="w", relheight=.5)
I don't have access to a windows machine, but this is what it looks like on my mac:
Related
I want the color of neighbouring buttons to change when I click a button. I am making a GUI in tkinter for a 19x19 boardgame. Imagine something like mindsweeper, so the entire board consists of Buttons. I am using python 3.7
Here is my code for a simple 1x2 playing field.
import tkinter as tk
def do_something(p):
p.configure(bg = 'blue')
def personal_do_something(p):
p.configure(bg = 'blue')
p1.configure(bg = 'blue')
window = tk.Tk()
frame = tk.Frame(master = window)
frame.pack()
p1 = tk.Button(master = frame, width = 10, height = 5, bg = 'orange', command = lambda:do_something(p1))
p2 = tk.Button(master = frame, width = 10, height = 5, bg = 'khaki', command = lambda:personal_do_something(p2))
p1.pack(side=tk.LEFT)
p2.pack(side=tk.LEFT)
window.mainloop()
starting situation:
click p1:
click p2:
When p1 is clicked, only p1 turns blue, but not its neighbour p2. when p2 is clicked both p1 and p2 turn blue. This however only works because p2 has a personal_do_something() function. In this function I explicitly tell p1 to turn blue. This might be a viable method for a small 1x2 board, but I can't write personal functions for every button when there are 19x19 buttons. Does anyone have any clue how I could write 1 general function that always turns the direct neighbours blue? I assume I would have to add some kind of attribute to a button, for example a coordinate, and then search all the buttons that match neighbouring coordinates or something like that. But I have no clue how.
Thanks in advance :)
You can store the references of those buttons in a 2D list and pass the row and col of the clicked button to do_something() function. Then you can update the background color of those buttons based on passed row and col.
Below is an example based on your code:
import tkinter as tk
def do_something(row, col):
buttons[row][col].config(bg="blue")
# change direct connected buttons (left, right, up, down)
for dir in (-1, +1):
if 0 <= row+dir < len(buttons):
buttons[row+dir][col].config(bg="blue")
if 0 <= col+dir < len(buttons[row]):
buttons[row][col+dir].config(bg="blue")
window = tk.Tk()
frame = tk.Frame(window)
frame.pack()
ROWS = 10
COLS = 10
buttons = [[None]*COLS for _ in range(ROWS)] # for storing references of buttons
for row in range(ROWS):
for col in range(COLS):
buttons[row][col] = tk.Button(frame, width=10, height=5, bg="orange", command=lambda r=row,c=col: do_something(r,c))
buttons[row][col].grid(row=row, column=col, sticky="nsew")
window.mainloop()
I have made most of this window already, and would prefer to not have to restart because of a hitch with a scrollbar not resizing properly. Problem being that the scrollbars appear way too small for the listboxes and I want them to span the whole height of each box respecitvely, but as of now they can only function if you spam the arrows as the actual scrolling bit can't move for lack of space. Any help would be appreciated, stuck on this for a while now. (Using python 3.8).
import tkinter as tk
from tkinter import *
setup = tk.Tk()
setup.title("Set Up Game")
setup.geometry("450x650")
setup.resizable(width=False, height=False)
select_Box = tk.Canvas(setup, width=450, height=496, bg="#cd3636")
select_Box.pack(padx=10)
listbox1 = Listbox(setup, width=33, height=30)
listbox1_win = select_Box.create_window(110,250, window=listbox1)
listbox2 = Listbox(setup, width=33, height=30)
listbox2_win = select_Box.create_window(320,250, window=listbox2)
scroll1 = Scrollbar(setup)
scroll1_win = select_Box.create_window(200,250, window=scroll1)
scroll2 = Scrollbar(setup)
scroll2_win = select_Box.create_window(410,250, window=scroll2)
listbox1.config(yscrollcommand = scroll1.set, selectmode=SINGLE)
scroll1.config(command = listbox1.yview)
listbox2.config(yscrollcommand = scroll2.set, selectmode=SINGLE)
scroll2.config(command = listbox2.yview)
nameArray = ["Bulbasaur", "Ivysaur", "Venasaur", "Charmander", "Charmelion", "Charazard", "Squirtle", "Wartortle", "Blastoise", "Lucario", "Garchomp", "Gengar", "Snorlax", "Reuniclus", "Joel","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder","placeholder"]
for item in nameArray:
listbox1.insert(END, item)
setup.mainloop()
If you want to use Canvas.create_window to place all of your widgets, all you have to do is define the height of your scrollbar (you may need to play around with the numbers a little to get it to the right size).
So the edited snippet from your code will be:
scroll1 = Scrollbar(setup)
scroll1_win = select_Box.create_window(200,
250,
height=480, # this is all you're missing!
window=scroll1)
I am trying to create a harmless prank joke on my friends, and I want the background of a python tkinter window(not canvas) to change to a random colour every second, then, after ten rounds, it will destroy itself. The problem is that when root.config(background=random_colour)is called, it will not change it's background colour. The entire code is below:
from tkinter import *
import pyglet
import time
import random
root = Tk()
text = Label( padx = 1000, pady = 999, text = 'VIRUS!' )
text.pack()
text.config(font=('Courier', 44))
root.attributes("-fullscreen", True)
root.update()
I'm cutting this bit out because it's just a list of all the named colours in python(It's called COLOURS).
for x in range(0, 9):
colours_length = len(COLOURS)
number = random.randint(0, colours_length)
random_colour = COLOURS[number]
root.config(background=random_colour)
time.sleep(1)
root.update()
root.destroy()
I've took acw1668's advice from the comments section, and it works now. Turns out that the label was covering the entire root window, and that was why it wasn't working.
I am using the ttk.Progressbar in my app. I have scoured the net for an answer but no avail.
I have the following code which is working well. But I want to change the thickness of the bar.
progressbar = ttk.Progressbar(myGui, orient=HORIZONTAL,
length=400, mode="determinate",
variable=value_progress,
)
progressbar.pack()
I want the length to still be 400, but from the top of the bar to the bottom, I wish to decrease that so its half or less then half. (I want my bar on a diet, so to say)
But I am beating my head against the wall to figure out a solution.
Andy ideas? Thanks in advance.
The ttk progress bar appears to lack the width option in Python.
Using a work around (here) for an issue with a Tkinter Button. From this I have been able to create a working solution.
The key to solving the issue was to add the progress bar to a window inside the canvas. Using a window inside the canvas doesn't cause the canvas to resize when the widget is added which means we can control the width of the progress bar.
I have created some working example code:
from ttk import Progressbar
import Tkinter
class Example(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
value_progress =50
self.parent.title("Progressbar Thingymawhatsit")
self.config(bg = '#F0F0F0')
self.pack(fill = Tkinter.BOTH, expand = 1)
#create canvas
canvas = Tkinter.Canvas(self, relief = Tkinter.FLAT, background = "#D2D2D2",
width = 400, height = 5)
progressbar = Progressbar(canvas, orient=Tkinter.HORIZONTAL,
length=400, mode="indeterminate",
variable=value_progress,
)
# The first 2 create window argvs control where the progress bar is placed
canvas.create_window(1, 1, anchor=Tkinter.NW, window=progressbar)
canvas.grid()
def main():
root = Tkinter.Tk()
root.geometry('500x50+10+50')
app = Example(root)
app.mainloop()
if __name__ == '__main__':
main()
So to sum up the progress bar is the same size but you just cant see half of it!
If you must use the xpnative theme or themes like it, then you will likely not have the option to change the thickness the conventional way. However if you use the default theme, you can configure the thickness with a style. There are likely other themes that let you do this as well, and if you're going to be playing around a lot with the look and feel of your program, you may wish to use these instead.
from Tkinter import *
from ttk import *
def main():
root = Tk()
s = Style()
s.theme_use("default")
s.configure("TProgressbar", thickness=50)
pb = Progressbar(root, style="TProgressbar")
pb.pack()
root.mainloop()
main()
You can just use the ipady option of pack manager.
progressbar = ttk.Progressbar(myGui, orient=HORIZONTAL,
length=400, mode="determinate",
variable=value_progress,
)
progressbar.pack(ipady=10)
I'm adding strings to a listbox using the code below. When I run the code and the window opens, the longer strings get clipped as the window is not large enough (see screenshot). I have tried making the window resizeable and adding scroll bars but I was wondering if there was a way to automatically size it to fit the content.
master = tk.Tk()
listbox = tk.Listbox(master, selectmode=tk.SINGLE)
games = ["Garry's Mod", "Mount and Blade: Warband", "Tekkit"]
for game in sorted(games):
listbox.insert(tk.END, game)
button = tk.Button(master, text="Execute", command=execute)
listbox.pack()
button.pack()
tk.mainloop()
Resetting the listbox width worked for me. I used the Oblivion's answer and noticed that the width is always zero.
listbox = tk.Listbox(master, selectmode=tk.SINGLE)
listbox.config(width=0)
I also recommend to reset the root window geometry after reloading a content of the list. Otherwise if user manually extends a window the window would stop accommodate size of its content.
root.winfo_toplevel().wm_geometry("")
just give width and height 0 as below
listbox.config(width=0,height=0)
tkListAutoWidth.py shows one way to do it.
Edit:
So you might have something along the lines of,
import tkinter as tk
from tkinter import font
class NewListbox(tk.Listbox):
def autowidth(self, maxwidth=100)
autowidth(self, maxwidth)
def autowidth(list, maxwidth=100):
f = font.Font(font=list.cget("font"))
pixels = 0
for item in list.get(0, "end"):
pixels = max(pixels, f.measure(item))
# bump listbox size until all entries fit
pixels = pixels + 10
width = int(list.cget("width"))
for w in range(0, maxwidth+1, 5):
if list.winfo_reqwidth() >= pixels:
break
list.config(width=width+w)
if __name__ == "__main__":
master = tk.Tk()
listbox = NewListbox(master, selectmode=tk.SINGLE)
# ...
# ...
keys = serverDict.keys()
for key in sorted(keys):
listbox.insert("end", key)
listbox.pack()
button = tk.Button(master, text="Execute", command=execute)
button.pack()
listbox.autowidth()
master.mainloop()