Can I use rbg instead of hex in tkinter? If so, how can I do it?
I am planning to use this feature to make sort of a gradient from one color to another and I plan to make a for loop to change it from 1 to 255 in a few seconds.
from tkinter import *
root = Tk()
root.configure(background="can i use rgb instead of hex here?")
root.mainloop()
No, tkinter does not support RGB, but you can write a small helper function to remedy this:
Maybe something like this, where the argument rgb must be a valid rgb code represented as a tuple of integers.
import tkinter as tk
def _from_rgb(rgb):
"""translates an rgb tuple of int to a tkinter friendly color code
"""
return "#%02x%02x%02x" % rgb
root = tk.Tk()
root.configure(bg=_from_rgb((0, 10, 255)))
root.mainloop()
If you find it more readable, you can also use fstrings to achieve the exact same result:
def _from_rgb(rgb):
"""translates an rgb tuple of int to a tkinter friendly color code
"""
r, g, b = rgb
return f'#{r:02x}{g:02x}{b:02x}'
Note that the colorsys module from the Python standard library can help translate from HSV, HLS, and YIQ color systems
def rgbtohex(r,g,b):
return f'#{r:02x}{g:02x}{b:02x}'
print(rgbtohex(r=255, g=255, b=255))
Hope this helps some of you
This will make a gradient.
from tkinter import *
root=Tk()
root.title("colors")
cv=Canvas(root, width=20, height=255)
cv.pack()
def _from_rgb(rgb):
"""translates an rgb tuple of int to a tkinter friendly color code
"""
return "#%02x%02x%02x" % rgb
for canvas in range(255):
cv.create_line(0,canvas, 20,canvas, fill=_from_rgb((canvas, canvas,
canvas)))
You can have fun with this.
You can try this to:
from tkinter import *
def dec2hex(r,g,b):
return f'#{r:02x}{g:02x}{b:02x}'
root=Tk()
cv=Canvas(highlightthickness=0)
cv.pack(expand=True, fill=BOTH)
for color in range(510):
cv.create_line(0,color, 3000,color, fill=dec2hex(0, round((510-color)/2), round(color/2)))
for color in range(510):
cv.create_line(0,(color+510), 3000,(color+510), fill=dec2hex(round(color/2), 0, round((510-color)/2)))
Sorry for not answering correctly, I didn't think it through properly. Now that I have seen your comment #Mike-SMT, I've improved it
from tkinter import *
import random
import time
window = Tk()
window.title("Random colours")
colours = ["black",
"cyan",
"magenta",
"red",
"blue",
"gray"
]
bgColour = window.configure(background = random.choice(colours))
window.update()
time.sleep(1)
bgColour1 = window.configure(background = random.choice(colours))
window.mainloop()
Have fun with this, you can get creative and do things like making this into a forever changing background colour, or making a sequence. There are so many different colours on Tkinter that you can use, so you can manually change each colour after every few seconds if you really want. Another thing I forgot to mention previously, you can't use a time.sleep() option as Mike said, but it will work if you use a ".update()" line of code, as shown above.
Related
I was wondering how do the geometry() function values in tkinter come to play with the height value of for example a scrolled text? How can I convert the units to work with each other?
For example: If I want to open a scrolled text box underneath my tkinter window with a click of a button, I know I need then to change my window's geometry() (height) value, but I don't know by how much exactly.
(In the following example I randomly added 100 to the geometry value in the function open. But I want a more specific value that translates to the 7 of the height value of the scrolled text)
from tkinter import *
from tkinter import scrolledtext
def open():
root.geometry(f'{frame_width}x{frame_height+100}')
st.pack(side="bottom")
frame_width = 900
frame_height = 500
root = Tk()
root.geometry(f'{frame_width}x{frame_height}')
root.configure(bg='white')
root.resizable(False, False)
open_st = Button(root, text="OPEN SCROLLED TEXT", command= open)
open_st.pack()
st = scrolledtext.ScrolledText(root, width=frame_width, height=7)
root.mainloop()
Widgets that contains text usually provide their width and height in character space. This means tkinter takes the average width and height of your font and multiplies it with the given number in width and height.
There are mainly two ways to deal with that, either tk.Font.measure or metrics, if you want to convert characters to pixel or the much more comfortable way by just asking the widget for it's size via winfo. Happily your case fits for the latter.
The alternate code would looks like this:
def open_text():
st.pack(side="bottom")
width, window_height = root.winfo_width(), root.winfo_height()
requested_text_height = st.winfo_reqheight()
new_height = window_height + requested_text_height
root.geometry(f'{width}x{new_height}')
Please note that I have named your function differently. Cause you redefined open in the global namespace of your module and this could lead to unintended behavior. In addition I wonder why you want to do it like this and not just let the geometry managers do their job?
This problem drives me crazy as it looks trivial but i have already wasted many hours to find a solution but still no success. I need help.
Let's say the line is 'HelloHelloHelloHelloHello', the font is Georgia 17. How to find a correct value for the width to get the width of the text widget equal to the length of line? "The width of the widget in characters (not pixels!), measured according to the current font size." My findings show that people asking similar questions get answers about using font measure method, but it doesnt work...
import tkinter
import tkinter.font as tkFont
txt='HelloHelloHelloHelloHello'
root=tkinter.Tk()
t_Font = tkFont.Font(family='Georgia', size=17)
width=t_Font.measure(txt)
t=tkinter.Text(root,width=width,font=('Georgia',17))
t.insert(1.0,txt)
t.pack()
The result is ridiculous http://joxi.net/E2p1NJlT7NgjvA.jpg (with width=280). Empirical research shows that 20 is a correct value..but how to get it? Using len(txt) looks much better but i believe there should be a good solution. Can't understand what I am missing here...
If you want the Text widget having width in pixels around the width of the text, you can put the Text widget inside a frame and set the size (in pixels) of the frame to the desired value and then use .place() on the Text widget to fill the frame:
t_Font = tkFont.Font(family='Georgia', size=17)
width, height = t_Font.measure(txt), t_Font.metrics('linespace')
print(width, height)
lines = 20
# +4 to include the width of the border (default 1) and padding (default 1)
frame = tkinter.Frame(root, width=width+4, height=lines*height+4)
frame.pack()
# put text box inside the frame
t = tkinter.Text(frame, font=t_Font)
t.insert(1.0, txt)
t.place(relwidth=1, relheight=1) # fill the available space of the frame
I am using Tkinter and need to color the background of a label after it is drawn based on an input value.
import random
from tkinter import *
import tkinter.font as font
if __name__=='__main__':
listo=chose_num()
main_win=Tk()
main_win.title('Your Bingo Bord')
rows, cols = (15, 5)
arr = [[None]*cols]*rows
#Column O
can1=Canvas(main_win,width=100,height=70,bg='white')
lab1=Label(can1, text="O", width=10,fg = 'red')
lab1.pack()
main_win.mainloop()
Let's say I want to color the background of one of the labels. How can I do this without reconstructing the canvas, please?
How should I approach this, please?
Any help would be appreciated.
The Code:-
from tkinter import *
import sys
import time
import random
root = Tk()
canvas = Canvas(root,height=700,width=700,bg='pink')
canvas.pack()
canvas.create_rectangle(0,0,10,700,fill='blue')
canvas.create_rectangle(690,0,700,700,fill='blue')
canvas.create_rectangle(0,0,700,10,fill='blue')
canvas.create_rectangle(0,690,700,700,fill='blue')
canvas.create_arc(110,9,130,29,extent=359,fill='black',style=ARC)
canvas.create_rectangle(290,500,410,510,fill='red')
root.mainloop()
Everything appears fine with color, only the arc doesn't get filled up.
How can I color the arc?
According to the documentation, you cannot fill an arc except if its style is either PIESLICE or CHORD.
This actually makes sense: how would you fill a geometric object which is not closed?
You can simply remove the style attribute and it should work.
canvas.create_arc(110, 9, 130, 29, extent=359, fill='black')
I find it easier to use the outline = colour method while leaving the entry of style = 'arc' alone this will change the colour to what you want because of a tkinter querk that for small line widths you only ever see the outline. A more thorough way would be outline = colour, fill = colour this will be a complete uniform color no matter the thickness
I have a tkinter frame that I want to automatically resize on the Y axis but remain a constant width as I add label widgets to it.
To keep the X-size constant I am using grid_propogate(False) but that keeps the whole thing a constant size.
How can I set the frame to resize in this manner?
Thanks
Ok, figured it out
Made a larger frame that encompassed the space that my frame could fill if maxed out and used pack(fill=X) and pack_propagate(False) to make the inner frame conform to the X dimension of the outer frame while not changing it. I then could add lines to the innerframe as needed with it maintaining it's X size:
OuterFrame = Frame(root, height=500, width=400)
InnerFrame = Frame(OuterFrame, borderwidth=3, relief=RAISED)
InnerFrame.pack(side=TOP, fill=X)
# stuff that goes in the y-resizing InnerFrame
OuterFrame.pack_propogate(False)
OuterFrame.pack()
This seems like a very ugly solution to me, (hopefully someone will come along with something better):
import Tkinter as tk
root=tk.Tk()
f=tk.Frame(root,width=100,height=300)
f.grid_propagate(False)
f.grid(row=0,column=0)
def resize(evt):
f.update_idletasks()
height=f.winfo_reqheight()
f.grid_propagate(False)
if(evt.width!=100) or (evt.height!=height):
f.configure(width=100,height=height)
print "HERE", evt.width,height
f.bind('<Configure>',resize)
#Just some stupid (ugly) code to update the size of the widget at runtime.
def add_label():
f.grid_propagate(True)
lbl=tk.Label(f,text=' %d Hello!'%(add_label.row))
lbl.grid(column=0,row=add_label.row)
add_label.row+=1
add_label.row=0
b=tk.Button(root,text="Add label",command=add_label)
b.grid(row=1,column=0)
root.mainloop()