How to get global geometry of child widget - c++

I have label inside custom frame.
I try to movement of MainWindow (all aplication) on mouse event:
void settingslogolabel::mouseMoveEvent(QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull){
window()->move( mapToGlobal(ev->pos() - m_dragPosition - this->geometry().topLeft()));
}
}
BUT! this->geometry() returns local geometry.
So, how can I get global geometry of child?
What I try to make:
When you press mouse and move - all application should move as your cursor move, until you up mouse button. I want to make this interactive for label.
Full code:
HPP:
#ifndef SETTINGSLOGOLABEL_H
#define SETTINGSLOGOLABEL_H
#include <QLabel>
#include <QWidget>
#include <QMouseEvent>
class settingslogolabel : public QLabel
{
Q_OBJECT
public:
explicit settingslogolabel(QWidget *parent = 0);
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
private:
QPoint m_dragPosition;
bool firstCIsNotNull = true;
private:
};
#endif // SETTINGSLOGOLABEL_H
CPP:
#include "settingslogolabel.hpp"
settingslogolabel::settingslogolabel(QWidget *parent) :
QLabel(parent)
{
}
void settingslogolabel::mouseMoveEvent(QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull){
window()->move( mapToGlobal(ev->pos() - m_dragPosition - this->geometry().topLeft()));
}
}
void settingslogolabel::mousePressEvent(QMouseEvent *ev)
{
if (ev->button() == Qt::LeftButton) {
m_dragPosition = ev->pos();
firstCIsNotNull = true;
}
}
void settingslogolabel::mouseReleaseEvent(QMouseEvent *ev)
{
if (ev->button() == Qt::LeftButton) {
firstCIsNotNull = false;
}
}

Not sure I fully understand the problem but, the global coordinates of the top left corner of a widget can be found -- from within that widget's member functions -- using...
mapToGlobal(QPoint(0, 0));
Similarly, the global geometry would be...
rect().translated(mapToGlobal(QPoint(0, 0)));
Edit:
If the aim is to allow dragging of the top level window then your mouseMoveEvent implementation should be something like (untested)...
void settingslogolabel::mouseMoveEvent (QMouseEvent *ev)
{
if ((ev->buttons() & Qt::LeftButton) && firstCIsNotNull) {
auto delta = ev->pos() - m_dragPosition;
window()->move(window()->pos() + delta);
}
}

Related

Keyboard input in custom QQuickPaintedItem

I defined my custom QQuickPaintedItem in such a way:
class NiceItem : public QQuickPaintedItem
{
...
public:
...
void keyPressEvent(QKeyEvent * event);
void paint(QPainter *painter);
...
};
Here you have keyPressEventcode:
void NiceItem::keyPressEvent(QKeyEvent * event)
{
if(event->key() == Qt::Key_Left)
playerX--;
else if(event->key() == Qt::Key_Right)
playerX++;
else if(event->key() == Qt::Key_Up)
playerY--;
else if(event->key() == Qt::Key_Down)
playerY++;
}
Here's paint code:
void NiceItem::paint(QPainter *painter)
{
QPen pen(m_color, 2);
painter->setPen(pen);
QRectF rectangle(playerX, playerY, 80.0, 60.0);
painter->drawRect(rectangle);
update();
}
As you can see code is really simple. Rectangle is successfully drawn on the screen, but pressing arrows does nothing. Is this a wrong method? If so, how can I process the keyboard input?
For an Item to receive the mouse event, it must meet the following:
Have the flag QQuickItem::ItemIsFocusScope enabled.
Having focus, this can be done in C++ with setFocus(true) or in QML: focus: true.
On the other hand, if your objective is to draw a rectangle on the window, then you have an error in the concept of what coordinates are used for the painting, the painting uses the local coordinates and not the window or screen. So instead of creating new attributes you should only use position(), x(), y() (and their setters) to modify the geometry since these elements are with respect to the parent's coordinates.
#ifndef NICEITEM_H
#define NICEITEM_H
#include <QQuickPaintedItem>
class NiceItem : public QQuickPaintedItem
{
Q_OBJECT
public:
NiceItem(QQuickItem *parent=nullptr);
void paint(QPainter *painter);
protected:
void keyPressEvent(QKeyEvent *event);
private:
QColor m_color;
};
#endif // NICEITEM_H
#include "niceitem.h"
#include <QPainter>
#include <QPen>
NiceItem::NiceItem(QQuickItem *parent):
QQuickPaintedItem(parent), m_color(QColor("red"))
{
setFlag(QQuickItem::ItemIsFocusScope, true);
setFocus(true);
setSize(QSizeF(80.0, 60.0));
}
void NiceItem::paint(QPainter *painter)
{
QPen pen(m_color, 2);
painter->setPen(pen);
painter->drawRect(boundingRect());
}
void NiceItem::keyPressEvent(QKeyEvent *event)
{
QPointF delta;
if(event->key() == Qt::Key_Left)
delta = QPointF(-1, 0);
else if(event->key() == Qt::Key_Right)
delta = QPointF(+1, 0);
else if(event->key() == Qt::Key_Up)
delta = QPointF(0, -1);
else if(event->key() == Qt::Key_Down)
delta = QPointF(0, +1);
setPosition(position() + delta);
}

Qt rubberband not being drawn

I am attempting to implement a rubberband. Here is my code.
void TOTMain::mousePressEvent(QMouseEvent * event)
{
QPoint origin = event->pos();
_selectionSquare = new QRubberBand(QRubberBand::Rectangle, this);
_selectionSquare->setGeometry(QRect(origin, QSize()));
_selectionSquare->raise();
_selectionSquare->show();
}
void TOTMain::mouseMoveEvent(QMouseEvent *event)
{
QPoint origin = event->pos();
_selectionSquare->setGeometry(QRect(origin, event->pos()).normalized());
}
void TOTMain::mouseReleaseEvent(QMouseEvent *event)
{
_selectionSquare->hide();
// determine selection, for example using QRect::intersects()
// and QRect::contains().
}
The issue is that the band is not being drawn. I confirm it is being constructed and persists through the dragging, but no rendering.
Any ideas appreciated.
Take a look at your mouseMoveEvent implementation...
void TOTMain::mouseMoveEvent(QMouseEvent *event)
{
QPoint origin = event->pos();
_selectionSquare->setGeometry(QRect(origin, event->pos()).normalized());
}
You're setting the geometry of the rubber band to QRect(origin, event->pos()), but you've previously set origin = event->pos() so the top-left and bottom-right corners of the rectangle are the same.
Make origin a member variable variable of your class (untested)...
class TOTMain: public QWidget {
public:
protected:
virtual void mousePressEvent (QMouseEvent *event) override
{
_origin = event->pos();
_selectionSquare = new QRubberBand(QRubberBand::Rectangle, this);
_selectionSquare->setGeometry(QRect(_origin, QSize()));
_selectionSquare->raise();
_selectionSquare->setStyleSheet("{ background-color : red; }");
_selectionSquare->show();
}
virtual void mouseMoveEvent (QMouseEvent *event) override
{
_selectionSquare->setGeometry(QRect(_origin, event->pos()).normalized());
}
virtual void mouseReleaseEvent (QMouseEvent *event) override
{
_selectionSquare->hide();
// determine selection, for example using QRect::intersects()
// and QRect::contains().
}
private:
QPoint _origin;
QRubberBand *_selectionSquare = nullptr;
};

How to move the whole window when mouse is on the window's custom widget in Qt?

Let's say I have a custom widget and add it to the main window in qt.
As you can see, the red area is the custom widget. What I want to do is when the mouse is pressed in the red area and moved, the whole window will move as well.
I know how to simply implement mousePressEvent and mouseMoveEvent; but when dealing with a window with the custom widget, I do not know how to move the whole window when mouse is pressed on the custom widget.
Also I want to mention that I only want the window movable when mouse is pressed and moved in the red area, and when mouse is pressed and moved in the rest part of the main window area, nothing will happen.
This is what my CustomWidget class looks like:
CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
{
setFixedSize(50, 50);
setStyleSheet("QWidget { background: red; }");
}
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter painter(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
}
void CustomWidget::mousePressEvent(QMouseEvent *event)
{
xCoord = event->x();
yCoord = event->y();
}
void CustomWidget::mouseMoveEvent(QMouseEvent *event)
{
move(event->globalX() - xCoord, event->globalY() - yCoord);
}
In case you wonder why I want to do this, in my app, I hid the title bar and drew a custom title bar by myself. But the window is not movable, so I want to make the whole window movable when mouse is pressed and moved on the title bar.
Hope I explained myself clearly.
To move the window from any widget it is necessary to be able to access the window, and for this we use the method window() that returns the top level, it is not necessary to separate the coordinates x() and y(), the following code implements the solution:
customwidget.h
#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H
#include <QWidget>
class CustomWidget : public QWidget
{
Q_OBJECT
public:
explicit CustomWidget(QWidget *parent = nullptr);
protected:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QPoint startPos;
};
#endif // CUSTOMWIDGET_H
customwidget.cpp
#include "customwidget.h"
#include <QMouseEvent>
#include <QPainter>
#include <QStyleOption>
CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
{
setFixedSize(50, 50);
setStyleSheet("QWidget { background: red; }");
}
void CustomWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter painter(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
}
void CustomWidget::mousePressEvent(QMouseEvent *event)
{
startPos = event->pos();
QWidget::mousePressEvent(event);
}
void CustomWidget::mouseMoveEvent(QMouseEvent *event)
{
QPoint delta = event->pos() - startPos;
QWidget * w = window();
if(w)
w->move(w->pos() + delta);
QWidget::mouseMoveEvent(event);
}
If you are working on Windows, can use it:
#include "mywidget.h"
#include <windows.h>
#include <QWindow>
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
}
MyWidget::~MyWidget()
{
}
void MyWidget::mousePressEvent(QMouseEvent* event)
{
if (event->buttons().testFlag(Qt::LeftButton))
{
HWND hWnd = ::GetAncestor((HWND)(window()->windowHandle()->winId()), GA_ROOT);
POINT pt;
::GetCursorPos(&pt);
::ReleaseCapture();
::SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, POINTTOPOINTS(pt));
}
}
void QHexWindow::mousePressEvent(QMouseEvent *event)
{
QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
if (child!=mTitleBar) //mTitlebar is the QLabel on which we want to implement window drag
{
return;
}
isMousePressed = true;
mStartPos = event->pos();
}
void QHexWindow::mouseMoveEvent(QMouseEvent *event)
{
if(isMousePressed)
{
QPoint deltaPos = event->pos() - mStartPos;
this->move(this->pos()+deltaPos);
}
}
void QHexWindow::mouseReleaseEvent(QMouseEvent *event)
{
QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
if (child!=mTitleBar)
{
return;
}
isMousePressed = false;
}
I have implemented the above in one of my github project https://github.com/VinuRajaKumar/AVR-HEX-Viewer where QLabel is used as TitleBar for the window.

How can I recognize QGraphicsView mouse move event?

I am new in qt and c++. I have a qgraphicsview to plot signal. I would zoom specific area with mouse clicking and rectangle drawing. So I need mouse pressed position and dragged position. For this I do such this:
in header file:
#include <QtWidgets/QMainWindow>
#include <QGraphicsScene>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
#include "ui_QtGuiApplication.h"
class QtGuiApplication : public QMainWindow
{
Q_OBJECT
public:
QtGuiApplication(QWidget *parent = Q_NULLPTR);
protected:
void mouseMoveEvent(QMouseEvent* event);
void mousePressEvent(QMouseEvent* event);
bool eventFilter(QObject *obj, QEvent *ev);
private:
Ui::QtGuiApplicationClass ui;
QPoint Zoom_point1_;
QPoint Zoom_point2_;
QGraphicsScene* scene = new QGraphicsScene();
};
in source file:
QtGuiApplication::QtGuiApplication(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.graphicsView->installEventFilter(this);
ui.graphicsView->setMouseTracking(true);
}
bool QtGuiApplication::eventFilter(QObject * obj, QEvent * ev)
{
if (obj == ui.graphicsView)
if (ev->type() == QEvent::MouseMove)
{
QMouseEvent *mEvent = (QMouseEvent*)ev;
Zoom_point2_ = mEvent->pos();
}
return false;
}
void QtGuiApplication::mouseMoveEvent(QMouseEvent * ev)
{
Zoom_point2_ = ev->globalPos();
//do some thing …
}
void QtGuiApplication::mousePressEvent(QMouseEvent * ev)
{
Zoom_point1_ = ev->globalPos();
}
When I press and move mouse in graphicsview, I can recognize the clicked position but mouseMoveEvent(QMouseEvent * ev) never be calle. and also obj == ui.graphicsView statement in eventFilter never be occurred.What's wrong with me? How can I fix it?
By Installing event filter on the viewport of the QgraphicsView object such as
ui.graphicsView->viewport()->installEventFilter(this);
and adding below condition on eventfilter
if (ui.graphicsView->viewport())
if (ev->type() == QEvent::MouseMove)
{
QMouseEvent *mEvent = (QMouseEvent*)ev;
Zoom_point2_ = mEvent->pos();
}
problem solved.

How to remove cropped rect from QImage/QLabel?

I did sub-classing to include mouse click function. Here, a rectangle can be chosen by mousePressEvent, mouseMoveEvent and mouseReleaseEvent. When I am trying to chose another rectangle, my previous rectangle is not being removed. It is still displaying with my previous drawn rectangle, which I don't want to display. I want to chose and display only one rectangle. I meant when I press again to chose another rectange, the previous one should be removed.
I included here my subclass named mouse_crop
mouse_crop.h is as follows
#ifndef MOUSE_CROP_H
#define MOUSE_CROP_H
#include <QMainWindow>
#include <QObject>
#include <QWidget>
#include <QMouseEvent>
#include <QLabel>
#include <QRubberBand>
class mouse_crop : public QLabel
{
Q_OBJECT
public:
mouse_crop(QWidget *parent=0);
QRubberBand *rubberBand;
QPoint origin, ending;
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
signals:
void sendMousePosition(QPoint&);
void sendMouseEnding(QPoint&);
};
#endif // MOUSE_CROP_H`
And mouse_crop.cpp is as follows
#include "mouse_crop.h"
mouse_crop::mouse_crop(QWidget *parent):QLabel (parent)
{
}
void mouse_crop::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
rubberBand->show();
emit sendMousePosition(origin);
}
}
void mouse_crop::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin, ev->pos()).normalized());
}
void mouse_crop::mouseReleaseEvent(QMouseEvent *ev)
{
ending = ev->globalPos();
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
emit sendMouseEnding(ending);
}
}
Can any one tell me how to solve this? Thanks in advance.
The problem is caused because every time you press the mouse you are creating a new QRubberBand, what you must do is create only a QRubberBand, hide it and show it when necessary.
mouse_crop::mouse_crop(QWidget *parent)
: QLabel(parent)
{
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->hide();
}
void mouse_crop::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
rubberBand->setGeometry(QRect(origin, origin));
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
rubberBand->show();
emit sendMousePosition(origin);
}
}
void mouse_crop::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin, ev->pos()).normalized());
}
void mouse_crop::mouseReleaseEvent(QMouseEvent *ev)
{
ending = ev->globalPos();
if(ev->button()== Qt::LeftButton || ev->button()== Qt::RightButton)
{
emit sendMouseEnding(ending);
}
}