I have a Widget that is huge (80,000 px long maybe? 800 elements at 100px each) because it lays out many smaller widgets. I've put the huge widget into a QScrollArea. But the scroll area still renders the entire widget. This causes manipulation of the widget to be choppy, and I want things to be smoother.
Instead I want the QScrollAea to be intelligent enough to only render the elements that I know will be displayed. (The elements are ordered and are all the same fixed size, so this computation should be fast)
What's the best approach to go about this? Should QScrollArea already be doing this?
Does QListView already implement this functionality? (But I want my own custom widget in there it has buttons that interact with the user, QListWiget doesn't cut it.)
Have you considered using a QGraphicsView? This allows scrolling in addition to efficient rendering of only the visible objects (and plenty of other benefits such as hit testing).
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.
So I am curren]tly working on an app for image processing. I am using PyQt5 for this purpose. You can see how it looks like now on the picture below. My question is, what is the best way to make it responsive, meaning, if I resize the window, all the widgets will rescale as well. Right now I am using some groupboxes, Hlayouts, VLayouts.
Only thing that comes to my mind is to create a gridlayout, though I would like to know, if there is by any chance any other possibility how to easily do it, since there is quite a lot of widgets.
Also, I would like to ask about GroubBox widget. Down left I have four buttons which are in one groupbox whose border is set to none by self.tableButtonsGroupBox.setStyleSheet("tableButtonsGroupBox {border: none}"), but there is still visible the upper line. Is there way to get rid of it?
Thank you for suggestions in advance!
I wanted to know if anyone knew where to start in terms of recreating this sort of functionality?
http://www.learningnuke.com/wp-content/uploads/nukewipepreview.png
In the picture you can drag the centre line to reveal Image A or Image B or parts of each, interactively.
I want to be able to wipe/reveal across two images, maybe it's possible doing some sort of interactive crop of sorts.
Wanting to add this feature to a window in Maya, so maybe with QT, but not essential.
Just some pointers would be great.
I can tell you that this is possible via Qt/PyQt in maya. You can create a dialog that displays QPixmaps with some form of mouse interaction to control their display. I would forget about trying to extend the actual Render View as this would be a pain in the ass.
Just focus on a Qt solution. Unfortunately beyond this, I'm not sure what more I can offer unless you have a specific question about its implementation.
I would probably stack the QPixmaps on top of each other inside of custom QLabel widgets. The QLabel would have a custom mousepress/move event that would resize maybe the right edge to simulate the wipe effect, and reveal the one stacked underneath.
Also, it does resemble the functionality of a QSplitter so that might also work, with an image on each side of the layout and a custom style to the split bar.
This is about wxPython.
I would like to have 2 Panels laying one over the other:
PanelBG should be some sort of a "background", with its own GridBagSizer with subPanels, StaticTexts and so on;
PanelFG should be the "foreground" panel, also with its own GridBagSizer with some StaticTexts, Buttons... but a transparent background, in such a way that PanelBG is visible wherever PanelFG doesn't lay widgets.
I need both Panels to stretch to all the sides of the frame, even when resizing the window, though never changing the reciprocal proportions, that's why I'm not sure if there's a way to use absolute positioning.
In case you are wondering, the reason why I don't want to use a single Panel is that merging the 2 GridBoxSizers would require me to place many many more cells in the sizer, because rows and columns of foreground and background don't always coincide, and I should split them in many cells, with grid dimensions growing up to hundreds**2.
Since the content I want to put in the foreground needs to be updated and refreshed quite often, this would require redrawing all the cells every time, which would take 10 - 20 seconds to complete the operation (tested). Updating only the foreground would require just some hundredths of a second instead.
Thank you!
This would be at least partially a change of direction, but it might be worth examining what other rendering options you have.
In particular, I'm thinking of wxWebKit (http://wxwebkit.kosoftworks.com/), which would let you do layering, etc. using the WebKit browser rendering engine. I'm not sure whether it's at a stage that would provide everything you need since I haven't actually used it, but even if it doesn't work then it may be an approach worth trying - using HTML/CSS for part of your display, while wrapping the whole in a wxPython app.
As I understand it, this is a calendar with rectangles for the days containing the events for the days.
The simple thing would be to use a wxGrid, with seven columns and four or five rows, to represent the months. You would then place the events into the grid cell for the correct date. The wxGrid widget would look after the details of refreshing everything properly.
Using wxGrid you might lose a little control over the exact appearance, though wxGrid is very flexible and feature rich once you learn its many methods, but you would save yourself having to write large amounts of code that would require significant effort to debug.
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.