Question
I have created several GUI projects so far, but they all have one fatal mistake. When I make a window smaller, (which usually uses only one frame.) several of the widgets will disappear. Is there anyway to make the widgets 'aware' of the size of their frame?
What I have tried so far
I have tried to use this:
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
to specify the size of the window, but since many widgets use values other than pixels, it never works. I am also unsure as to whether it updates constantly or only when the window is spawned. (Text uses the size of the characters... etc)
Specs
Python 2.7.3
Windows 7/ Mac OSX Lion
This is generally quite easy, and often just happens by default. It all depends on how you use pack and grid. Without seeing your code it's going to be hard to give you useful information.
Can you show us a really small program that illustrates the problem and is an accurate indication of how you lay out your GUIs?
Related
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.
im doing an tkinter app in a computer, im using the grid() method to place the widgets. At first of the program i use this code to make the window size like the screen size:
an = self.root.winfo_screenwidth()
al = self.root.winfo_screenheight()
self.tam = '%dx%d'%(an,al)
self.root.geometry(self.tam)
And it works, but this app will be used through a remote desktop with different devices (different screen sizes).
How can I do that the widgets fill on the window like the original design? Thanks
Without any concrete examples of your code, there's no way to give more specific advice than to say that the solution is to design your program so that it resizes well.
Tkinter excels at making widgets fit, so as long as you use the options at your disposal (fill and expand for pack, row and column weights and other options for grid), and you don't hard-code any widths and heights, your GUI will easily work on a variety of systems.
Concrete pieces of advice:
don't use place except in very rare circumstances. While place supports relative positioning and sizing, it requires more work than pack and grid
design the GUI to work on the smallest display possible, and then make sure that when you manually resize the window it behaves properly
When using grid, make sure you always have at least one row and one column with a non-zero weight so that it knows how to allocate extra space
When using pack make sure you use expand and fill properly
Don't turn off the ability for the user to resize the window
I am experimenting with the sample code in the kivy_examples package. On a Macbook Pro with a Retina display, that is also connected to an external monitor with standard pixel density.
When I launch any of the example apps, the window first appears on the built-in Retina display and looks fine. When I then drag that window over to the external monitor, suddenly all of the widgets blow up in size.
There are a number of existing StackOverflow questions which deal with Kivy and pixel density. But the questions and answers all seem to deal with single-screen use cases. You don't know what the density of your target screen might be, so here's how to use the dp(...) function to configure for that screen at application startup, etc.
However, I can't find any discussion that deals with a multiple-monitor use case. Is there any way to have a Kivy app respond dynamically to pixel density changes, as the app is moved around between multiple monitors? As opposed to just configuring for a fixed density level at startup time?
When a User opens a particular tab inside the QMainWindow of my PyQt4 driven GUI,
the window needs to be automatically resized so that the contents of this particular tab will fit.
As you know, when using Qwidget.resize(), the Window (by default on PC) is instantly resized.
This isn't easy on the eyes and would probably surprise / confuse the User.
Is it possible to have the window smoothly transition into the new window size?
(An animation in essence)
(For instance, a really horrible method would be to continuously call resize, each time slightly increasing the window size to elude to a transition)
The window size is not adjustable to the User, so when the window exands and shrinks to and from the different sizes, I know their exact dimensions. It is also known to me that all my Users run Windows 7 (Since my users are school mates in a tablet program).
Does anybody know if this is possible with PyQt4, and how to achieve it?
(Qt Kinetic sounded relevant to me, but it's proven difficult to search for the appropriate information)
Thanks! x 100
Specs:
- PyQt4
- Python 2.7
- Windows 7
There is QPropertyAnimation which can be used to animate QObject properties, including the size of your window.
I'm not sure if it will work well performance wise, since it will call resize() perpetually, as you say, but it seems like that is what you want.
What you could maybe do is to resize the window, but somehow disable painting (i.e. override paint()) during that animation, so that only the frame is smoothly resized (should be ok) and the interior is not redrawn until the target size has been reached.
I want to put a Canvas with an image in my window, and then I want to pack widgets on top of it, so the Canvas acts as a background.
Is it possible to have two states for the pack manager: one for one set of widgets and another for another set?
The answer to your specific question is no. You can't have two states or otherwise use pack two different ways in the same parent.
However, what I think you want to accomplish is simple. Use the built-in features of the canvas to create an image item that is part of the canvas, then pack things into the canvas as if it were a frame.
You can accomplish a similar thing by creating a label widget with an image, then pack your other widgets into the label.
One advantage to using a canvas is you can easily tile an image to fill the whole canvas with a repeating background image so as the window grows the image will continue to fill the window (of course you can just use a sufficiently large original image...)
I believe that Bryan's answer is probably the best general solution. However, you may also want to look at the place geometry manager. The place geometry manager lets you specify the exact size and position of the widget... which can get tedious quickly, but will get the job done.
... turned out to be unworkable because I wanted to add labels and more canvases to it, but I can't find any way to make their backgrounds transparent
If it is acceptable to load an additional extension, take a look at Tkzinc. From the web site,
Tkzinc (historically called Zinc) widget is very similar to the Tk Canvas in that they both support structured graphics. Like the Canvas, Tkzinc implements items used to display graphical entities. Those items can be manipulated and bindings can be associated with them to implement interaction behaviors. But unlike the Canvas, Tkzinc can structure the items in a hierarchy, has support for scaling and rotation, clipping can be set for sub-trees of the item hierarchy, supports muti-contour curves. It also provides advanced rendering with the help of OpenGL, such as color gradient, antialiasing, transparencies and a triangles item.
I'm currently using it on a tcl project and am quite pleased with the results. Extensions for tcl, perl, and python are available.
Not without swapping widget trees in and out, which I don't think can be done cleanly with Tk. Other toolkits can do this a little more elegantly.
COM/VB/MFC can do this with an ActiveX control - you can hide/show multiple ActiveX controls in the same region. Any of the containers will let you do this by changing the child around. If you're doing a windows-specific program you may be able to accomplish it this way.
QT will also let you do this in a similar manner.
GTK is slightly harder.