Scrollable background with resizable Qt widgets on it - c++

I would like to create a Qt window that
can be scrolled/panned by dragging its background (scrollbars should not be shown)
contains multiple sub-widgets at defined locations (which scroll with the background)
the sub-widgets can be resized by pulling their border
What I managed so far is to create a QGraphicsView with setDragMode(QGraphicsView::ScrollHandDrag) http://doc.qt.io/qt-5/qgraphicsview.html#dragMode-prop. I then placed the sub-widgets on a QGraphicsScene, however, this didn't allow the sub-widgets to be resized by pulling their border.
I also tried to inherit my custom sub-widget class from QDialog, which allows setSizeGripEnabled(true). However, this doesn't resize their content, and QDialog is probably not meant to be part of a QGraphicsView.
Any suggestions? It would also be ok if the sub-widgets behave like sub-windows that can also be dragged at their title bar, as long as they cannot be closed and they move when the background is dragged.

You can look aside QMdiArea class (Qt documentation: QMdiArea). By problem description it is what you need.
Of course, you can use Graphics View Framework, but, i think, it will be more difficult. If you choose such approach, very useful will be class QGraphicsWidget (Qt documentation: QGraphicsWidget).

Related

How disable window move inside an area?

I'm trying to write a circuit designer software in QT on Linux. I'm using KDE 5 Plasma desktop and QTCreator as an IDE.
I tried to use QFrame paintEvent to paint on it, and it worked, but when im grabbed the window inside QFrame it moved.
I know about QGraphicsView, but i cant make a custom class and promote it based on that(it's not listed).
How can i create a custom class from a container(QFrame, QGraphicsView or anything) where i can override paint event and also it doesn't move window if i grab it?
Sorry for my poor english.
QGraphicsView inherits from QAbstractScrollArea which inherits from QFrame itself.
So you can keep the QFrame in the form, and keep it promoted to your canvas class, but simply make you canvas class inherit QGraphicsView instead.
Although, my Qt has two differences in behavior from the OP (but I don't use KDE):
Clicking on a QFrame and moving the mouse doesn't move the whole window for me. I guess this behavior for the OP could be changed by reimplementing void mousePressEvent ( QMouseEvent * event ) in the canvas class and giving it an empty code instead. (doc)
I can put QGraphicsView in my ui files, and I can right click on them to promote them to another custom-defined class.
Edit: Found the reason why the window moves on KDE!

Implementation of gui designer

I'm interested in making my own small gui designer for learning purposes in Qt. Just basic drag and drop from left panel which would have controls, to right panel on which they could be selected, moved, resized and have their properties changed (name and such) and eventually (if selected) be lined up.
I would use QGraphicsScene as the right panel cause it already has selecting and moving implemented. But how would I implement resizing? And then how would I generate a QWidget class with controls at same positions? Or is there an easier way?
What would be the best way to implement all of this? All suggestions are welcome and keep in mind that it won't be complex as Qt designer.
You need to define some widgets, which are going to be dragged from the left panel -maybe a tree view with icons- and dropped to the scene.
These widgets should inherit from QGraphicsWidget. You can also inherit QWidget and put the widgets into scene via QGraphicsProxyWidget. They can be resized by highlighting corners and overloading the mouse events. Please check out corner grabbers and sizable box examples. Also check out QSizeGrip. It is the resizing grip of any QStatusBar.
Property panel is the easiest, you should list the properties of the clicked item. To line up, you can reinvent the wheel and write a layout maker class, or simply use QGraphicsLayout and highlight the layout on your interface. Ctrl+left click should select multiple widgets, a layout button should layout them programmatically, and a bounding rectangle item should be drawn.

Enlarge a Qt widget so it might cover other widgets

I have a complex layout of widgets in widgets in widgets in a QMainWindow. In one of them I have an image, it sits in the corner. What I would like to achieve is following: if the image is activated (e.g. clicked upon), it should be enlarged, so it might overlap other widgets, or parts of other widgets. The problem is, I still would like it to remain in the layout, but in a way that everything else remains in its original size and position.
I was thinking about having an empty but similar size widget as a "placeholder", and have the actual resizable widget float on top of it. My problem is, that it does not guarantee that it stays in its position if the main window is resized, maximized, etc. Is there a better or more efficient way to do it?
One way to do it, if the widgets to be overlapped are in the same layout than the one you want to enlarge, and the policies for that widget allow it, is just .setVisible(false) in the other widgets. The widget that remains visible should resize to cover all the available area!
If I can't find a better solution, I think I'll do the following:
The MainWindow will have no layout, just two QWidgets on top of each other. The bottom one will contain all the layouts and everything else, while the upper one will have a transparent background and the resizable widget, maybe supported with a number of spacers.

How to paint with QPainter only after a specific event?

I have a main window with some widgets on it, each needs its own graphic. I would like to use QPainter to draw shapes, lines, etc. on them, but only after a specific event, like the press of a button.
The problem is, if I just create a QPainter in any function, it won't work:
QPainter::setPen: Painter not active
The QPainter methods can only be called inside a paintEvent(QPaintEvent *) function! This raises the following problems:
I have to derive my custom classes for all the widgets I would like to paint on, so I can't use the Designer to place my widgets. This can get frustrating with a large number of widgets.
The widgets redraw themselves after each paint event of the window, like moving it around, or moving other windows in front of it. I do a lot of drawing in those widgets, so they will visibly blink in these cases.
Is there a better and simpler way to solve this? I started to think about just displaying images, and re-manufacturing those images only when the specific buttons are pressed. I doubt that it's the most elegant solution...
You can use custom widgets in the designer: Creating Custom Widgets for Qt Designer.
Qt Designer's plugin-based architecture allows user-defined and third party custom widgets to be edited just like you do with standard Qt widgets.
For your second question, one of the approaches is to create a QPixmap for each of your widgets. When your widget's appearance needs to be changed, you draw in that pixmap (using QPainter's constructor that takes a QPaintDevice - QPixmap is a QPaintDevice).
In your widget's paintEvent function, you simply fill your widget with that "cache" pixmap. This way, you only do the (potentially expensive) painting when it's actually necessary.

How should I use a QGraphicsScene with layouts and widgets

I'm creating some graphic data displaying widget in Qt4 and I was tempted to use the QGraphicsScene for it, create QGraphicsItems for the data items etc.
However, I wanted to add some layer of controls (eg. scrollbars, zoom+other buttons - I want to make it in a similar style as eg. Google Maps, that is, the data would be displayed all over the widget, and the buttons would be shown atop of them) to the widget. So I thought it might be feasible to add them to the scene (perhaps as a child of a QGraphicsGroupItem that would be shown over the data). But I want them to move & resize when I resize the whole widget, so I should use a QGraphicsLayout for managing them. But at this point, I discovered things are pretty complicated.
The problem is that when using QGraphicsLayout, the following constraints hold:
Only a QGraphicsWidget can be managed by a layout
QGraphicsLayout can only be used to manage children of a QGraphicsWidget
Which means that I would have to create my controls as QGraphicsWidgets, add a top level QGraphicsWidget to the data widget, and manage the size of this top level widget myself.
So I want to ask:
Wouldn't a classic approach (ie. use plain old widgets for all controls, and use QGraphicsScene only for displaying the data) be more reasonable?
Is there any advantage in using QGraphicsScene in this case (performance or simplicity...)?
How should I use QGraphicsScene to exploit its strengths?
Since Qt 4.4 you can embed classic widgets in a QGraphicsScene by using QGraphicsProxyWidget :
QWidget *widget = new QWidget;
QGraphicsScene scene;
QGraphicsProxyWidget *proxy = scene.addWidget(widget);
If you think that QGraphicsScene (or whatever other widget you have) is appropriate for most of your display, use that. What we have done in the past for somewhat similar things is to make a custom widget that inherits (one way or another) from QWidget, and put the control widgets in a layout on top of that widget. This means that the whole widget is drawing whatever it is you want drawn, and the control widgets are on top of that, resizing as the whole widget is resized.
Alternatively, a couple of times we've had layouts that were just a bit too complicated for the layout widgets to easily handle. Rather than create a custom layout, we just positioned them with no layout, and moved them in code on the resize event. It works just as well.