Tkinter better backgrounds - python

I have managed to create this.
I am using an oval with a different shade to create this.
def Banner():
canvas.create_oval(-300, 1600, 4000, 200, fill="gray38", outline="gray38", width=4)
banner_label = Label (canvas, width=30, height=2, font=font3, text = "FITNESS FIRST", bg="gray30", fg = "white")
canvas_banner_label = canvas.create_window(500, 200, window=banner_label)
However i was wondering if theres anyway i could get the oval to almost take priority, and overlap the Label so that the oval is in front of it, allowing the pattern to be visible all the way through

The problem with using Label() on the canvas is the label itself has its own background and will always be at the same level as the text so you cannot overlap your canvas image behind the text. However canvas has a method called create_text that will draw the text directly on the canvas instead of using a label.
Here is an example using create_text for canvas.
In the create_text method the first 2 arguments are coordinates then all you need is the text font and fill is the color.
import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width=800, height=650, bg="darkgrey")
canvas.create_oval(-300, 1600, 4000, 200, fill="gray38", outline="gray38", width=4)
canvas.create_text(400,325, text="FITNESS FIRST", font=("Purisa", 60),fill="white")
canvas.pack()
root.mainloop()
Results:

Related

Python TKinter Set absolute Label size

I am looking to set the Label Widget width to an exact value - width=100 should be 100 pixels.
Is there a way to achieve this or should I be looking at using a different widget?
When using the TKinter Label, the width and height parameters refer to the text size - height=2 will set the label large enough for two lines of text, not 2 pixels as I would expect.
I believe this post might help with your issue if you absolutely need a solution to do sizes pixel-perfect on your widget.
There is however no easy way to do it straight on the widget itself.
Specify the dimensions of a Tkinter text box in pixels
You can assign a blank image to the label, then you can specify width option in pixels:
import tkinter as tk
root = tk.Tk()
blank = tk.PhotoImage()
tk.Label(root, image=blank, text="Hello", width=200, height=50, compound="c", bg="yellow", bd=0, padx=0).pack(padx=100, pady=10)
tk.Label(root, image=blank, text="World", width=200, height=30, compound="c", bg="cyan", bd=0, padx=0).pack(padx=100, pady=10)
root.mainloop()
Result:

How to get all the buttons to be automatically the same size depending on the largest one in tkinter using canvas?

How are you supposed to go around sizing all the buttons to be the same size regardless of the text you insert inside, they should all size according to the biggest one.
There is an answer to a similar question like mine already, but it is done using grid and I am using a canvas to place a background image in the window and to place the buttons.
Is it even worth the hassle to get your buttons to the same size according to text automatically, since my text will always be around the same...
I tried getting the size of the buttons using cget() but that returns 0. Where does it store its width then since it has to size itself somehow even if it does it according to text? Can access that in any way? I was thinking of using that value to adjust the value of other buttons somehow, but it turned out as a fail.
If you are wondering why am I making it into a class, idk either, wanted to try it.
I had it working by putting all the buttons in a frame and telling them to fill=x but using a frame destroys the point of using a canvas since the background can't be seen because the frame covers it. Is there a way to make the frame transparent in the canvas, that could also potentially solve my problem.
from tkinter import *
class ThreeButtonMenu():
def __init__(self, button1_text, button2_text, button3_text, image_height = 600, image_width = 500, bg_input = 'space_background.png'):
self.root = Tk()
HxW = str(image_height)+'x'+str(image_width)
self.root.geometry(HxW)
self.root.maxsize(image_height,image_width)
self.root.minsize(image_height,image_width)
self.root.title('Guess')
bg = PhotoImage(file=bg_input)
background_canvas = Canvas(self.root, width = 600, height=500)
background_canvas.pack(fill="both", expand=True)
background_canvas.create_image(0,0, image=bg, anchor='nw')
button1 = Button(self.root, text=button1_text, font = ('Lato',28))
button2 = Button(self.root, text=button2_text, font = ('Lato',28))
button3 = Button(self.root, text=button3_text, font = ('Lato',28), command = self.root.destroy)
button1_window = background_canvas.create_window(300,45, anchor=N, window=button1)
button2_window = background_canvas.create_window(300,160, anchor=N, window=button2)
button3_window = background_canvas.create_window(300,275, anchor=N, window=button3)
print(button1.cget('width'))
print(button2.cget('width'))
print(button3.cget('width'))
self.root.mainloop()
start_menu = ThreeButtonMenu('Start Game', 'Leaderboard', 'Quit')
Thank you for your answers.
You would typically do this when you use a geometry manager (pack, place, or grid).
For example, you need to call pack on each of the buttons. See example of pack below.
import tkinter as tk
root = tk.Tk()
for text in (
"Hello", "short", "All the buttons are not the same size",
"Options", "Test2", "ABC", "This button is so much larger"):
button = tk.Button(root, text=text)
button.pack(side="top", fill="x")
root.mainloop()

Tkinter fix size of Frame to not overlap Canvas border with scrollbar

I'm working on a GUI with tkinter and i have a problem.
When i add a scrollbar to my app, the frame on my canvas overlaps the outlines (see image)
Here is the code:
from tkinter import *
window = Tk()
window.geometry("400x225")
scrollbar1 = Scrollbar(window, orient=VERTICAL)
canvas1 = Canvas(window, bg="#003333", yscrollcommand=scrollbar1.set)
frame1 = Frame(canvas1, bg="#003333")
scrollbar1.config(command=canvas1.yview)
scrollbar1.pack(side=RIGHT, fill=Y)
canvas1.pack(fill=BOTH, expand=True)
canvas1.create_window((0, 0), window=frame1, anchor="nw")
for x in range(20):
string = "line " + str(x)
label1 = Label(frame1, fg="white", bg="#003333", text=string, font=("Calibri Bold", 14))
label1.pack(pady=5)
window.update()
canvas1.config(scrollregion=canvas1.bbox("all"))
window.mainloop()
I don't know if it's possible but i want the frame to fit within the canvas and keeping the outlines as well.
I hope you get my problem and can probably help me out! Thanks in advance.
The highlightthickness
Specifies a non-negative value indicating the width of the highlight rectangle to draw around the outside of the widget when it has the input focus.
So, this is not really the "border" that you want. It is a part of the drawing space within the canvas, when you use window_create to draw a window, the parent of that window is the canvas, which begins before the highlight and so the window slides over it.
A solution, as also suggested by #martineau would be to make this 0 by specifying highlightthickness=0 and as you suggested that you need the "border" around the whole thing, you can either create a container frame and specify the bd parameter, or just set the bd of the window window.config(bd=2).

How to dynamically resize window with Tkinter?

root= tk.Tk()
root.title('Quick Googling')
canvas1 = tk.Canvas(root, width = 400, height = 300)
canvas1.pack()
entry1 = tk.Entry (root)
canvas1.create_window(200, 140, window=entry1)
canvas1.config(background="#8FB1CC"
button1 = tk.Button(text='Search Google', bg = "blue")
canvas1.create_window(200, 180, window=button1)
I want the colour of my window and the entry and button to utilise all the space when the window's size is changed.
If you use a frame the geometry mangers of tkinter is doing the job for you see:
import tkinter as tk
root= tk.Tk()
root.title('Quick Googling')
myframe = tk.Frame(root)
myframe.pack(fill='both',expand=True)
entry1 = tk.Entry (myframe,background="#8FB1CC")
entry1.pack(fill='x')
button1 = tk.Button(myframe,text='Search Google', bg = "blue")
button1.pack(fill='both',expand=1)
root.mainloop()
Look on a small overview I wrote over the basics.
fill stretch the slave horizontally, vertically or both expand The
slaves should be expanded to consume extra space in their master.
So what the above code does is to create a frame in its natrual size, this means it shrinks itself to the minimum space that it needs to arrange the children.
After this we use for the first time the geometry manager pack and give the options fill, which tells the frame to stretch and using the optional argument expand to consume extra space. Together they resize your frame with the window, since there is nothing else in it.
After that we create an Entry and using once again the method pack to arrange it with this geometry manager. We are using again the optional argument fill and give the value 'x', which tells the geometry manager to stretch the slave/entry vertically.
So the entry streches vertically if the frame is expandes.
At least we create a Button and using the known keywords, to let it resize with the frame.

Static Text on Scrollable Canvas

I want to keep some text on a scrollable tkinter canvas static, or anchored. It should not move with the scrollbars.
How can I do this?
from tkinter import *
root=Tk()
frame=Frame(root,width=300,height=300)
frame.grid(row=0,column=0)
canvas=Canvas(frame,bg='#FFFFFF',width=300,height=300,scrollregion=(0,0,500,500))
hbar=Scrollbar(frame,orient=HORIZONTAL)
hbar.pack(side=BOTTOM,fill=X)
hbar.config(command=canvas.xview)
vbar=Scrollbar(frame,orient=VERTICAL)
vbar.pack(side=RIGHT,fill=Y)
vbar.config(command=canvas.yview)
canvas.config(width=300,height=300)
canvas.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set)
canvas.pack(side=LEFT,expand=True,fill=BOTH)
canvas.create_text(10, 10, text='Static Text # 1', anchor = NW, fill = 'red')
canvas.create_text(10, 100, text='Static Text # 2', anchor = NW, fill = 'red')
canvas.create_text(150, 10, text='Scrollable Text # 1', anchor = NW)
canvas.create_text(150, 100, text='Scrollable Text # 2', anchor = NW)
root.mainloop()
If you do not need the text box to be transparent, the easiest thing to do is to not put the text on the canvas but to place a Label over the canvas.
import tkinter as tk
root = tk.Tk()
c = tk.Canvas(root)
c.place(x=0, y=0)
r = c.create_rectangle(100, 100, 200, 200, outline='red',
fill='yellow', width=10)
ct = c.create_text(110, 150, text='canvas text', anchor='w')
lt = tk.Label(c, text='label text')
lt.place(x=110, y=110)
If you do want the transparency, then you must intercept move commands between the canvas and scrollbars so as to also move the 'static' items to the canvas coordinates that correspond to the original screen (window) coordinates. This is complicated by the fact that Scrollbar.set expects two fractions, so a canvas calls x/yscrollcommand with two fractions. Similarly, moving the scrollbar slider causes the scrollbar to call its command (canvas x/yview) with a fraction, which I suspect is the upper or left fraction. In the other hand, clicking the scrollbar buttons calls x/yview with a number and units.
I think what I would do is create a list of tuples of static item id, and the 4 canvas.bbox coordinates of the item. Next replace canvas.xscrollcommand, canvas.yscrollcommand, hbar.set, and vbar.set with wrappers named, for instance, xscroll, yscroll, xset, and yset. In each wrapper, call the wrapped function. Then call a new static_set function that uses canvas.canvasx/y(screenx/y, gridspacing=1) to convert screen coords to the new canvas coordinates and canvas.coords(item id, *canvas coords) to place the item.
I leave you to work out the details. If you are not familiar with the NMT Tkinter reference, learn to use it. This is the source of the info above.
Code Edits: Don't use name t for both labels. Change parent of lt from root to canvas c, as suggested by mcu.

Categories

Resources