I currently have a scrollbar and a canvas on the same hierarchical level. In the canvas, there is a frame created using the canvas' create_window method.
I have a binding that is called when the canvas is configured that will resize the scrollregion to fit bbox("all"). It works, but ONLY when the entire window is resized (e.g. If I add more widgets to the canvas that are now not in its visible region, I have to resize the window to be able to change the canvas' scrollregion).
Ideally, the scrollregion should change as soon as the new widget is added to a nonvisible location of the canvas (e.g. it's off the screen). What am I currently doing incorrectly? Any advice is appreciated!
If I am reading your mind correctly (you really need to include a Minimal, Complete, Verifiable Example with debugging questions!), you are recalculating the scrollregion only on receipt of a <Configure> event. That only triggers when the widget changes size - and calling .create_window() on a Canvas certainly doesn't change its size. The simplest solution would probably be to explicitly do the scrollregion recalc yourself, every time you add widgets to it (there's no event that is triggered by this action, as far as I know). You might need to call .update_idletasks() first, to give the newly-added widget a chance to calculate its own size.
You need to put a binding on the inner frame's <Configure> event to also reset the scrollregion.
Related
I've always found the pack() geometry manager quite ambiguous in terms of how it acts when widgets are added.
Here I have a simple code for creating a new frame within a much bigger parent frame. The frame size has been set to 300x300. The problem is that if I create a label with the pack() geometry manager within this frame, it will suppress the original frame size. Basically the frame will become as big as is the label.
If I use the place() geometry manager, then there is no problem and the frame stays at the original 300x300 size.
The question is - why does packing a label within the frame affects its size? And then what is the best way to avoid this problem and have everything fixed at the size as they are set?
class MainRightFrame(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.place(x=600, y=0)
self.config(height=300, width=300, bg='green')
label = Label(self, text='Left Frame')
label.place(x=10, y=10) # OPTION 1
# label.pack() # OPTION 2
why does packing a label within the frame affects its size?
Because that is how the packer is designed to work. It will shrink or grow to fit its contents, which is what you want 99.99% of the time.
For the canonical documentation for how pack works, see the official tcl/tk documentation here:
The packer algorithm
And then what is the best way to avoid this problem and have everything fixed at the size as they are set?
The best wait to avoid this "problem" is to use place. However, the way both pack and grid works makes it much easier then using place to create a responsive UI that can handle changes in font size, resolution, and the user manually resizing the window.
In over a couple decades of writing GUIs with python/tkinter and tcl/tk, I have never used place except for extremely special circumstances. Its simply too difficult to use for must common layouts.
If you absolutely insist on using pack or grid without this "shrink to fit" behavior, you can pass a false value to the pack_propagate or grid_propagate method of the containing frame (eg: self.pack_propagate(False)). In my experience this is very rarely the right solution.
To fix this, add the following line after the line beginning: self.config(...:
self.pack_propagate(0)
See here for a documentary explaining this.
As #KārlisRieksts noted, this approach does not work however if the frame (or other parent widget) is packed with place() geometry manager. The child widgets will then affect the size of the parent.
In Tkinter, resizing a canvas and/or frame can be done using
canvas.pack(fill="both", expand=True)
This way I can drag the tkinter window with the mouse and the canvas and frames within will adapt to the new size.
However I have not found a solution for applying this to images within the canvas. Only solutions so far are to independently change the size of the images through event actions.
Is there any way to make images within a canvas to resize dynamically, just like the canvas does with the one-liner above?
Is there any way to make images within a canvas to resize dynamically, just like the canvas does with the one-liner above?
No, there is no way to do what you want. Images aren't like widgets which can automatically grow and shrink. You will need to set up a binding on the <Configure> event of the containing widget, and in the bound function you will have to convert the image to the desired size.
Ideally, the transparent border.
Here's an example of what i'd like to achieve:
Notice the transparent border.
Now i suppose I could use cairo to create a rectangle with transparency, and put a borderless non-transparent window inside, mimic'ing that effect - which I would if i knew the window would have a fixed dimension. However, if the inner window grows, it'll grow out of the transparent rectangle.
How should one approach such task?
Making window frames is really the job of the window manager (at least under X11, don't know how it works on windows).
But have a look at the GtkBin, GtkBox or GtkMisc widgets. Pack the dialog inside it as a single widget, and use padding to give it a size. Read up on GTK+ drawing model. You will probably need to set a flag and define your own expose-event handler to re-draw your frame.
I have been making a small program with the Tkinter module in python, and I was wondering whether it was possible or not to resize a frame in my program with the mouse. As in, the user can drag the frame border and it will resize itself.
Your use of terminology makes the question unclear. Windows which may be resized by the user are called Toplevel windows. These are what appear as rectangular windows on the display, with a frame around them, typically a title bar, and edges or corners that can be grabbed and resized.
The term Frame refers to a container widget that must be inside a Toplevel or one of its descendents. A Frame has the ability to be resized but you have to write the code to let you interactively resize them. For example, you could place a little grip widget in one or more corners, and writing bindings to the press, motion and release of a mouse button.
Depending on the effect you are looking for, you might want a PanedWindow which is a container that includes a sash that lets you adjust the proportion of space between two other widgets.
What is the best way to have transparency of specific widgets in a PyGTK application? I do not want to use themes because the transparency of each of the widgets will be changing through animation.
The only thing I can find is to use cairo to draw widgets with an Alpha, but I can't figure out how to do this. Is there perhaps a better way to do this as well?
Thanks!
Assuming that your program runs under composition manager, you could get per-widget transparency by manipulating widget's X window. Look at gtk.gdk.Window.set_opacity().
Note, it is not gtk.Window; you can get this object by getting its window property (buttonWidget.window), but only when widget is realized and only when widget does handle events -- gtk.Label does not have its own X window for instance.
If you need to work also when you don't have composition manager, drawing your widgets by yourself is the only option -- but you don't necessarily have to use cairo; drawing pixel by pixel on the bare X window will also work.