Why doesn't this centre the window? - python

I am using this code to centre my screen as shown in this post and my question but to my surprise it doesn't centre the window exactly. It puts it in the lower right hand corner not the centre exactly. Why is this?
top1=Toplevel(root)
w = top1.winfo_screenwidth()
h = top1.winfo_screenheight()
topsize = tuple(int(_) for _ in top1.geometry().split('+')[0].split('x'))
x = w/2 - topsize[0]/2
y = h/2 - topsize[1]/2
top1.geometry("+%d+%d" % (topsize[0]+x, topsize[1]+y))
Final Solution by Steven Summers
import Tkinter as tk
def center_window(win):
w = win.winfo_screenwidth()
h = win.winfo_screenheight()
x = w/2 - win.winfo_width()/1-150
y = h/2 - win.winfo_height()/1-200
win.geometry("+%d+%d" % (x, y))
root = tk.Tk()
top1 = tk.Toplevel(root)
top1.title('TopLevel Window 1')
top1.minsize(300, 300)
b = tk.Label(top1, text='Here is a Label')
b.pack()
l = tk.Button(top1, text='Click Me')
l.pack()
top1.after(1, lambda: center_window(top1))
root.mainloop()

You need to call root.after(delay, command) to run this. When you create the widget and it tries to initialize, the size is 1x1. Which is why your values are not correct when placing it. Also as mentioned in the answer to the question referenced, use .winfo_width() and .winfo_height() instead of going through the geometry to get the values.
import tkinter as tk
def center_window(win):
w = win.winfo_screenwidth()
h = win.winfo_screenheight()
x = w/2 - win.winfo_width()/2
y = h/2 - win.winfo_height()/2
win.geometry("+%d+%d" % (x, y))
root = tk.Tk()
top1 = tk.Toplevel(root)
top1.title('TopLevel Window 1')
top1.minsize(300, 300)
b = tk.Label(top1, text='Here is a Label')
top1.after(1, lambda: center_window(top1))
l = tk.Button(top1, text='Click Me')
b.pack()
l.pack()
root.mainloop()

I think it should be
top1.geometry("+%d+%d" % (x, y))

Related

Why doesn't this image move when the key is pressed?

Python and Tkinter nebwie. I tried making an image in tkinter and have it move using the arrows. The image shows just it should, but when I try to move it using the arrows, it doesn't work at all. Any idea why? I use python 2.7.18 and I'm on the latest version of Ubuntu
from Tkinter import *
############
#things
w = 500
h = 500
width=w
height=h
#############
######################################################################
#window
window = Tk()
window.title("Moving image")
canvas = Canvas(window, width = 500, height = 500)
canvas.pack()
my_image = PhotoImage(file="/home/user/Documents/ddd.png")
canvas.create_image(260, 125, anchor = NW, image=my_image)
#######################################################################
################################
#var
def up(event):
x = 0
y = -10
canvas.move(my_image, x, y)
def down(event):
x = 0
y = 10
canvas.move(my_image, x, y)
def left(event):
x = -10
y = 0
canvas.move(my_image, x, y)
def right(event):
x = 10
y = 0
canvas.move(my_image, x, y)
###############################
###############################
#binds
window.bind("<Up>", up)
window.bind("<Down>", down)
window.bind("<Left>", left)
window.bind("<Right>", right)
window.mainloop()
##############################
You are trying to move the wrong object. Use the object, which is returned by canvas.create_image:
image_id = canvas.create_image(260, 125, anchor = NW, image=my_image)
...
canvas.move(image_id, x, y)
Alternatively, you can attach a tag to the image:
canvas.create_image(260, 125, anchor=NW, image=my_image, tag="move")
...
canvas.move("move", x, y)
This will move all objects, which have this specific tag attached.

How to deal with unhashable type 'StringVar' Python

I am creating a code that converts temperature units to other temperature units for example Celsius to Fahrenheit. When I run this code I get an error stating type error: unhashable type StringVar. I'm not sure what I am doing wrong and am not sure how to resolve this problem any help would be appreciated.
from tkinter import *
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
#======================================================================
notebook = ttk.Notebook(root)
frame3 = ttk.Frame(notebook)
notebook.add(frame3, text='Temperature')
notebook.pack(expand=1, fill="both")
#======================================================================
def Temperature_converter(*args):
v = float(temp_entry.get())
temp_dict = dict(Fahrenheit= (1/1.8, -32/1.8), Celsius= (1, 0), Kelvin= (1, -273.15))
x, y = temp_dict[temp_var1]
cels = temp_entry * x + y #turns input to celsius by mapping x and y to ratio and difference
x, y = temp_dict[temp_var2]
answer = (cels - y) / x # turns input in celsius to output
temp_label['text']=answer
#======================= ===============================================
temp_entry = Entry(frame3)
temp_entry.grid(row=0, column=0)
temp_label = Label(frame3, relief='groove', width=20, text='')
temp_label.grid(row=0, column=3)
options3 = ['Unit', 'Celsius', 'Fahrenheit', 'Kelvin']
temp_var1 = tk.StringVar(frame3)
temp_var1.set(options3[0])
temp_dropdown1 = tk.OptionMenu(frame3, temp_var1, options3[1], options3[2], options3[3])
temp_dropdown1.grid(row=1, column=0)
temp_var2 = tk.StringVar(frame3)
temp_var2.set(options3[0])
temp_dropdown2 = tk.OptionMenu(frame3, temp_var2, options3[1], options3[2], options3[3])
temp_dropdown2.grid(row=1, column=3)
temp_equal_button = Button(frame3, text='=', command=Temperature_converter)
temp_equal_button.grid(row=1, column=5)
#======================================================================
root.mainloop
To get string from StringVar you have to use .get() and then dictionary has no problem to find this string
x, y = temp_dict[ temp_var1.get() ]
x, y = temp_dict[ temp_var2.get() ]
the same with Entry but you have to also convert string to float to make calculation
cels = float( temp_entry.get() ) * x + y
Code:
def Temperature_converter(*args):
temp_dict = dict(Fahrenheit=(1/1.8, -32/1.8), Celsius=(1, 0), Kelvin=(1, -273.15))
x, y = temp_dict[temp_var1.get()]
cels = float(temp_entry.get()) * x + y
x, y = temp_dict[temp_var2.get()]
answer = (cels - y) / x
temp_label['text'] = answer

How to change window geometry in tkinter using after?

What I want to achieve is displaying an image on another application window with regard to its coordinates. For example, it should appear 100 pixels down and 100 pixels left to the left upper corner. I am using transparent window for the image, and it displays an image properly but it doesn't update its coordinates.
Here is my code:
import tkinter as tk # Python 3
from functions import window_coordinates # it takes x, y, width, heigth of the window
x, y, w, h = window_coordinates("window_name")
def update_coordinates():
global x, y, w, h
x, y, w, h = window_coordinates("window_name")
root.geometry("+{}+{}".format(x + 100, y + 100))
print("update_coordinates function")
root = tk.Tk()
# The image must be stored to Tk or it will be garbage collected.
root.image = tk.PhotoImage(file='path/to/image.png')
label = tk.Label(root, image=root.image, bg='white')
root.overrideredirect(True)
root.geometry("+{}+{}".format(x+100, y+100))
root.lift()
root.wm_attributes("-topmost", True)
root.wm_attributes("-disabled", True)
root.wm_attributes("-transparentcolor", "white")
label.pack()
label.after(100, update_coordinates)
label.mainloop()
Thanks for help.
EDIT1: I put root.geometry("+{}+{}".format(x + 100, y + 100)) inside the function but it didn't help. Also I added print statement to see how this function works and it's called only once at the beginning.
OK, I found the answer. There was a mistake in the function. Callback didn't work. Right code:
import tkinter as tk # Python 3
from functions import window_coordinates
x, y, w, h = window_coordinates("3949206036")
def update_coordinates():
global x, y, w, h
x, y, w, h = window_coordinates("3949206036")
root.geometry("+{}+{}".format(x + 100, y + 100))
label.after(1, update_coordinates) # This addition was needed
root = tk.Tk()
# The image must be stored to Tk or it will be garbage collected.
root.image = tk.PhotoImage(file='d:/Python/Projects/Data-mining/samples/avatar.png')
label = tk.Label(root, image=root.image, bg='white')
root.overrideredirect(True)
root.geometry("+{}+{}".format(x+100, y+100))
root.lift()
root.wm_attributes("-topmost", True)
root.wm_attributes("-disabled", True)
root.wm_attributes("-transparentcolor", "white")
label.pack()
label.after(1, update_coordinates)
label.mainloop()

How to make simple GUI graph with Linear Equation

I am a beginner programmer. I have a task to make a GUI with a linear equation y=mx+b and a set of parameters where I can change the m and b values. I have both matplotlib and numpy. I also have tkinter for the GUI. This is what i have so far i edited my friends code on a coordinate GUI.
def onButtonValChange():
if X1.get() != '':
x[0] = float(X1.get())
if Y1.get() != '':
y[0] = float(Y1.get()
def createGraph(x,y):
graphRoot = Tk.Tk()
graphRoot.wm_title("Your Graph")
graphRoot.resizable(0,0)
f = Figure(figsize=(5, 4), dpi=100)
a = f.add_subplot(111)
a.plot(x, y)
canvas = FigureCanvasTkAgg(f, master=graphRoot)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
x = [1]
y = [1]
ButtonChangeValues = Tk.Button(root, text="Submit Change", command=onButtonValChange)
ButtonChangeValues.grid(row=11, columnspan=3)
ButtonCreateGraph = Tk.Button(root, text="Create This Graph", command=lambda: createGraph(x, y))
ButtonCreateGraph.grid(row="15", columnspan=3)
Tk.mainloop()
So here is some code that i use its a moving line graph but you could adapt the code to move only when you change the equation. all you would have to do is populate the lists of x0Coords y0Coords and xy0Coords with the right mx+b formula
# Run from IDLE or LXTerminal not IDLE 3
# for import spidev to work, must run as python (v2) not python3
from Tkinter import * #to run on python 2, use Tkinter, for python3 use tkinter
import math
from datetime import datetime, timedelta
import numpy as np
import spidev
#--------------------- variables -------------------------
#---user defined settings
screenWidth = 450
resolution = 5 #number of pixels between data points, for visual purposes only
samplePeriod = 100 #milliseconds, time between data points written to txt file
timeRange = .5 #minutes
#---end user settings
baseTime = int(timeRange*60*1000/screenWidth)
startTime = datetime.now()
nl = "\n"
root = Tk()
root.title("Simple GUI")
root.geometry("500x300") #widthxheight
C = Canvas(root, bg = "gray", height = 250, width = screenWidth)
x0Coords = []
y0Coords = []
xy0Coords = []
coordLength = int(screenWidth/resolution)
#---initiation of lists
for i in range(0,coordLength):
x0Coords.append(i*resolution)
y0Coords.append(125)
xy0Coords.append(0)
xy0Coords.append(0)
#putting X and Y corrdinites in a list
def coordinate():
global x0Coords, y0Coords, xy0Coords
for i in range(0,coordLength*2,2):
xy0Coords[i] = x0Coords[i/2]
xy0Coords[i+1] = y0Coords[i/2]
#print(xy0Coords)
#---End initiation of lists
c0 = C.create_rectangle(0,0,20,50)
cl0 = C.create_line(xy0Coords)
pressure = Label(root, text="test")
pressure.pack()
spi_0 = spidev.SpiDev()
spi_0.open(0, 0)
#--------------------------- End of Variables -------------------------
#--------------------------- Definitions ------------------------------
#shifts y values down in index in array to represent time moved forward
def shiftCoords(nextValue):
global y0Coords, xy0Coords
y0Coords.pop(0)
y0Coords.append(nextValue)
coordinate()
#updates the GUI based on the new time
def move_time():
global c0,cl0,xy0Coords, resolution, baseTime
C.delete(c0)
C.delete(cl0)
c0 = C.create_rectangle(0,0,20,int(float(readadc_0(0))/1023*250))
shiftCoords(125-int(float(readadc_0(0))/1023*125))
cl0 = C.create_line(xy0Coords)
#print(float(readadc_0(0))/1023*250)
root.title("V= " + str(round(3.3*float(readadc_0(0))/1023,2)))
root.after(baseTime*resolution,move_time)
C.pack()
root.after(baseTime,move_time)
root.after(samplePeriod,writeData)
root.mainloop()

How to move a Canvas image using Tkinter?

Guys I am working on a code which needs to move an image in python using Tkinter(canvas)
This is creating problems for me. The image is being displayed but it is not moving.
from Tkinter import *
root = Tk()
root.title("Click me!")
def next_image(event):
global toggle_flag
global x, y, photo1
# display photo2, move to right, y stays same
canvas1.create_image(x+10, y, image=photo1)
canvas1.create_image(x+20, y, image=photo1)
canvas1.create_image(x+30, y, image=photo1)
canvas1.create_image(x+40, y, image=photo1)
canvas1.create_image(x+50, y, image=photo1)
canvas1.create_image(x+60, y, image=photo1)
canvas1.create_image(x+70, y, image=photo1)
canvas1.create_image(x+100, y, image=photo1)
image1 = "C:\Python26\Lib\site-packages\pygame\examples\data\ADN_animation.gif" #use some random gif
photo1 = PhotoImage(file=image1)
# make canvas the size of image1/photo1
width1 = photo1.width()
height1 = photo1.height()
canvas1 = Canvas(width=width1, height=height1)
canvas1.pack()
# display photo1, x, y is center (anchor=CENTER is default)
x = (width1)/2.0
y = (height1)/2.0
canvas1.create_image(x, y, image=photo1)
canvas1.bind('<Button-1>', next_image) # bind left mouse click
root.mainloop()
Canvas provides move method. Arguments are item you want to move, relative x offset from the previous position, y offset.
You need to save the return value of the create_image to pass it to the move method.
Also make sure the canvas is expandable (pack(expand=1, fill=BOTH) in the following code)
from Tkinter import *
root = Tk()
def next_image(event):
canvas1.move(item, 10, 0) # <--- Use Canvas.move method.
image1 = r"C:\Python26\Lib\site-packages\pygame\examples\data\ADN_animation.gif"
photo1 = PhotoImage(file=image1)
width1 = photo1.width()
height1 = photo1.height()
canvas1 = Canvas(width=width1, height=height1)
canvas1.pack(expand=1, fill=BOTH) # <--- Make your canvas expandable.
x = (width1)/2.0
y = (height1)/2.0
item = canvas1.create_image(x, y, image=photo1) # <--- Save the return value of the create_* method.
canvas1.bind('<Button-1>', next_image)
root.mainloop()
UPDATE according to the comment
Using after, you can schedule the function to be called after given time.
def next_image(event=None):
canvas1.move(item, 10, 0)
canvas1.after(100, next_image) # Call this function after 100 ms.

Categories

Resources