Propagate events to both QGraphicsView and QGraphicsScene - c++

I have a Qt app with a QGraphicsView and QGraphicsScene. I subclassed them both and want to handle mouseevents in both. I can do this for both classes separately, using
virtual void mousePressEvent(QMouseEvent* event);
But when I handle the events in the GraphicsView, I don't receive them anymore in the GraphicsScene. How do I fix this, i.e. pass the event from the grapchicsview to the graphicsscene?

Just forward mousePressEvent to your GraphicsView's parent, this will then call scene's mousePressEvent :
void MyGraphicsView::mousePressEvent(QMouseEvent * e)
{
// forward to scene (via default view behaviour)
QGraphicsView::mousePressEvent(e) ;
// ...
}
BTW, QGraphicsScene::mousePressEvent has a different kind (class) of event : QGraphicsSceneMouseEvent

Call the base implementation at the end of your overriden function, eg:
void MyView::mousePressEvent(QMouseEvent* event)
{
// do something
QGraphicsView::mousePressEvent(event);
}

Related

Send Signal From Child To Parent On Mouse Click Qt

I have a MainWindow, a DockWidget and a QGLWidget inside it. I am drawing circles inside the QGLWidget. I want to print the x and y coordinates of the place that I am clicking to the labels inside DockWidget.
I would be glad if someone could show me the way?
Override the QWidget::mousePressEvent(QMouseEvent *) or QWidget::mouseReleaseEvent(QMouseEvent *) of the QGLWidget and create a signal for sending the x and y. It means you have to create own class inherithing from QGLWidget.
It could look like this:
void MyGLWidget::mouseReleaseEvent(QMouseEvent *event)
{
emit printXY(event->pos());
}
and in the MyGLWidget.h:
signals:
void printXY(const QPointF& clickedPos);
then create a slot in the DockWidget:
public slots:
void onPrintXY(const QPointF& clickedPos);
and connect it in the place where you create the MyGLWidget. I suppose in some function of the DockWidget like:
void DockWidget::createGLWidget()
{
MyGLWidget widget = new MyGLWidget;
connect(widget, &MyGLWidget::printXY, this, &DockWidget::onPrintXY);
}

Qt mouse events not working in QGraphicsScene

I am using Qt 5.7 (the latest version). I can't get the mouse events to work in QGraphicsScene, but they work in window outside of my scene. I have followed this question.
So I have overwritten QWidget::mouseMoveEvent() in my main widget's subclass like this:
// header:
class MyWidget {
...
void mouseMoveEvent( QMouseEvent * event );
};
// source:
MyWidget::MyWidget() {
setMouseTracking();
}
void MyWidget::mouseMoveEvent( QMouseEvent * event ) {
}
It doesn't work for: mouseMoveEvent, mouseGrabber, mousePressEvent, mouseReleaseEvent, or mouseDoubleClickEvent. But somehow it only works for mousePressEvent.
Could this be a bug in Qt?
SOURCE CODE:
In objectloader.cpp
ObjectLoader::ObjectLoader(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::ObjectLoader)
{
ui->setupUi(this);
scene=new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
ui->graphicsView->setMouseTracking(true);
setMouseTracking(true);
}
Thats were i set mouse tracking twice
In objectloader.h
Then i define that method in objectloader.h
class ObjectLoader : public QMainWindow
{
Q_OBJECT
public:
explicit ObjectLoader(QWidget *parent = 0);
~ObjectLoader();
private slots:
void mouseMoveEvent(QMouseEvent *event);
protected:
private:
};
#endif // OBJECTLOADER_H
And implementation of that method in objectloader.cpp
void ObjectLoader::mouseMoveEvent(QMouseEvent *event){
qDebug()<<"Mouse moved";
}
When a mouse event is generated by Qt it is generally passed initially to the QWidget that was under the mouse pointer when the event was generated. If that QWidget accepts the event then no further processing will take place. If the event isn't accepted then Qt may propogate the event to that QWidget's parent and so on.
In your particular case the mouse move events you are interested in are being sent to the QGraphicsView/QGraphicsScene conponents where they are being accepted and, hence, no further processing takes place. In a case like that you generally need to install an event filter to intercept and process the events of interest.
Mouse move events will occur only when a mouse button is pressed down, unless mouse tracking has been enabled with QWidget::setMouseTracking().
So, I think you should check whether mouseTracking is really enabled or not, by using `bool hasMouseTracking() const'.

Qt : catched mouseMoseEvent dont interact with QWebView html page element

I catch the mouseMoveEvent of my QWebView for restarting a timer of a screensaver. The problem is that now the mouseMoveEvent isnt distribued to the HTML elements so its impossible for example to move a sliding bar on the page.
I use connect to bind mouseMoveEvent to the restart slot :
QObject::connect(_view, SIGNAL(mouseMoveEvent(QMouseEvent*)), _mediaPlayer, SLOT(stop()));
WebView class :
class WebView : public QWebView
{
Q_OBJECT
public:
WebView(QString menu) : _menuDesc(menu) {};
WebView(){};
void setMenuDesc(QString menu) {_menuDesc = menu;};
QString getMenuDesc() {return _menuDesc;};
void setCurrPage(QString page) {_currPage = page;};
QString getCurrPage() {return _currPage;};
void setCurrCategory(QString page) {_currPage = page;};
QString getCurrCategory() {return _currPage;};
void mouseMoveEvent(QMouseEvent *)
{
emit mouseMoved();
};
signals :
void mouseMoved();
private:
QString _menuDesc = 0;
QString _currPage;
QString _currCategory = 0;
};
Is there a solution to still catch the signal and pass it to the HTML page?
mouseMoveEvent is not a signal but an event handler. You can reimplement this event handler and let it emit a signal you can connect to if you need that.
Like this:
MyWebView::mouseMoveEvent(QMouseEvent * e) {
emit mouseMoved(); // this would be signal you could connect to.
}
Seems you misunderstand event handler and signal usages.
mouseMoveEvent is a member method of QWidget, is not a signal so you cannot connect to it. You can override it in you subclass and emit your own signal.
And if a QWidget's mouse tracking is switched off, mouse move events only occur if a mouse button is pressed while the mouse is being moved. Maybe you need to call setMouseTracking too.

Synchronizing mouse wheel and MarbleWidget (ZoomIn(), ZoomOut() )

I use MarbleWidget with OpenStreetMap on Qt.
Wheel zoom shows blurry images on the map. Therefore, I want to synchronize the mouse wheel with ZoomIn() and ZoomOut() inorder user to get sharp images on the map.
I want to do something like this:
QObject::connect( MarbleWidget, SIGNAL(??????), this, SLOT(wheelEvent(wheelEvent)) );
void MainWindow::wheelEvent(QWheelEvent *event){
//....
}
Is there any signal or event that I can use from MarbleWidget for ??????? above line?
And, how can I disable the mouse zoom on the MarbleWidget?
You can make your own input handler and tell MarbleWidget to use it. This will allow you to intercept mouse wheel events in the way you are asking.
Create a custom input handler
MarbleWidget uses a default input handler. Inside of MarbleInputHandler.cpp there is a function eventFilter(QObject*, QEvent*) that handles (among other things) the QEvent::Wheel event. Derive from this class and override eventFilter:
class MyMarbleInputHandler : public MarbleWidgetDefaultInputHandler
{
Q_OBJECT
public:
explicit MyMarbleInputHandler(MarbleWidget* mw) :
MarbleWidgetDefaultInputHandler(mw) {}
virtual bool eventFilter(QObject *o, QEvent *e);
signals:
void wheelEvent(QWheelEvent *event);
};
Basically, you want to intercept QEvent::Wheel and emit your own signal. Anything you don't handle yourself should be passed along to the base class.
bool MyMarbleInputHandler::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QEvent::Wheel)
{
emit wheelEvent(static_cast<QWheelEvent*>(e));
return true;
}
return MarbleWidgetDefaultInputHandler::eventFilter(o, e);
}
Create a custom MarbleWidget
The constructor below shows how you can set the input handler defined above. You'll also have to wire the signal/slot.
class MyMarbleWidget : public MarbleWidget
{
Q_OBJECT
public:
explicit MyMarbleWidget()
{
MyMarbleInputHandler *myMarbleInputHandler = new MyMarbleInputHandler(this);
setInputHandler(myMarbleInputHandler);
connect(myMarbleInputHandler, SIGNAL(wheelEvent(QWheelEvent*)),
this, SLOT(handleWheelEvent(QWheelEvent*)));
}
public slots:
void handleWheelEvent(QWheelEvent *event)
{
if (event->delta() > 0) zoomIn();
else zoomOut();
}
};
handleWheelEvent() provides the code to zoom in/out. Not all scroll wheels work the same, so you'll have to figure out how much movement of the mouse wheel it will take to zoom in/out by one step. In this example, it zooms in/out one step based on each event, paying attention only to the sign of delta() and ignoring its magnitude.
You might also check out MarbleDefaultInputHandler::handleWheel() to see what's going on with the default behavior. They use interpolated/stretched bitmap images between vector layers to provide a smoother animation when zooming. Note that the plus+ and minus- keys on the keyboard will allow you to zoom to non-interpolated map levels, whereas the mouse wheel zooms using animated ("blurry") interpolated layers. This behavior is documented in a bug report.

custom Qt event is not delivered (event flow: Widget inside -> QMainWindow)

I have a QMainWindow-derived Widget that contains a QGLWidget-derived Widget. I have a custom Event that will get fired from within the GLWidget's paintGL() method that way (the notification shall be asynchonous, that's why I'd like to post an event):
QCoreApplication::postEvent(parent(),new ColpickEvent(rgb, pickPoint));
The event looks like this (very simple, no capsuling of data):
#define COLORPICK_EVENT QEvent::Type(31337)
class ColpickEvent : public QEvent
{
public:
ColpickEvent(QRgb col, const QPoint& pos)
: QEvent(COLORPICK_EVENT), Color(col), PixelPos(pos) {};
QColor Color;
QPoint PixelPos;
};
The MainWindow overrides QObject::event(QEvent*) like this:
#define EVENT_TYPE(ClassName) { ClassName *e = static_cast<ClassName*>(event)
#define END_EVENT } break
#define ACCEPT_EVENT e->accept(); return true
bool MainWindow::event(QEvent* event)
{
switch(event->type())
{
/*... handle other events ...*/
case COLORPICK_EVENT:
EVENT_TYPE(ColpickEvent);
// do something with the data provided by the event ...
ACCEPT_EVENT;
END_EVENT;
/*... handle other events ...*/
}
return QMainWindow::event(event);
}
What happens is, that my ColpickEvent never seems to get dispatched to MainWindow. Any ideas why this happens (or actually doesn't happen)?
OOPS.
As the top level widget was derived from QMainWindow, it needed to have a centralWidget. Somehow it wasn't possible to set the GLWidget as centralWidget, as I needed a Layout to overlay other widgets on top of it.
So the centralWidget of MainWindow is a simple QWidget "w" with a GridLayout. The GLWidget is added to the Layout, that way its parent was changed to "w".
Because of this, the solution is simply enough:
QCoreApplication::postEvent(parent()->parent(),new ColpickEvent(rgb, pickPoint));
(see the double-parent-call).