How to move a Tkinter button? - python

I am new to Python and Tkinter and I am needing to move a button.
I have been using button1.pack() to place the button.
I am not able to move the button from its original position at the bottom of the screen.

Absolute position
button1.place(x=some_value, y=some_value)
or relative position
button1.pack(side=RIGHT, padx=some_value, pady=some_value)
padx, pady - paddings

button1.grid(row = 0, column = 0, padx = 0, pady = 0)
But this cannot be used together with pack(), you need to stick to either one.
And this only orders objects relatively, so if you have only one object and you set the row and column to 40 and 50, respectively, the object will still be on the top left corner.

animated movement:
import time, tkinter
X,Y=,0,0
for i in range(pixelsToMove):
button.place(x=X,y=Y)
X=X+1
Y=Y+1
time.sleep(0.1)
it will move to the bottom right corner slowly here is how to adjust it:
to move to the right ONLY at a set Y then at the y=Y part do y=set_y and for x do the same thing to move left change X=X+1 do X=X-1 and at X,Y = 0,0 do X,Y = start_x,0 same for y.

Related

Why does this label go off screen when anchored?

I want to anchor this label but for some reason, it keeps going off the screen in my computer, i don't know if its just me but here's my code:
import tkinter as tk
root = tk.Tk()
root.attributes("-fullscreen", True)
label_frame = tk.Frame(root)
answer_label = tk.Label(label_frame, text="text")
answer_label.grid(row = 0, column = 0)
label_frame.place(anchor = "n")
root.mainloop()
Why does this label go off screen when anchored?
Consider this line of code:
label_frame.place(anchor = "n")
The anchor option tells tkinter what part of the frame is to be placed at the given coordinates. n means "north", or the top-center of the frame. So, whatever coordinates are given, the top-center portion of the frame will be at those coordinates.
Since you did not give any coordinates, they default to x=0 and y=0. Thus, the top-middle portion of the frame will be placed at 0,0. That means that the left half of the frame will be to the left of coordinate 0,0.
If you insist on using place, and if you want the frame centered, you can give a relx of .5, meaning that the anchor position (n) will be placed half-way across the width of the containing widget.
label_frame.place(relx=.5, y=0, anchor = "n")
try
label_frame.place(anchor = "nw")
Tested this and it seems to put the label in the right place.

Python Tkinter how to adjust the x,y default 0,0 coordinates

I've been learning some basic tkinter and I've come across simple code to centre the window in the middle of your monitor, except when I run it, it's off horizontally. It's pedantic but it bothers me a lot.
The code I used
# Imports
from tkinter import *
# tkinter Application
root = Tk()
#Root Geometry
root_Width = 600
root_Length = 600
# Coordinates of top left pixel of application for centred
x_left = int(root.winfo_screenwidth()/2-root_Width/2)
y_top = int(root.winfo_screenheight()/2-root_Length/2)
root_Pos = "+" + str(x_left) + "+" + str(y_top)
# Window size and position
root.geometry(str(root_Width) + "x" + str(root_Length) + root_Pos)
root.mainloop()
Even if I go basic, and just try to open a window the size of my monitor (1920x1080) at 0,0, it's misaligned horizontally by 8px.
from tkinter import *
root = Tk()
root.geometry("1920x1080+0+0")
root.mainloop()
I took a screenshot of the result:
I have a dual monitor set up so I've added a red line where the right monitor starts. I don't know what the issue is or how to fix it. If I change it to,
root.geometry("1920x1080+-8+0")
It opens where it should, but I want to fix this in general preferably. I want 0,0 to be the top left pixel of the monitor. I acknowledge the issue may not be with python, but any advice would be helpful.
Ok, there are two thing that you are missing. The first, in your first example, is that you need to assure tkinter is getting the right values, and to do this you have to use update_idletasks() method before any winfo.
The second thing, which explains why you have to use -8 to center the full screen window, is that tkinter widows have outer-frames. You can determine the size of this frame by checking for the top left coordinate of the window (winfo_rootx()) and of the outer-frame (winfo_x()). Now the frame width is the difference between both: frame_width = root.winfo_rootx() - root.winfo_x() while the real window width is real_width = root.winfo_width() + (2*frame_width), since you have to consider the frame in both sides.
In summary, to center the window horizontally you do:
width = root.winfo_width()
frame_width = root.winfo_rootx() - root.winfo_x()
real_width = root.winfo_width() + (2*frame_width)
x = root.winfo_screenwidth() // 2 - real_width // 2
(here you can print the frame width and you will see it is 8)
and then use geometry method to place the window at position x.
Off course you can do the same for the vertical alignment

Why does my tkinter object keep changing shape?

I have created an image on a canvas in tkinter that responds to a button event. And, the object is created on position x and position y where that event took place. But the object changes shape constantly.
def leftclick(event):
canvas1=Canvas(play, height=hei, width=wid)
canvas1.grid(row=0, column=0, sticky=W)
canvas1.delete("all")
x=event.x
y=event.y
print(event.x, event.y)
bullet = canvas1.create_oval(x,y, 100,100, fill="red")
xspeed=random.randint(0, 50)
yspeed=random.randint(0,50)
This just draws ovals which are randomly shaped. Why is this happening and how do I fix it?
You should only create your canvas once, but that's not a problem.
The problem is that the tkinter tries to create an oval inside the rectangle. You've specified the 2 points of the rectangle: x,y and 100,100. Just use bullet = canvas1.create_oval(x-50,y-50, x+50,y+50, fill="red") or whatever number you pick instead of 50. Hope that's helpful!

position of line when resizing Tkinter window

The following code:
from tkinter import *
root=Tk()
for x in range(10):
for y in range(10):
canvas=Canvas(root, width='15',height='15',highlightthickness=0,bg='red')
canvas.create_line(canvas.winfo_x(),canvas.winfo_y(),canvas.winfo_x()+15,canvas.winfo_y()+15,width=2,fill='black')
canvas.grid(row=y,column=x,sticky='NESW')
for x in range(10):
for y in range(10):
root.columnconfigure(x,weight=1)
root.rowconfigure(y,weight=1)
root.mainloop()
produces this, which is a 10 by 10 grid filled with canvases; there is a line extending from the top left to the bottom right corner of each canvas.
When I resize the window, the canvas widgets resize correctly, but the lines retain their shape like this. The lines need to adjust according to the window/widget size.
The core of the problem is that the lines are made using the coordinates of the top left corner of the widget, and are extended 15 pixels in each direction. Is there a way of getting the coordinates of the bottom right corner of the widget, so that the lines can change their shape dynamically, or some other way of keeping the lines shape, relative to the widget?
You can get the current width and height of any widget with the winfo_width and winfo_height methods. If you are binding to the <Configure> method to track when the canvas changes size, the event object has a width and height attribute.
For example:
from tkinter import *
def redraw_line(event):
width = event.width
height = event.height
canvas = event.widget
canvas.coords("diagonal", 0, 0, width, height)
root=Tk()
for x in range(10):
for y in range(10):
canvas=Canvas(root, width='15',height='15',highlightthickness=0,bg='red')
canvas.bind("<Configure>", redraw_line)
# coordinates are irrelevant; they will change as soon as
# the widget is mapped to the screen.
canvas.create_line(0,0,0,0, tags=("diagonal",))
canvas.grid(row=y,column=x,sticky='NESW')
for x in range(10):
for y in range(10):
root.columnconfigure(x,weight=1)
root.rowconfigure(y,weight=1)
root.mainloop()

Issues with canvas scrollbars in Tkinter

Relevant code:
self.propertyListWrapper = ttk.Frame(self.propertyMenu)
self.propertyListWrapper.pack( fill = tk.BOTH, expand = tk.YES )
self.propertyListCanvas = tk.Canvas(self.propertyListWrapper)
self.propertyListCanvas.pack( fill = tk.BOTH, expand = tk.YES, side = tk.LEFT )
self.propertyGrid = ttk.Frame(self.propertyListCanvas)
self.propertyListScrollbar = ttk.Scrollbar(self.propertyListWrapper)
self.propertyListScrollbar.config(command = self.propertyListCanvas.yview)
self.propertyListCanvas.config(yscrollcommand = self.propertyListScrollbar.set)
self.propertyListScrollbar.pack(side = tk.RIGHT, fill = tk.Y)
...
# where stuff is added to self.propertyGrid
...
self.propertyListCanvas.config( scrollregion = (0, 0, self.propertyGrid.winfo_width(), self.propertyGrid.winfo_height()))
self.propertyListCanvas.create_window((0,0), window = self.propertyGrid, anchor='nw')
This is what is currently happening:
As you can see, the scrollbar doesn't have a bar. Not very useful.
What am I doing wrong?
Here's a simplified Github Gist that duplicates the problem. 20 labels should be there, and you should be able to scroll through them, but the scrollbar doesn't appear.
The default for pack is to put something along the top edge. When you packed the canvas you're using the default, so it takes up the top of the gui, leaving blank space below. When you packed the scrollbar, you told it to go to the right, so it is at the right edge of the empty space below the canvas. If you want the scrollbar and canvas side-by-side, pack both on the right, or pack one on the right and one on the left.
The problem with your gist is that you're trying to get the width and height of the frame before it has been drawn. Since the frame hasn't been mapped to the screen (because you haven't added it to the canvas yet) it's width and height is 1 (one). You must make a widget visible before you can measure its width and height. That means to add it to a canvas or pack/place/grid it to a visible window and then wait for a screen repaint.

Categories

Resources