I wish to make a custom graphics item to follow the cursor without needing to be clicked on. My view has setMouseTracking(true), my graphics item has setFlag(ItemIsMovable, true); setAcceptHoverEvents(true);, but it doesn't track the cursor, I have to click and drag it. What is the proper way to make a QGraphicsItem follow the cursor?
You can only capture mouse event on an item if your cursor pass above it. For example, instead of clicking on the item, you can react on mouseMove events.
But you seem to want a more global behaviour. You could track mouseMoveEvent directly on your QGraphicsView (or on your QGraphicsScene if you have multiple views) (see mouseMoveEvent). After that, just keep a reference on your item and make it move each time you intercept an event
Related
I've created an object Chartblock that implements QGraphicsItem. My goal is to create a grid of these objects, and when the mouse button is pressed (and held) and is drug over each block, perform something on each block as the cursor enters it.
Since a QGraphicsItem grabs the mouse events when it is clicked within it, other Items will not fire for the mouseMoveEvent. I then created an object based on the QGraphicsItemGroup to handle all the mouse events, but then I would need some way to pass mousePressEvent/mouseReleaseEvent as well as mouseMoveEvent to each child that the cursor is over.
Am I overthinking how to do this? It seems like such a simple action shouldn't be that difficult to create, but with QGraphicsItems holding onto the mouse events for itself, I'm not sure how to get around it. I've read similar situations, but nothing seems to give a straightforward answer.
Edit: I suppose a way to do this would keep track of the coordinates/sizes of every single QGraphicsItem I create in an array, then get the position of the cursor in the Group mouseMoveEvent, and see if there's a hit..
I was able to pull together a few similar answers to create a solution; I dropped the idea of placing all my QGraphicItem's in a Group, and placed them directly on a scene. With the scene grabbing all mouse events, I have the mouseMoveEvent check to see if the current position is on top of a QGraphicsItem - if so, perform something.
I still need to try and get itemAt() to work for my own classes that implement QGraphicsItem, as itemAt returns only QGraphicsItem's, but I'm sure some cast should get it working.
void ChartScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF mousePosition = event->scenePos();
QGraphicsItem* pItem = this->itemAt(mousePosition.x(), mousePosition.y());
}
I need to detect if the mouse pointer leaves my custom widget even if a mouse button is pressed.
According to this post, Qt does not cause a leaveEvent in case a button is pressed, at least not in version 4.4. I am working with 4.7.3, but still do not get a leaveEvent in the described case. I also tried with the various drag-related events, but no luck. Does anyone have an idea how to deal with this?
Actually there is an even better option than using the mouse events of the parent widget: You can implement the mouseMoveEvent function of the child widget and get the QMouseEvent::pos() position which is relative to the top left corner of the widget. That means, if you know the size of the widget (use for example QWidget::rect()), you can compute within the widget if the mouse pointer is still on the widget or not without having to change the parent widget.
Well, I did something similar to #gregseth.
Write your own MouseLeaveEvent that is invoked from MouseMoveEvent
when the mouse's position is outside of the widget's boundary.
As Qt's documentation says "Mouse move events will occur only when a mouse button is pressed down"
I got the same problem. The only workaround I found is to manage the mouseMove event of the parent widget, and to check if the position of the cursor is inside or outside the boundaries of the widget you want the event on.
I need an event for detecting if an user has moved the scrollbar position to another one.
In other words, if the user does scroll up/down, would it be possible to catch a signal so I can know the scroll has been changed its position?
I think it's not important, but the scrollbar I refer to is inside a QGraphicsView.
Regards.
Edit:
QGraphicsView is for displaying items in the screen, and if those items are too big it shows the scrollbars I refer to. What I need is to know when the user changes the position of those scrollbars.
Sliders have a sliderMoved(int value) signal, where value is the new position of slider.
If you need to get notified when the scroll bar position is changed, you need to subclass the QGraphicsView and reimplement the QWidget::mouseMoveEvent(QMouseEvent*). For this you also need to enable mouse tracking. Here is Qt 4.7 QGraphicsView reference.
For my Gui I want to use the following system:
The way it works is that, if the widget under the mouse does not consume a mouse or kb event, it is passed to that widget's parent until it is consumed or the desktop is reached.
Just one thing puzzles me about it. Does that mean if a Button, for whatever reason has a Label as one of its children. If I click the label, would that not mean that my button, which is under the label would click (since a label does not consume the mouse), which is undesired in this case. Does that mean I'd have to do if(mouseEvent.source == this){do button stuff} ?
Thanks
If the label is a child widget, then yes, the label will attempt to eat the event, fail (as usually the label doesn't have a handler method) and thus pass the event back up to the button.
Chances are the easiest way to do this is to derive a subclass of the Label class, and override the handle function (assuming this is possible in your toolkit - which it should be in any decent toolkit). You can then use your handle function to capture mouse clicks, and pass any other event back up to the button.
Comparing pointers is probably a bad idea and is slightly dependent on the way the toolkit is implemented - for instance, it might deem the source as the button (because that's what it expects), not the label.
Though I find it highly strange that a Label is a widget in itself.....
It looks like you need a special kind of "Label" which consumes mouse events. You should be able to create a customized widget (derived from Label) that consumes mouse events for this specific case.
If that Label widget is from a third party that cannot be derived/subclassed, you should wrap the Label in another widget: A simple widget that consumes mouse events and has only one child, the original Label.
I'm trying to create a popup menu like control that contains custom widgets. I need to capture the mouse, but I need to have the children in the widget still get their mouse messages. It appears the grabMouse sends events only to the widget that grabbed the mouse, not its children.
The popup is simply a series of buttons (using a QGridLayout). The control should work that the user presses the right-mouse button, the popup appears, they move to an item and release the mouse button. Optimally it would work exactly like a QMenu popup but with custom widgets and a custom layout.
How can I achieve this?
It appears that simply specifying attribute Qt::Popup is enough to get the fundamental behaviour required.
Installing an event filter on all children is also necessary. All mouse events, enter/leave/hover events must be captured. QT has a defect with grabMouse so that won't work -- the filter must be used to get expected behaviour.