problem with QMouseEvent in QRect - c++

OS::win_xp_sp3
Qt::4.6
Is it possible to use QMouseEvent inside QRect?
I have parent widget and inside is some QLabel with text "status unchanged".
Also , inside parent widget is MyRect which is derived from QRect.
Now I want to MouseEvent act only inside this MyRect. For example , if I act on MyRect , text in parent widget need to be changed.
For example:
class MyRect : public QRect {
public:
MyRect(int x, int y, int w, int h, ParentWidget* parent)
: QRect(x,y,w,h)
{
itsParent = parent;
}
~MyRect() {}
protected:
void mouseMoveEvent(QMouseEvent* event)
private:
ParentWidget* itsParent
};
void MyRect::mouseMoveEvent(QMouseEvent* event)
{
if(event->buttons() == Qt::LeftButton)
{
itsparent->label->setText("status changed");
}
}
nothing happens
question:: is it possible to use QMouseEvent like this (only on QRect)?

A QRect is neither a QObject nor a QWidget, so it doesn't receive events.
It's just four numbers describing a rectangle (and it doesn't make sense to derive from it).
You can check if a point is the given rect in the mouse event handler of your widget. Like:
void MyLabel::mouseMoveEvent( QMouseEvent* e ) {
if ( !rect.contains( e->pos() ) )
return;
//... handle mouse move
}
An alternative to subclassing is using an event filter.

is it possible to use QMouseEvent like this (only on QRect)?
No, at least not how you do it. QRect is not a QWidget and therefore doesn't have any mouseEvent handlers and such. It is just an entity with four coordinates.
You can do what you want by adding a handler to a real QWidget (either by subclassing, or using installEventFilter) and in the handler check for clicking in your rectangle using QRect::contains(QPoint).

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);
}

Is there an easy way to trigger a hoverenter/hoverleave event on children of a QWidget?

For styling purposes, I'm trying to make all the widgets in a set of widgets adopt a certain background if a pointer enteres any of those widgets;
i.e. if the pointer is insides the containing rectangle of widget A, both A and widget B should change its background. Likewise if the pointer enters B, then A should also adopt the same background. The background should, naturally, fall back to the non-hovering background if the pointer is outside both A and B.
QWidget appears to have most of the plumbing to get this done, but its hidden behind protected.
I really want to avoid inheriting from QWidget if I can avoid it and I really would like to not have to change the stylesheets of the widgets too.
[1] In my case, I have three widgets, not two.
Have an event filter class, and let it hold the affected widgets in a vector of pointers:
#include <QMouseEvent>
class EventFilter : public QObject
{
Q_OBJECT
QVector<QWidget*> widgets;
public:
void append(QWidget * w)
{
w->setAttribute(Qt::WA_Hover);
w->installEventFilter(this);
widgets.append(w);
}
bool eventFilter(QObject *watched, QEvent *event)
{
if(event->type() == QMouseEvent::HoverEnter)
{
for(auto w : widgets)
{
w->setStyleSheet("background-color: red;");
}
}
else if(event->type() == QMouseEvent::HoverLeave)
{
for(auto w : widgets)
{
w->setStyleSheet("background-color: white;");
}
}
return false;
}
};
The append method will set up the widget and push it in the vector.
Have a private filter instance in your form class:
class Form : public QWidget
{
Q_OBJECT
//...
private:
EventFilter filter;
//...
In your form constructor:
ui->setupUi(this);
filter.append(ui->widget1);
filter.append(ui->widget2);
filter.append(ui->widget3);
In the example I used setStyleSheet to set the background color, but you can use whatever strategy you prefer, i.e. resetting the widget palette.

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).

Propagate events to both QGraphicsView and QGraphicsScene

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);
}