tkinter window not wide enough to display window title - python

Is there a 'standard' way of ensuring that the displayed window is wide enough to display the window title?
import tkinter as tk
root = tk.Tk()
root_f = tk.Frame(root)
root.title('Long Window Title Containing Much Text')
text_f = tk.Frame(root_f)
text_l = tk.Label(text_f, text='Short text')
root_f.grid()
text_f.grid()
text_l.grid()
root.geometry('+{}+{}'.format(100, 100))
root.mainloop()
root.quit()
When I use the winfo method to get the width of the root (or text) frames they give the size of the text not the size of a window wide enough to display the whole window title.
I know it has to be something simple, but I can't see it.
Thanks

No, there is no standard way. Tkinter has no way of knowing how long the title is on the titlebar. The OS / window manager has completely control of that portion of the window and doesn't expose any platform-independent way of getting at that information.
You would have to know not only the font used by the OS for window titles, but also whether there were any other decorations (eg: buttons, images, etc) that appear in the title area.
If you're fine with making assumptions that the font is the same as the default tkinter font, you can use tkinter's ability to measure the length of a string in a given font with the measure method of a font object.

Related

Python: Having trouble using .bind() on anything not involving the mouse

I can make a basic python application like so:
from tkinter import *
block = None
def moveUp(event):
field.move(block,0,-50)
root = Tk()
field = Canvas(root, width = 300, height = 300, bg = 'light blue')
field.pack()
block = field.create_rectangle(100,100,110,110)
field.bind('<Button-1>',moveUp)
mainloop()
and it will behave just like you would expect. It creates a square on a Canvas and moves that square up 50 pixels every time you click in the Canvas.
However, When I replace
field.bind('<Button-1>',moveUp)
to, for example,
field.bind('<Return>',moveUp)
the square does not move, no matter how many times I press the Enter key. This problem persists for any kind of keyboard input (e.g <space>, etc), but any input involving the mouse is fine.
Any input at all is appreciated. Thanks!
The field does not have focus, and therefore does not capture the keypress. One option is simply to make the binding more general:
field.bind('<Return>',moveUp)
to
root.bind('<Return>',moveUp)
Another option is to set the focus to the field:
field.bind('<Return>',moveUp)
field.focus_set()
Not entirely sure what's the reason, but it seems to work if you use bind_all instead of bind.
field.bind_all('<Return>',moveUp)
My guess is that using the keyboard, the canvas does not have focus and so does no register the event. Using bind_all, the event is registered when any widget of the application has focus.
See here for some information on levels of binding.

Tkinter root configuration

For adding a title to the TKinter root, we do something like:
root = Tk()
root.title("<Title Text>")
root.configure(bg = "<color>")
My question is how do we change the font size and font color of the Title Text. Seemed to me to be a simple requirement, but other than changing the background color of root, I don't seem to be able to do anything more.
Many Thanks
You can't change the title font or size via tkinter. Tkinter has no control over how the window manager / os decorates the program.

Tkinter box issues- Entry, Labelbox, Text all take up space from side to side, grid crashes computer

I'm using a tkinter canvas and trying to make a chat box on the right side of my game. However, I found that when I do...
import turtle
import tkinter as tk
master = tk.Tk()
w = tk.Canvas(master,width=1155,height=600,cursor='cross_reverse', bg='#101010')
shift = 1.000
sc = turtle.TurtleScreen(w)
tu = turtle.RawTurtle(sc)
e = tk.Entry(master, bg = '#000', fg = '#03f', font = 'Courier', justify='right', insertbackground = '#101010',width='115')
lb = tk.Listbox(master,height=3)
#e.grid(row=3,column=3)
sc.bgcolor("#101010")
txt = tk.Text(master,state="disabled")
txt.pack()
lb.pack()
w.pack()
sc.tracer(100)
drawcontinents() #Draws stuff with turtle, works just fine
e.pack()
tk.mainloop()
... a few things go wrong.
1.Text and Entry do not seem to want to coexist. I seem to be only able to have one or the other. My plan was to use entry as a chat entry, and display messages in Text. My backup plan is to append messages to label.
2.Text, entry, and Label box take up the entire window in whatever rows they are in, which blocks out the rest of what I am trying to draw. In other words,it puts the text box in the center, with a big gray stripe from side to side across whatever I've drawn. Is there any way to just display the box, and put it to the right?
3.Whenever I try to use the grid system, my whole computer freezes and I have to restart. Is this because the program is taking up more space than I have available, or is this a known bug or problem with installation?
You cannot use both pack and grid at the same time for the same containing widget (ie: for all widgets inside the same frame, toplevel or root window).
What happens is this: grid lays out all the widgets, potentially changing the size of some widgets based on your options (ie: it may grow a widget to stick to the sides of the cell). pack then notices that some widgets changed size in the containing widget it thinks it is responsible for, so it redoes what it thinks is the proper layout. This may change the size of some widgets based on your options. grid then notices that some widgets it thinks it is responsible for change size so it redoes what it does, potentially changing the size of some widgets. pack notices and re-adjusts, grid notices and re-adjusts, pack notices, ... until the end of time.
The solution is simple: only use grid, or only use pack, for all widgets that have a common parent. In this case, all your widgets share the root window as their parent, so they all need to use grid, or they all need to use pack.

tkinter's .pack_propagate() method

I am experimenting with Tkinter, as I was trying to figure out is there a way to set the tkinter's window size without using canvas. I came upon this how to set frame size question on SO's Question & Answer. So I went ahead and test it by writing a very small program to display a text label. But I found out it is "missing", or disappear when I use frame.pack_propagate(0)
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root, width=400, height=400)
# Does not work at the moment, textBox is missing
# frame.pack_propagate(0)
frame.pack()
textBox = tk.Label(frame, text="(x,y): ")
textBox.pack()
root.mainloop()
So my question is, can you explain why my textBox (Label) is not appearing when I use the frame.pack_propagate(0) instead of frame.pack() method? And secondly, is there a way to set the window size without using a canvas? I want to know because I am writing a series of small programs to teach my friend about tkinter, before introducing canvas to him. It would be nice if the window size are all the same across my tkinter samples. And I am just wondering as well (curious). Thank you very much.
I am using python 3.2.2 on MAC OS 10.5.8.
pack_propagate only sets a flag, it doesn't cause the frame to be placed in the widget. It is not a substitute for calling pack.
In other words you must do this:
# put the frame in its parent
frame.pack()
# tell frame not to let its children control its size
frame.pack_propagate(0)
# put the textbox in the frame
textBox.pack()
To answer your second question: Yeah, there is a way.
tkinters Tk do have the Tk.geometry function. When you just call it without arguments, you will get the current geometry in form of 'widthxheight+x+y', so for example (on Windows 10) '200x200+26+26' when you create your first Tk window. Using that format you can resize the Tk by, e.g., writing: root.geometry('400x500+60+60') to set the width to 400, the height to 500 and place it at the coordinates (60|60).
This works for Tk alswell as for Toplevel. But Toplevel also takes the arguments height and width when initialized or configured. If you want them to keep their size when packing something inside just use root.pack_propagate(False) on them.
By the way there is something similar for the grid manager: root.grid_propagate(False)

Randomly add buttons to Tkinter GUI?

How do I randomly add buttons to a Tkinter GUI? I need it to be able to create a button, then put it anywhere on the window, is this possible? I am using Python 2.6 on Windows.
If you want random button placement (or anything not aligned along a grid, etc.), you can use the place geometry manager. Depending on platform, overlapped buttons may not behave as you expect, though, so you may want to avoid them.
Here's a simple example:
from Tkinter import *
from random import random
root = Tk()
frame = Frame(root, height=200, width=200)
for i in range(10):
Button(frame, text=str(i)).place(x=random() * 150, y=random() * 180)
frame.pack()
root.mainloop()
There are several options to choose from. For example, you could design on a grid where you have six buttons per row. Then it's just a matter of starting at row 0, incrementing the column for each button. When you get to the last column, reset the column to 0 and increment the row by one.
Another option is to use a text widget as the container, and embed your buttons in the text widget with wrapping enabled. With this trick the buttons will fill a row automatically and wrap if the user grows or shrinks the main windows. It's a tiny bit more work, but it works well if that's the behavior you want.

Categories

Resources