walexia
walexia

Reputation: 171

Tkinter place widget in specific location relative to window resize

I am new to tkinter and python and I simply wanted to place a "text entry" widget and a "button" widget on a canvas(with a background image) at a specific point and have the whole entire layout keep its position relative to the size of the window.This is because I will set my gui to be a full screen on different monitors, e.g anything from widescreen to 4:3 aspect ratios.But i want my buttons and widgets to keep their relative positions, this diagram explains what I mean:- https://i.sstatic.net/4mZ5e.png

unfortunately I have not had any luck in using pack and grid options to give me that precise position that is also relative to windows/screen size.Is there a code I can run to return the position I want so i can input that in grid/pack to position my widgets?

So I developed some simple python3 code to try and get this done and have this:- (for your convenience the image reference is online, so the code should immediately run without any hitches in your IDE of choice)

from tkinter import*
from PIL import ImageTk, Image
import io
from io import BytesIO
import base64
import webbrowser
import urllib.request  # not urllib.request
from PIL import Image, ImageTk



root = Tk()

root.geometry("1600x700+0+0")




url = "https://i.imgur.com/VqBbqpH.png"  #use "direct link" from imgur, not  "image link"

u = urllib.request.urlopen(url)
raw_data = u.read()
u.close()

im = Image.open(BytesIO(raw_data))
image = ImageTk.PhotoImage(im)

entryDefaultText="Enter Text"




class App(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)
        self.button = Button(master, text="Edit Box Details(click here)", fg="blue")
        self.button.pack()
        #self.button.pack().pack(side=TOP, anchor=W, fill=X, expand=NO)
        self.columnconfigure(0,weight=1)
        self.rowconfigure(0,weight=1)
        self.original=im
        self.image = ImageTk.PhotoImage(self.original)
        self.display = Canvas(self, bd=0, highlightthickness=0)
        self.display.create_image(0, 0, image=self.image, anchor=NW, tags="IMG")
        self.display.grid(row=0, sticky=W+E+N+S)
        self.pack(fill=BOTH, expand=1)
        self.bind("<Configure>", self.resize)
        self.entryWidget(self)





    def entryWidget(self,root):
        self.entry_var = entryDefaultText
        v = StringVar(root, value='Enter Text')
        #self.entry = Entry(root, textvariable=self.entry_var)
        self.entry = Entry(root, textvariable=v)
        self.entry.grid(row=0, column=0, sticky=N,padx=1, pady=1)  # margins




    def resize(self, event):
        size = (event.width, event.height)
        resized = self.original.resize(size,Image.ANTIALIAS)
        self.image = ImageTk.PhotoImage(resized)
        self.display.delete("IMG")
        self.display.create_image(0, 0, image=self.image, anchor=NW, tags="IMG")

                                                                                 #in ms

app = App(root)
app.mainloop()
root.mainloop()

I managed to get the background image to resize according to the windows size, but my widgets and buttons just sit at the top.I have tried specifying locations e.g In this case I want the widget to sit at the top vertix of the triangle.But how can i specify that exact location, and how can I get my widget to sit on the background picture at that location, and not at the top/bottom/side of the gui. Thank you!

Upvotes: 3

Views: 7018

Answers (1)

walexia
walexia

Reputation: 171

I was able to resolve this (thanks to Goyo) by replacing both .pack and .grid geometry managers with the .place geometry manager i.e I added :-

self.button.place(relwidth = 0.07, relheight = 0.03, relx = 0.489, rely = 0.243)

and

self.entry.place(relwidth=0.07, relheight=0.03, relx=0.489, rely=0.276)

what that did was allowed me to specify the location to place the widget and the button and tied their size to the relative size of my window.Another thing I added as a quality of life issue was to post the location of the cursor on the gui using this code(special thanks to unutbu's answer here on stack overflow):-

def motion(event):
    x, y = event.x, event.y
    print('{}, {}'.format(x, y))
    #in ms

root.bind('<Motion>', motion)
root.mainloop()

This printed the co-ordinates of the location I wanted, so that I could properly position my buttons and edit text widget

Upvotes: 8

Related Questions