A Tree of QGraphicsItem? - qt

I was wondering if it would be possible to create a QGraphicsItem in a QGraphicsScene that behaves like a QTreeWidget. This QGraphicsItem should be a tree of QGraphicsItems in the scene, with all the capabilities of a QTreeWidget: Where you can expand, collapse and change the order of the items in the stack, while keeping track of the indices with drag and drop capabilities.
Would this be possible by inheriting from QGraphicsItem and QTreeWidget/QAbstractItemView?
Maybe this has been done before or QT already have this functionality(I haven't seen anything like this in the documentation. I know that a QGraphicsItem can have children, that could be a starting point.

Related

How can I create multiple custom widgets and display them with their absolute position

So I currently have got a custom widget, and I want to add them to the main window after clicking a button. I would like to add them all to one fixed position first and then I will be able to drag them wherever I like. I am able to create and display these custom widgets with help of QHBoxLayout or QVBoxLayout, but in this case they will not be in the same position after I create them. Any help will be appreciated!
As the names suggest, the QLayout classes manage the position and geometry of the items added to them. You cannot move (eg. drag) an item out of a layout w/out first removing it from the layout (QLayout::removeItem() and derivatives). For example when you drag a toolbar or dock widget out of a QMainWindow it goes through all sorts of machinations to remove it from the MW layout, change the widget's window flags, remember the old position in the layout, and so on. And the reverse to dock it again.
To do what you describe (drag widgets arbitrarily around a window) you would need to not use a QLayout and position the widgets manually by specifying a QWidget::setGeometry() for example. After initial position, and assuming the user has some way to grab the widget (title bar or drag handle you made, etc), you'll probably still need to manage their positions, for example if the main window is resized (if you care about keeping them contained). Essentially you'd have a bunch of separate widgets acting as individual windows and probably need some way to keep track of them.
I don't know what kind of widgets you're talking about, but one option may be a QMdiArea which lets the user drag windowed widgets around, tabify them, save/restore state, and so on.
For more flexibility you could also look into the Qt Graphics Framework. The graphics scene has a lot of features for user-movable items/widgets, keeping track of them, and so on. It is probably the most flexible method overall, and you can also use regular QWidgets inside a graphics scene.
A couple other Q/A about arbitrarily positioning widgets (I'm sure there are more to be found):
QPushButton alignment on top another widget
How to keep Push Buttons constant in relative to change of Label Size in PyQt4

What to paint in the paintEvent implementation?

The Qt's documentation says:
Many widgets can simply repaint their entire surface when asked to, but some slow widgets need to optimize by painting only the requested region: QPaintEvent::region(). This speed optimization does not change the result, as painting is clipped to that region during event processing. QListView and QTableView do this, for example.
Do this mean that when I write a QWidget's paintEvent function, there's no need to manually write codes about which part of the widget should be painted and it is all handled automatically by qt itself?
when I write a QWidget's paintEvent function, there's no need to manually write codes about which part of the widget should be painted [?]
That's correct. The painter passed to you is already clipped to your widget's rectangle, so you can't paint outside of your widget. If your painting is cheap, then you can certainly repaint the entire widget at once, and ignore the repaint rectangle or region passed in the paint event.
You should also not blindly assume that painting only a part of the widget will be somehow inherently faster. You must measure this!
Could you explain more about the paintevent's propagation direction, usually qt's events are propagated as child->parent, but is the paintevent different?
All widgets that need to be painted are painted. The event is not propagated, it is delivered directly to the relevant widgets, under the direction of the widget compositor.
[...] when a Child widget's paintEvent is called, it also gets its Parent widget's paintEvent called. Why is this?
Two separate widgets happen to be painted. Just because they happen to be a parent and a child doesn't mean much. Each widget cares about its paint event in isolation. The widget compositor (backing store) has the big picture. If the parent is painted for seemingly no reason just prior to the child being painted, then likely the child isn't opaque and the parent is painted so that the child can be composited on top of it. Set Qt::WA_OpaquePaintEvent if your paintEvent does opaque painting and no part of the parent is visible through what's painted.

Qt Scaling/zooming contents of a QFrame (widgets, etc)

Is there a way in which I can rescale a QFrame and all of its child widgets? The child widgets are all custom widgets of mine and I'm always interacting with them, but I need them all to scale, even their relative coordinate positions
Came across a solution inadvertently while solving a different problem.
I used the QFrame::grab() function to get the pixmap of the frame and all of its children and repainted said pixmap elsewhere while using the .scale(int x, int y) function on the QPainter.

How can you know when a specific part of an item drawn with a QStyledItemDelegate is hovered?

I have a custom QAbstractItemModel used to display information in a QTreeWidget. However, individual indices are drawn using a QStyledItemDelegate. One item that is drawn using the delegate is a pixmap. When the user hovers the mouse over the pixmap (either help event style or hover enter style is fine) I need to do something, what it is isn't important.
So my question is, how can I know when the mouse has hovered over a specific item inside a QTreeWidget, when that item is drawn using a delegate?
In other situations, I could just subclass QLabel, set the pixmap on it, and then do whatever I need in the event() function, but in this case there is no object behind the pixmap, it is just painted onto the screen, so it doesn't actually receive events. Is it possible to use the delegate to paint an actual widget where I want it to so that widget can receive events, or do I have to work around this some other way?
You could subclass QTreeWidget and reimplement the mouseMoveEvent. In the event you can use the itemAt function in order to check if a valid item is at the mouse position and then do what you want.
void MyTreeWidget::mouseMoveEvent(QMouseEvent * event)
{
QTreeWidget::mouseMoveEvent(event);
QTreeWidgetItem* treeItem = itemAt(event->pos());
if (treeItem != NULL)
doSomething(treeItem);
}
You could avoid subclassing QTreeWidget and implement it in the parent widget/main window. Notice however that the itemAt function expects coordinates in the widget's viewport so you should transform the coordinates to tree widget's coordinates. IMHO it is more elegant to subclass it and just implement the mouseMoveEvent function.
EDIT
If you need to detect the position of an icon within the widget item, it is a bit more advanced but you can check my answer to an older question for more details:
Position of icon in QTreeWidgetItem
There is no Qt built-in solution to this problem. The problem can be solved, however, by saving the geometry of the individual items that are painted using the delegate as they are painted. The paint() function, however, has a const modifier so the data structure you use to save the geometry must be mutable. In this case, I don't think this constitutes a breach of the principles of OOP, but is rather a prime example of why the mutable keyword exists and when it should be used.
You then need to subclass QTreeWidget so you can re-implement the mouseMoveEvent() function as webclectic said. Inside that function you can compare the position of the mouse to the geometry of the item that you painted earlier. If the mouse is inside the item, then it is being hovered.

QGraphics Scene Zooming in and out

Here I am again worrying about how to Zoom in and out a QGraphicsPixmapItem in a graphics scene. I looked for a direct method for this but could not find any in graphics scene or in pix map. Can someone help me with this. Do I have to extend QGraphicsPixmapItem and implement methods for this.
Thanks again for help and I really do appreciate it.
~Tharanga
setScale() changes the size of the item, not the view scale of the scene. For a one item scene, it's effectively the same. But if you have more than one item in the scene, it changes the relation between items.
QGraphicsView::setTransform() should be used if you want to keep the item's relationship to the scene and other items.
QGraphicsPixmapItem inherits from QGraphicsItem, so it has all of that class's methods.
In particular, there's setScale that will change the item's scale factor (i.e. "zoom" it).
Look at the Transformations Example page for how this is done, and other transformations you can do.

Resources