Weird control boundaries detection on QGraphicsProxyWidget - c++

Hello in my application i'm making a QGraphicsView and set the scene on it:
QGraphicsProxyWidget *rotateItemIcon;
HoverFilter *hv = new HoverFilter(); // my hover filter class
connect(hv,SIGNAL(SignalHover(QObject*)),this,SLOT(ObjectHover(QObject*)));
connect(hv,SIGNAL(SignalHoverLeave(QObject*)),this,SLOT(ObjectHoverLeave(QObject*)));
ui->TestIcon->installEventFilter(hv);
...
scene = new QGraphicsScene(this);
scene->setSceneRect(0, 0, 661, 255);
ui->TestIcon->setParent(NULL);
rotateItemIcon = scene->addWidget(ui->TestIcon); // here i add my control to the scene and receive QGraphicsProxyWidget object
rotateItemIcon->setTransformOriginPoint(ui->TestIcon->width()/2,
ui->TestIcon->height()/2);
ui->graphicsViewFive->setScene(scene); //QGraphicsView on my form
ui->graphicsViewFive->show();
my HoverFilter.cpp
#include "hoverfilter.h"
#include "QDebug"
HoverFilter::HoverFilter()
{
}
bool HoverFilter::eventFilter( QObject *dist, QEvent *event )
{
if( event->type() == QEvent::Enter )
{
emit SignalHover(dist);
return true;
}
if( event->type() == QEvent::Leave )
{
emit SignalHoverLeave(dist);
return true;
}
return false;
}
rotateItemIcon is my QGraphicsProxyWidget and the problem is that it has weird boundaries, i need to implement some animation on hover of my control TestIcon, (i done that using event filter) mouse enter and mouse leave fires when i drag my mouse on a random places, not only on my TestIcon control. If do not add my control to the QGraphicsScene hover detection works fine, so i assume this is a scene/proxywidget problem. Is there a way i can set size or boundaries to QGraphicsProxyWidget to stop that?

I'm not sure if I completely understand your question, but it sounds like you're have a widget placed in a scene via a QGraphicsProxyWidget and when you try to detect if your mouse is over the widget you want it to animate.
By 'weird boundaries' I assume you mean the extents to which the proxy widget is accepting the mouse as being over the widget. If so, I suggest either calling setGeometry on the QGraphicsProxyWidget to set its position and dimensions, or inherit from QGraphicsProxyWidget and implement the boundingRect function to define the area of the proxy widget.

Related

Why is QSlider not updating it's position immediately in its UI?

I am creating a video application.
Upon starting this app, you would see a VideoWidget looping a playlist along with other widgets in the screen. By clicking the VideoWidget, the VideoWidget will go to fullscreen mode and a volume slider will be laid over it. It would go to show normal if clicked again in fullscreen mode.
To do this I created 2 classes. First, I created a main class that would contain all widgets including the Video widget. Second, I created a custom VideoWidget class. I instatiated my Qslider in this VideoWidget class and I instantiated a VideoWidget Object in my main class whose object is instantiated in main.cpp.
I got what I expect it to do. Except that the slider would not update its position immediately. It would only update position if you click to show normal then click to go back fullscreen. The volume change but the position of slider in UI does not change while in fullscreen.
I would like to ask what am I doing wrong? What should I do so that the slider position would update in UI?
Code Snippet:
in VideoWidget.h
class VideoWidget : public QVideoWidget
{
Q_OBJECT
QVideoWidget* videoWidget;
QMediaPlaylist* playlist;
QMediaPlayer *player;
public:
VideoWidget();
QSlider* slider;
};
In VideoWidget.cpp
VideoWidget::VideoWidget()
: videoWidget(new QVideoWidget(this)),
slider(new QSlider(Qt::Horizontal, this))
{
/*QMediaplaylist *playlist, QMediaPlayer *player instantiated here*/
slider->hide();
slider->setGeometry(300,735,600,20);
slider->setRange(0, 100);
slider->setValue(player->volume());
connect(slider, &QSlider::valueChanged, player, &QMediaPlayer::setVolume);
}
void VideoWidget::changeEvent(QEvent *event)
{
if(event->type() == QEvent::WindowStateChange)
slider->setVisible(windowState() == Qt::WindowFullScreen);
QWidget::changeEvent(event);
}
enter code here
void VideoWidget::resizeEvent(QResizeEvent* event) {
videoWidget->resize(size());
event->accept();
}
void VideoWidget::mousePressEvent(QMouseEvent *event)
{
this->setFullScreen(!isFullScreen());
event->accept();
}
In the MainWidget.cpp
mainwidget::mainwidget(QWidget *parent)
: QWidget(parent)
{
videoWidget = new VideoWidget(); // the video container
videoWidget->setFixedSize(500, 300);
QBoxLayout *displayLayout = new QHBoxLayout;
displayLayout->addWidget(videoWidget, 2);
QBoxLayout *layout = new QVBoxLayout;
layout->addLayout(displayLayout);
setLayout(layout);
videoWidget->setGeometry(100,100,300,400);
videoWidget->show();
}
edit:
This is the app at startup playing a video of my hand.
When I click the Video,
The video sets to fullscreen and the slider appears. The slider can control the volume of mediaplayer but the problem is, it won't move when dragged.
You're very confusing in ways you describe what the problem is, but if I get you right that QSlider doesn't track the mouse but you can change volume with it, presumably with a click?
You had connected valueChangedsignal , which is emitted only after sliderReleased() if tracking property is false. You have to handle Pressed\Moved\Released group of signals if you want to adjust volume continuously, or you can use built-in function of QSlider (which usually is enough):
slider->setTracking(true);

not calling mousemove event on widgets and graphics view

I have created a set of wizard pages inherited from qwizardpage. in one of my wizard page i have a graphics view and in that using graphics scene and a qrect a rectangle has been created and now i am trying to catch the callback event of mouse move when the mouse is in the graphicsview area, but outside this area only call back is happening. But mouse press event is functioning properly. could anyone suggest me any solution.
WizardPage::WizardPage(QWidget* parent)
{
m_pScene = new QGraphicsScene(this);
graphicsView->setScene(m_pScene);
m_pRect = new QRect(-25, 25, 100, 40);
m_pScene->addRect(*m_pRect);
setMouseTracking(true);
}
void EgoLeverWizardPage::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << "move";
}

How to draw a line on a child widget instead of the parent widget?

I'm trying to draw a line (and some other primitives) on a QWidget. That QWidget is physically "on top of" another widget with a picture in it. I want to draw lines and circles over a picture.
I know how to draw a line already. I can do that with this code:
bool MySpecialWidget::eventFilter( QObject* watched, QEvent* event )
{
if (watched == this && event->type() == QEvent::Paint)
{
QPainter painter(this);
painter.translate(50, 50);
painter.setPen(QPen(Qt::blue, 12));
painter.setBrush(Qt::BrushStyle::SolidPattern);
painter.drawLine(0, 0, 200, 200);
}
return false;
}
But what I really want to do is position a widget to hold a picture, then position a widget over it to hold the lines. Like this:
MySpecialWidget::MySpecialWidget(QWidget *parent) : QWidget(parent)
{
QRect position = QRect(30, 50, 600, 600);
pictureBox = new QLabel(parent);
pictureBox->setGeometry(position);
pictureBox->setPixmap(QPixmap(QString::fromUtf8(":/main/graphics/MyPicture.png")));
pictureBox->setScaledContents(true);
drawnElements = new QWidget(parent);
drawnElements->setGeometry(position);
drawnElements->raise();
this->installEventFilter(this);
}
Then to draw the lines and primitives, I want to do it like this:
bool MySpecialWidget::eventFilter( QObject* watched, QEvent* event )
{
if (watched == this && event->type() == QEvent::Paint)
{
QPainter painter(drawnElements);
painter.translate(50, 50);
painter.setPen(QPen(Qt::blue, 12));
painter.setBrush(Qt::BrushStyle::SolidPattern);
painter.drawLine(0, 0, 200, 200);
}
return false;
}
But this doesn't work. Nothing is drawn. Blank.
The problem is the line that reads QPainter painter(drawnElements);
If I say QPainter painter(this);, it draws something, but it's not on the child widget, it's on the parent widget.
The documentation is pretty clear on the subject:
Each widget performs all painting operations from within its
paintEvent() function. This is called whenever the widget needs to be
redrawn, either as a result of some external change or when requested
by the application.
You should only draw on a widget from its paint event, and you should only draw on that particular widget.
The problem is the line that reads QPainter painter(drawnElements);
Of course. You need to be watching the target widget instead and catch its paint event. To control the order of drawing, you should explicitly deliver the event to the target as well.
bool MySpecialWidget::eventFilter( QObject* watched, QEvent* event )
{
// *** vvvvvvvvvvvvv *** (A)
if (watched == drawnElements && event->type() == QEvent::Paint)
{
// Let the target draw itself first.
watched->event(event);
// Then overlay our content on it.
// *** vvvvvvvvvvvvv *** (B) - must match (A)!
QPainter painter(drawnElements);
painter.translate(50, 50);
painter.setPen(QPen(Qt::blue, 12));
painter.setBrush(Qt::BrushStyle::SolidPattern);
painter.drawLine(0, 0, 200, 200);
return true; // The event is already handled.
}
return false;
}
MySpecialWidget::MySpecialWidget(QWidget *parent) : QWidget(parent)
{
//...
drawnElements->installEventFilter(this);
}
Feel free to also consider using an overlay widget.

Qt mouseMoveEvent not firing when mouse pressed

I have a custom QGraphicsScene in which I have a mouseMoveEvent(QGraphicsSceneMouseEvent *event);
When I hover on the scene with the mouse, the mouseMoveEvent gets properly fired. However when I hover with a mouse button pressed, then it does not get fired anymore.
This is how I setup the whole scene in the main window:
scene = new NodeScene(this); -> My Custom QGraphicsScene class
scene->setSceneRect(QRectF(0, 0, 5000, 5000));
QHBoxLayout *layout = new QHBoxLayout;
view = new QGraphicsView(scene);
layout->addWidget(view);
view->setDragMode(QGraphicsView::RubberBandDrag);
view->setMouseTracking(true);
QWidget *widget = new QWidget;
widget->setLayout(layout);
setCentralWidget(widget);
scene->setCentralWidget(widget);
And here is the code where I do handle mouse events (it's for Maya execution):
void NodeScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
MGlobal::displayInfo("Move");
QGraphicsScene::mouseMoveEvent(event);
}
void NodeScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
MGlobal::displayInfo("Press");
QGraphicsScene::mousePressEvent(event);
}
void NodeScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
MGlobal::displayInfo("Release");
QGraphicsScene::mouseReleaseEvent(event);
}
Any idea how I can get the mouseMoveEvents even when a mouse button is pressed ?
It sounds like you're not implementing all of the mouse events, just the mouseMoveEvent.
When overriding a mouse event, you should handle all of them (move, press and release events).
You can then set a boolean in the press event to know whether or not the mouse button is held down when entering the mouseMove event.
Found the issue by comparing my code to other examples, and it is due to the setDragMode(QGraphicsView::RubberBandDrag);
line. The code should by default be on QGraphicsView::NoDrag and the RubberBandDrag be enabled only upon press.

Remove scroll functionality on mouse wheel QGraphics view

I have a QGraphicsView window on my widget and have just put in an event for mouse wheel which zooms in on the image.
However as soon as i zoom in scroll bars are displayed and the scroll functionality on the mouse wheel overrides the zoom function i have.
i was wondering if there is any way that i can remove scrolling all together and add a drag to move option or maybe a CTRL and mouse wheel to zoom and mouse wheel alone would control scrolling
here is my zoom function (Which im aware isnt perfect) but if anyone could shed some light on that it would be a bonus
cheers in advance
void Test::wheelEvent(QWheelEvent *event)
{
if(event->delta() > 0)
{
ui->graphicsView->scale(2,2);
}
else
{
ui->graphicsView->scale(0.5,0.5);
}
}
You reimplemented wheelEvent for QWidget/QMainWindow that contains your QGraphicsView, however, wheelEvent of QGraphicsView remains intact.
You can derive from QGraphicsView, reimplement wheelEvent for derived class and use derive class instead of QGraphicsView - this way you won't even need wheelEvent in your QWidget/QMainWindow, and you can customize reimplemented wheelEvent to do what you want. Something like that:
Header file:
class myQGraphicsView : public QGraphicsView
{
public:
myQGraphicsView(QWidget * parent = nullptr);
myQGraphicsView(QGraphicsScene * scene, QWidget * parent = nullptr);
protected:
virtual void wheelEvent(QWheelEvent * event);
};
Source file:
myQGraphicsView::myQGraphicsView(QWidget * parent)
: QGraphicsView(parent) {}
myQGraphicsView::myQGraphicsView(QGraphicsScene * scene, QWidget * parent)
: QGraphicsView(scene, parent) {}
void myQGraphicsView::wheelEvent(QWheelEvent * event)
{
// your functionality, for example:
// if ctrl pressed, use original functionality
if (event->modifiers() & Qt::ControlModifier)
{
QGraphicsView::wheelEvent(event);
}
// otherwise, do yours
else
{
if (event->delta() > 0)
{
scale(2, 2);
}
else
{
scale(0.5, 0.5);
}
}
}
Scrolling can be disabled with the following code:
ui->graphicsView->verticalScrollBar()->blockSignals(true);
ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->graphicsView->horizontalScrollBar()->blockSignals(true);
ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
I think your question has a bit simpler answer.. To disable scroll bars just set scroll bar policy (QGraphicsView is just QScrollView), so step 1)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
that will disable scroll bars..
step 2) (if you want to keep it simple)
QGraphicsView * pView; // pointer to your graphics view
pView->setInteractive(true);
pView->setDragMode(QGraphicsView::ScrollHandDrag);
thats the fastest way to get results you want