Automatic layout when widget space is finite in Tkinter - python

I am trying to achieve the following effect using a Tkinter python app:
The user can define a finite number of list elements, aka categories.
I then would like to present these categories next to each other, based on the following approach:
l=Label(self.body,text='Category: ')
l.pack(side=Left)
for i in range(0,len(self.categories)):
l=Label(self.body,text=self.category[i])
l.pack(side=LEFT)
self.body.pack(fill=BOTH)
Of course, this does not work. Is there an elegant way to "wrap" a whole label at the widget borders?
Thanks!

You have to know the size of the frame you are using to pack the labels into, and the width of the label. You can set the width parameter for the label, but it uses a size that depends on the font used i.e. the same "width=" results in different label widths for different font sizes. So it can not be done with the code you posted. Link to label parameters http://effbot.org/tkinterbook/label.htm

Related

How can I make a tkinter canvas hold an image much greater than the available screen size?

I'm attempting to adapt martineau's excellent answer on how to use tkinter to highlight and select an area of an image with a mouse. My goal is to modify the code to support huge images, such as 10000x6000 pixels or more!
This is my first attempt at using tkinter, and it's much more challenging than expected.
The three options which I've considered and experimented with are:
Load the image, then scale the image to the size available in the window before placing it on the canvas. This in turn requires that I know the scale factor, so I can reverse the scaling when operating on the original image.
Add scrollbars to the side/button on the visible part of the image in the canvas. (My preferred option).
Don't add scrollbars, but use the cursor keys to scroll the visible part of the image in the canvas.
I've tried to do all of them, but ran into various kinds of trouble:
I used root.state('zoomed') to maximize the window, then placed a button to top of the window using tk.Button(...).pack(fill=tk.X) before placing the canvas as in the linked code using self.canvas = tk.Canvas(...). At this time I discovered two issues: It turns out that I can't maximize the canvas to the remaining space in the window using self.canvas.pack(fill=tk.BOTH) (it only expands the width). Another more crucial issue was that I could not read the actual width/height value that the canvas was expanded to, (or get there available space in the window before placing the canvas), and without these values, I can't calculate the scaling factor. :-(
I tried to follow various methods of adding scrollbars to the packed canvas but they all, with one exception, required to use the grid method and I quickly found that pack and grid methods were conflicting methods. After several attempts at rewriting the code to use the grid method, I gave up. The place method seemed promising, except that it will require me to size the canvas manually and then place the scrollbars at calculated offsets to the canvas... and all of this required that I have the same values that were needed to calculate the scaling factor above. :-(
I didn't get very far with this, as it seems I can't get (keyboard?) binds to work at all (On windows with Python 3.10.6). Shouldn't something like self.canvas.bind("<Right>", lambda event: print("Ping")) followed by self.canvas.focus_set() (perhaps with root instead of the canvas) work?
I'm sure I'm overlooking something basic, but after a few evenings looking at this I've gotten nowhere. :-(
I hope some of you can provide help and/or pointers allowing me to get further.
Ohh, for completeness, I'm trying to hack together a small tool that does the following:
On startup requests and load an image file. (Adding a button to perform the load/re-load is nice to have, but not strictly needed. )
Display the image file and allow an area of the image to be selected with the mouse.
Perform some software analysis on the selected part of the image when a button is pressed.

How to set my widgets' size and padding dynamically to fit window in Tkinter?

I am new to Tkinter and still learning. My desktop resolution is 1366x768 and I am developing for an environment which is 2048x768. Right now I am setting the window resolution by detecting it like this -
w = main_container.winfo_screenwidth()
h = main_container.winfo_screenheight()
main_container.geometry(str(w) + "x" + str(h))
Now I have several screens and I cannot use grid on each and every screen. Like I have a Login Screen in which I have a Frame like this-
self.frame_background = tk.Frame(self.frame_parent, bg='#ffffff')
self.frame_background.pack(fill='both', expand=True, padx=100,
pady=100)
This is just an example of one widget. Since values for padx and pady are fixed with 100, if I am running my application on a 640x480 resolution device, the layout gets too stretched and almost nothing is visible inside this frame.
How can I set these padx and pady and other width and height values dynamically according to the screen size and resolutions?
Now I have several screens and I cannot use grid on each and every screen.
Why can't you? There's nothing preventing you from using grid on every screen. Though, it's actually quite common to mix and match pack and grid in different frames, and arguably a best practice.
Like I have a Login Screen in which I have a Label like this...
The code following that statement doesn't have a Label, so it's hard to know what you are trying to do.
if I am running my application on a 640x480...
First you say you have a desktop resolution of 1366x768, then say you are targeting 2048x768, and are now asking about 640x480. That's a pretty wide range of values. If you have to support something as low as 640x480 you definitely should not be hard-coding padding to such huge values. Typically padding is never more than one or two. Tkinter apps can be made to accommodate that wide range of screen sizes, but that relies on not hard-coding the size of widgets and padding as much as possible.
How can I set these padx and pady and other width and height values dynamically according to the screen size and resolutions?
Generally speaking, you shouldn't do that. The general rule of thumb with tkinter is that you make the widgets the smallest size they need to be and let the geometry managers worry about stretching or shrinking them to fit the available space. There are a few exceptions to that rule, but in general, that rule works quite well.
Unfortunately, geometry management questions are hard to answer without knowing more about what you're trying to do. For example, we need to know why you think you need padding of 100 pixels. That seems highly unusual. Plus, we need to know what else is in your frame, what your frame is in, and so on.
My advice is to remove the padding, or set them to very small values. Then, make sure you use all of the geometry manager options that are available to you, such as fill and expand with pack, and sticky and others for grid.

Force label line wrap

I'm using a Gtk.Label within a tooltip to display text. The text is usually rather short, but does occasionally become very long, in which case the label expands horizontally to fill the entire screen width, which results in a ridiculously wide tooltip. Is there a way to force the label's text into more lines?
I had two ideas:
1) set the label's maximum width. Gtk doesn't seem to support this.
2) set the label's maximum line length. Gtk doesn't seem to support this either.
Which means I'm fresh out of ideas. Is there any way to do this?
Use gtk.Label.set_line_wrap combined with gtk.Label.set_max_width_chars.
Example:
label.set_line_wrap(True)
label.set_max_width_chars(20)

Make width of various widgets correspond with treeview columns

As an example, I have an entry, and several optionmenus located below a treeview widget. I am using the grid manager, and the treeview has a columnspan equal to all the widgets along it's lower side.
Since specifying the width of an entry or an optionmenu is in characters (the width in px of those characters is in turn based on the font size/family chosen for the widgets), and specifying the width of a column in a treeview is in pixels, how can I calculate the lengths of both a column and the widget underneath it so that they are visually linked by their positions (the length being the same)?
I found a great example of treeview. It might help to provide some insight. Here is the link
Create a table using treeview with control of column widths

How to make matplotlib:pyplot resizeable with the Tkinter window in Python?

I am trying to build a grid of frames in each there is a matplotlib figure.
When I resize the window the figure remain with fix size and are not resizing to fit the empty space.
Is there a way to make the figure change its size according to the canvas (hopefully that it does change with the window size)?
This is how I do the embedding in each frame:
self._figure = pyplot.figure(figsize=(4,4))
self._axes = self._figure.add_subplot(111)
self._canvas = FigureCanvasTkAgg(self._figure, master=self._root)
self._canvas.get_tk_widget().grid(row=1,column=1,rowspan = 4)
This is most likely related to this question. The gist is that there are two parts to making a Tk grid cell grow:
Use the sticky keyword when applying grid to your widget, e.g., widget.grid(..., sticky=Tkinter.NSEW (Python 2.7) to make widget be able to grow in all four directions. See this documentation for more details.
Tell the parent/master to make the respective column/row grow when resizing by calling parent.grid_columnconfigure(...) and/or parent.grid_rowconfigure(...) with the desired row, column, and weight keyword. E.g., parent.grid_columnconfigure(col=0, weight=1) makes the first column take all available space (as long as there are no other columns, or they have not been similary configured). See the grid_columnconfigure documentation and the grid_rowconfigure documentation for more details, e.g., about how the weights affect multiple columns/rows.
This page contains many more details about grid layouts.

Categories

Resources