I custom my own item, which inherits from QGraphicsItem, override the mousePressEvent function, then I add it into QGraphicScene.
When I debug, I move mouse onto my item, then press down, I find that the QGraphicScene's event processing function is called first(I install a event processing filter on QGraphicScene), then mousePressEvent of my custom item is called, is this correct?
How can I made my custom item earlier receiver than QGraphicScene?
The behavior you describe is correct and by design. The item will never receive the event before the scene does; it is - after all - the scene's job to route the event to the correct item. The scene maintains spatial index of the items and uses it to route the event. What you can do instead is to filter the event on the item itself, not on the scene: use QGraphicsItem::installSceneEventFilter.
Related
I have a subclass of QGraphicsItem inside a QGraphicsScene. To handle mouse events inside the item, I reimplemented mousePressEvent and mouseReleaseEvent. Since I want the item to be movable, I wrote setFlags(ItemIsMovable); inside my constructor. But when I move the item, my mouseXxxEvent methods are called as well.
How can I detect whether the mouse event was used to move the item or not? I would be ok to only reimplement one of the above mentioned functions.
I have several QGraphicsItem objects on my custom GraphicsScene. They have different custom types, so some of them have to handle MouseMove event in one way, and other in different way.
When I select some of them and then move selected items only the item that is under the mouse cursor receive MouseMove event but other items does not. I have to make some additional actions in MyCustomItemClass::mouseMoveEvent when moving is started.
So why does the other items not receive the event?
From your description I would not handle these actions in MyCustomItemClass::mouseMoveEvent because this is only executed when the mouse moves on top of that particular item as you already stated.
Instead I'd subclass the mouseMoveEvent in the scene to check which items are selected and execute the related method in these items. Of course you have to be careful to only move them relatively to their original position according to the relative mouse movement.
If you want to select a group of items and then move them all at once, you can add them to a QGraphicsItemGroup during the select and then move the group as a single object, which will move all the items in the group.
In my application, I have one tableview of items, and a side-panel "preview":ing the latest selected item.
I want clicking on an item to change the selection, and double-clicking to cause a "run"-action to be performed. More specifically, I want the "run"-action (including key-navigation and pressing enter) to be bound to the "activation" of the item in the table-row.
My problem is; single-clicks does not only change the selection, but fires the "activated" signal on the item. I would like to tweak it such that:
Navigation Keys, Single Mouse Click: Selection-change, update preview-panel
Enter Key, Double Mouse Click: Activate/run/open action triggered.
Is there a nice clean way to do it, or are overriding the onclick/doubleclick events my best option? Or is there some other tabular list-widget better suiting my needs?
I would connect the slot for the preview action to the currentChanged() signal of the table view's selectionModel(). This covers single clicks and key navigation.
Then there's two options for the double clicks and Enter key presses:
Subclass your tableview, override doubleClickEvent() and keyPressEvent() and fire your custom signal in there, with maybe the model index or something else as an argument. Then just connect your run method to your own signal as you have full control over when it is fired.
If you don't want to subclass, you can use the installEventFilter() mechanism.
Either I'm getting your approach wrong or I'm too tired, but if you want to trigger a run event you should avoid the activated signal completely. Set the signal slot mechanism so that your double click and Enter key press event trigger your run() function, and then the single click/nav buttons should trigger the 'activated' slot which will return your index in the tableview.
I'm pretty certain Qt wants you to be explicit about which signal points to which slot or it'll ignore it or point to a default.
In a Qt 4.7.1 Windows app, a slot that's connected to QGraphicsScene::changed() is fired as expected but the dirty region count is always 1 and the rect size I get is always the same as my app window. I tried calling QGraphicsView::setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); but that didn't help.
Is there a way to tell Qt to only give me the area(s) of the page that changed?
An update in a QGRaphicsView is different from the one in a QGraphicsScene. Update in the view is caused by the need to repaint the view. With or without changing the scene. This typical is from window (resize) and view changes (scroll). An change in the scene will also trigger an update to the view.
A change in a scene is the change of the content of the scene. Like adding or removing a item, scaling or translating of the transformation. This will emit the changed() signal. All views displaying that scene will also update themselves for the display.
For example. Scrolling a view around will not generate any scene update since nothing in the scene changed. The paint() function of items in the scene will be called to repaint. But no changed() signal will be emitted from the scene.
If you changed the scale of the scene for instance, the whole scene changed. In addition to the whole repaint, the scene will emit changed() signal and indicates the whole scene changed. But if you add a new item to the scene, changed() should indicate only the rect of the new item.
If you want to know what part of the scene need to be repainted, in addition to calling QGraphicsView::setViewportUpdateMode(), you need to install a event filter to the view and check for QEvent::Paint. Note that the region and rect in QPaintEvent is in local coordinate of the view, which can be different from the scene. But QGraphicsView has many mapping functions to do the conversion.
I have a Canvas (lets call it the Drop Box) which users can drag and drop external files onto. Next to this I have a ViewStack, of which one of the layers is a Canvas with a TileList. I have successfully managed to code it so that the items dropped onto the Drop Box appear in the TileList. I simply capture the darg drop event (lets call this event A) and dispatch a new one that the TileList is listening for (lets call this event B).
However, this only works if the ViewStack selectedIndex is set to that of the Canvas with the TileList. If the Canvas with the TileList isn't selected then the event listener which is added to the TileList at CreationComplete level (event B), won't be called until after the drag drop event has dispatched (event B). This means that something is firing before something even has a chance to listen for it!
I've tried looping until the Canvas with the TileList is completely drawn, but this causes the app to hang.
I've also tried passing the event to the Canvas and storing it locally, but when I attempt to access the clipboad of the event I get an error (dead clipboard).
Effectively I want to only dispatch the event to the Canvas after it's had a chance to load, and add the event listener to the TileList.
Any ideas? :)
Maybe setting creationPolicy="all" for View Stack will help? All it's children will be created at startup.