How could I display IntVar with tkinter using place()? - python

When I use the below code which display using .pack(), the number appeared. However when i change to place, there is no number appeared on the screen. How could I use place to display number instead of pack because I want to set it to specific location?
Code with pack() :
import tkinter as tk
master_window = tk.Tk()
master_window.geometry("250x150")
master_window.title("IntVar Example")
integer_variable = tk.IntVar(master_window, 255)
label = tk.Label(master_window, textvariable=integer_variable, height=250)
label.pack()
master_window.mainloop()
Code with place () :
import tkinter as tk
master_window = tk.Tk()
master_window.geometry("250x150")
master_window.title("IntVar Example")
integer_variable = tk.IntVar(master_window, 255)
label = tk.Label(master_window, textvariable=integer_variable, height=250)
label.place( x = 80 , y=80 )
master_window.mainloop()
How could I set the integer variable using place because i want it to display in specific location?

You've set the label to be 250 characters tall. By default the text appears in the centered in the middle of the label. Because of the size it forces the value off screen. If you are able to make the window tall enough, you'll see the number.
If you remove the height attribute from the label it will show up.

Related

Changing a displayed image inside mainloop on Tkinter?

I'm trying to make a program to display a single color, fullscreen. The idea is to use it on a large screen to create environment in the room, the screen changing from color to color after certain time.
Displaying the color fullscreen is not a problem but how can I change said color smoothly?
For the fullscreen display I've used a Tkinter window with the same size as the screen: imagesprite = canvas.create_image(w/2, h/2, image=image) where image is a certain color. But to change the color I need to destroy the window using root.after(2000, root.destroy) and then create a new one. This is not smooth as the desktop can be seen for a brief moment.
How can I change the image displayed inside a Tkinter window on the go, or, how can I close one window and open another one smoothly?
An option you have is instead of using an image is to have a background for the Canvas object. Here is the minimum code to have a single colour background.
from tkinter import Tk, Canvas
root = Tk()
root.attributes("-fullscreen",True)#Makes the window fullscreen
canvas = Canvas(root, width=root.winfo_width(),height=root.winfo_height(), background="red") #Makes a canvas with a red coloured background
#The width and height of the Canvas are taken from the root object
canvas.pack()
root.mainloop()
From here, instead of deleting the window constantly, it is possible to just change the attributes of Tkinter widgets. This is done using the config method.
canvas.config(background="green")
A great thing about tkinter is that you can give it a hex code for the colour and it will draw use that. It needs to be in a string formatted like this:
"#RRGGBB" where each group is a hexadecimal number from 0 to FF.
With this in mind, you can increase the hexadecimal number each frame or however many frames you want between two colours. To have a good transition, you may want to use Hue,Saturation,Value (HSV) colours, and only change the Hue value.
You can store the HSV in a list:
hsv = [0,0.7,0.7]
To convert, you first want to convert to 0 to 255 RGB and then to Hexadecimal.
import colorsys
rgb = colorsys.hsv_to_rgb(*hsv) #Uses list unpacking to give it as arguments
Next, you use the rgb and turn it into Hexcode form.
def getHexCode(rgb):
r = hex(int(rgb[0]*255))[2:] #converts to hexadecimal
#With the hex() function, it returns a number in "0xFE" format (0x representing hex).
#To ignore this, we can take the substring using [2:]
if len(r) < 2: #If the value is a 1-digit number, then we want to add a zero at the front for hexcode form
r = "0"+r
g = hex(int(rgb[1]*255))[2:]
if len(g) < 2:
g = "0"+g
b = hex(int(rgb[2]*255))[2:]
if len(b) < 2:
b = "0"+b
return "#" + r + g + b
Finally, we actually call the change method.
changeSpeed = 200
def changeColor():
rgb = colorsys.hsv_to_rgb(*hsv)
hexCode = getHexCode(rgb)
canvas.config(background = hexCode)
hsv[0]+=0.01
root.after(changeSpeed,changeColor)
root.after(changeSpeed, changeColor)
(EDITED)
Two things that were previously a problem were the root.winfo_width() and root.winfo_height(), as well as the fullscreen giving a border.
To solve the first problem, we have to somehow update the root object, since by default it's 1x1. What we can do for that is make the Canvas object and then update it. It looks like this:
canvas = Canvas(root, width=100,height=100, background="white",highlightthickness=0) #Makes a canvas with a white coloured background
canvas.pack()
canvas.update()
canvas.config(width = root.winfo_width(), height = root.winfo_height())
The second problem is also solved by making the canvas object with a specific attribute, highlightthickness=0. If you notice, the canvas object initialization is now:
canvas = Canvas(root, width=100,height=100, background="white",highlightthickness=0)
Another thing that I thought was useful is if a button closes the program. I bound the "Escape" key to the closing using the following:
def quit(event):
root.destroy()
root.bind("<Escape>", quit)
As a full program, it looks like this:
import colorsys
from tkinter import Tk, Canvas
hsv = [0,1,0.8]
changeSpeed = 200
root = Tk()
root.attributes("-fullscreen",True)
canvas = Canvas(root, width=100,height=100, background="white",highlightthickness=0) #Makes a canvas with a white coloured background
canvas.pack()
canvas.update()
canvas.config(width = root.winfo_width(), height = root.winfo_height())
def getHexCode(rgb):
r = hex(int(rgb[0]*255))[2:]
if len(r) < 2:
r = "0"+r
g = hex(int(rgb[1]*255))[2:]
if len(g) < 2:
g = "0"+g
b = hex(int(rgb[2]*255))[2:]
if len(b) < 2:
b = "0"+b
return "#" + r + g + b
def changeColor():
rgb = colorsys.hsv_to_rgb(*hsv)
hexCode = getHexCode(rgb)
canvas.config(background = hexCode)
hsv[0]+=0.01
root.after(changeSpeed,changeColor)
def quit(event):
root.destroy()
root.after(changeSpeed, changeColor)
root.bind("<Escape>", quit)
root.mainloop()
Some variables you can change in this is the changeSpeed, the original hsv list, and the 0.01 that is added to the hue each increase

Tkinter - relation between font type and width

I apologize in advance if my question is a duplicate however I have not found an answer to this question.
I'm learning Tkinter and I'm struggling with understanding the relation between a label's font type, it's size and it's width and the length of the string in it.
Specifically, what my problem is:
I have created a widget: a 800x640 canvas on which I want to place other
widgets.
On this canvas I want to place a label with some text which has the following
attributes: font: Helvetica, font size: 20, text = "main application". I want
to place this label widget at the very most top left corner of the
widget(meaning at point 0,0 with respect to the canvas). I want the label to
be 200 in width meaning it's background to take almost 1/3 of the canvas's
size(after I manage to do this I plan to add 2 more labels as well). I guess
the height of the label is determined by the font size in this case 20. I
placed the label at coordinate y=20 and this coordinate seems to be ok.
I did some googling and found out that the width parameter of the label widget is not the actual width but something related to the font and size of the label's text: something like if I understood correctly: if the width is 6 than the label will be wide enough to contain 6 characters of, in my case verdana size 20. But I was not able to figure out what width and what x coordinate I should give my label so it starts at the x point of the canvas. Here is the code that I wrote:
from tkinter import *
from tkinter.ttk import *
from tkinter import messagebox
from tkinter import Menu
# Define the application class where we will implement our widgets
class Application(Frame):
def __init__(self, master):
super(Application, self).__init__(master)
# CANVAS COLOUR DEFAULTS TO THE COLOUR OF THE WORKING WINDOW
canvas = Canvas(master, width=800, height = 640, bg="gray") # IF YOU DO .PACK() HERE IT WILL RETURN NONE AND THEN YOU WILL HAVE PROBLEMS BECAUSE .PACK() RETURNS A 'NONE' TYPE OBJECT
canvas.place(relx=0.5, rely=0.5, anchor=CENTER)
# The 'menu' of the application. The selection labels
main_application_label = Label(master, text="main_application", font=("Helvetica", 20))
main_application_window = canvas.create_window(103,20, window=main_application_label)
main_application = Tk()
main_application.title("main_application")
app = Application(main_application)
app_width = 800
app_height = 640
screen_width = main_application.winfo_screenwidth()
screen_height = main_application.winfo_screenheight()
x_coord = (screen_width/2) - (app_width/2)
y_coord = (screen_height/2) - (app_height/2)
main_application.geometry("%dx%d+%d+%d" % (app_width, app_height, x_coord, y_coord))
main_application.mainloop()
I have managed to somehow get the label at around point 0,0(by giving more values till I got it right) but the actual width of the label is not 200 pixels(~1/3 of the canvas). Please help me understand what values to the width parameter I should give so that my label's background is 1/3 of the canvas's size and if possible explain the relation between character font and width parameter so I can do that for any widgets regardless of their text's length. Thank you for reading my post!
Edit: What I wanted to do was to place 3 widgets(labels in this case but it doesn't matter) on the canvas. I did not understand what the 'anchor' option does and that was confusing me because I was expecting the center of the widget to be placed at the given coordinates all times but as I was changing anchor the placement of the center of the widget was changing and that was confusing me. It's all clear now thanks to #Bryan Oakley. Thanks.
If you want the upper left corner of the text to be at (0,0), you don't have to adjust the coordinates based on the width. You can use the anchor option when creating the canvas object:
main_application_window = canvas.create_window(0, 0, anchor="nw",
window=main_application_label)
If you really need to compute the actual size of the string, you can create a Font object and then use the measure method to find the actual width of a string in the given font.
from tkinter.font import Font
font = Font(family="Helvetica", size=20)
string_width = font.measure("main_application")
string_height = font.metrics("linespace")
This gives you the size of the rendered string. If you're using a label widget you'll also need to take into account the amount of padding and borders that the widget uses.
When you create items on a canvas, you can specify the width and height. For example, this makes the widget 200 pixels wide:
main_application_window = canvas.create_window(0, 0, anchor="nw", width=200,
window=main_application_label, width=400)

Place widgets into Frames?

I was trying out something new on Tkinter (I am still a newbie), but it keeps failing...maybe someone could help out?
I wanted to create a window with several Frames, so that I can open and close them and show that way different content. However I am already stuck with not being able to "place" the, in this case a button, to the frame. Instead I get a blank frame with nothing inside...
The reason I want to use the place manager is so that I can easily choose the x and y coordinates. I don't want to create empty columns just in order to get a button appear in the middle of the screen.
Here the code:
from Tkinter import *
root = Tk()
root.title("Tkinter window")
root.geometry("800x600")
StartFrame = Frame(root)
StartFrame.pack()
Button1 = Button(StartFrame, command = StartTkinter, text = "Start", bg = "white", fg = "black", height = 2, width = 15)
Button1.place(x=0, y=50)
root.mainloop()
The problem is that you forgot to specify the dimensions of the frame. So, by default, it is created to be just 1 pixel high and 1 pixel wide. This means that its contents will not be visible on the window.
To fix the problem, you can either set exact values for these dimensions when you create the frame:
StartFrame = Frame(root, height=600, width=800)
or you can do:
StartFrame.pack(expand=True, fill="both")
to have the frame fill all available space.

Python: GUI packing widgets

This is my program and i packed my widgets so it would be left but somehow when i run it the widgets are not appearing from the left. The person and colour are appearing in the middle but the scary person and creature is appearing on the left. I want person and colour widget to to appear on the left too.
Here is my program
from Tkinter import *
import Tkinter
import tkMessageBox
class StoryMaker:
def __init__(self):
# Create the main window.
self.main_window = Tkinter.Tk()
#Create nine frames to group widgets.
self.first_frame = Tkinter.Frame()
self.second_frame = Tkinter.Frame()
self.third_frame = Tkinter.Frame()
self.fourth_frame = Tkinter.Frame()
self.fifth_frame = Tkinter.Frame()
# Create the widgets for the first frame.
self.prompt_label = Tkinter.Label(self.first_frame, text='Please enter information for a new story, then click the "Make Story" button.')
# Create the widgets for the second frame.
self.person_label = Tkinter.Label(self.second_frame, text='Person: ')
self.person_entry = Tkinter.Entry(self.second_frame, width= 15)
# Pack the second frame's widgets.
self.person_label.pack(side='left')
self.person_entry.pack(side='left')
# Create the widgets for the third frame.
self.colour_label = Tkinter.Label(self.third_frame, text='Colour: ')
self.colour_entry = Tkinter.Entry(self.third_frame, width= 15)
# Pack the third frame's widgets.
self.colour_label.pack(side='left')
self.colour_entry.pack(side='left')
# Create the widgets for the fourth frame.
self.scary_label = Tkinter.Label(self.fourth_frame, text='Scary person or creature: ', justify=LEFT)
self.scary_entry = Tkinter.Entry(self.fourth_frame, width= 15)
# Pack the fourth frame's widgets.
self.scary_label.pack(side='left')
self.scary_entry.pack(side='left')
# Pack the frames.
self.first_frame.pack()
self.second_frame.pack()
self.third_frame.pack()
self.fourth_frame.pack()
self.fifth_frame.pack()
# Enter the Tkinter main loop.
Tkinter.mainloop()
my_gui = StoryMaker()
The first thing I suggest is that you give each of the frames a distinct background color. This is just temporary, so you can see where each frame begins and ends. I think you'll find the results surprising:
self.first_frame = Tkinter.Frame(background="red")
self.second_frame = Tkinter.Frame(background="pink")
self.third_frame = Tkinter.Frame(background="green")
self.fourth_frame = Tkinter.Frame(background="blue")
self.fifth_frame = Tkinter.Frame(background="yellow")
When you do that you'll quickly see that the problem isn't that the labels are centered, but that the frame they are in is in the center. This is because you packed them with no options, which is the same as saying ...pack(side="top", fill=None, expand=False).
If you add fill="x") when packing first_frame, second_frame, etc, you'll see that your labels and entry widgets are indeed on the left side of their container.
My advice to people who are trying to learn tkinter is to take the "divide and conquer" approach. If you are using intermediate frames to organize your widgets, start by creating only those frames. Get the pack or grid options set so that these containing widgets are where you want them, and resize the way you want them to. Only after doing that should you add the interior widgets. That way, at any one time you're only trying to solve the layout problems of one group of widgets at a time.
If you're laying out a form, you might find it easier to use grid rather than pack. Typically in a form all of the labels in a group of labels will be the same size and aligned with each other. That's much easier to do by using grid and placing all of the widgets in a single frame, than it is to use multiple frames.

change size of Frame even if there widget python

hi is there any way to change width and height of widget even if there's widget?
i have code like this
form = Tk()
form.geometry("500x500")
def click():
global frame
frame.config(height = 0 ,width = 0)
frame = LabelFrame(form , text = "vaaja")
frame.place(x = 20 , y = 30)
Label(frame, text ="1").grid(row = 0,column = 0 )
Label(frame, text = "2").grid(row = 1 ,column = 0 )
Button(form , text="Click", command = click).place(x = 200 , y = 200)
form.mainloop()
and when I click the button the size of the frame is the same ( I'cant use grid_forget() for labels and then change the size of frame)
Because you are using place, you have two solutions: you can use place to set the width and height to zero, or you can turn geometry propagation off.
Using place to set the width and height
place allows you to define the width and the height of the placed widget, so in your click function you can do this:
def click():
frame.place_configure(width=0, height=0)
Turning geometry propagation off
A frame is resized to fit its contents by something called "geometry propagation". If you turn this off, you can control the size of the frame with the width and height options of the frame itself. Usually it's better to let Tkinter decide the size for you, but sometimes there's a need to have an explicit size, which is why it's possible to turn geometry propagation off.
Since you are using grid to manage the widgets internal to the frame, you need to use grid_propagate(False) to turn geometry propagation off for that frame:
frame.grid_propagate(False)
By doing so, you're responsible for setting the initial width and height of the widget, though you could leave propagation on to get the initial size, then turn it off with the button click in order to work around that issue.
There's an interesting bug (or feature...) in that if you set the width and height to zero, Tkinter won't redraw the window. At least, it doesn't on the Mac. I don't recall the workaround for that because I never, ever need to set a widget to a zero size, but setting it to 1x1 pixel makes it nearly invisible.

Categories

Resources