I am trying to get a mouse press event to work with my widget I created but every time I click the widget, the window stops responding and I have to kill the program. Does anyone know how to fix this and also how to get the color to change?
Here is the .h and the .cpp files.
.cpp file:
#include "iconwidget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPainterPath>
iconWidget::iconWidget(QWidget *parent) :
QWidget(parent)
{
this->resize(ICON_WIDGET_WIDTH,ICON_WIDGET_HEIGHT);
pressed = false;
}
void iconWidget::paintEvent(QPaintEvent *event)
{
QRect areatopaint = event->rect();
QPainter painter(this);
QBrush brush(Qt::black);
QPointF center = this->rect().center();
QPainterPath icon;
icon.addEllipse(center,20,20);
painter.drawPath(icon);
painter.fillPath(icon, brush);
if (pressed) {
brush.setColor(Qt::red);
}
}
void iconWidget::mousePressEvent(QMouseEvent *event)
{
pressed = true;
update();
iconWidget::mousePressEvent(event);
}
.h file:
#define ICONWIDGET_H
#include <QWidget>
#define ICON_WIDGET_WIDTH 45
#define ICON_WIDGET_HEIGHT 45
class iconWidget : public QWidget
{
Q_OBJECT
public:
explicit iconWidget(QWidget *parent = 0);
void paintEvent(QPaintEvent *event);
bool pressed;
protected:
void mousePressEvent(QMouseEvent *event);
};
#endif // ICONWIDGET_H
You call mousePressEvent() in an endless recursion. You should change the line:
iconWidget::mousePressEvent(event);
in your mousePressEvent function to:
QWidget::mousePressEvent(event);
Related
I'm trying to create a canvas to draw on with the mouse similar to most digital painting applications that I can also zoom in on (zoom in on the drawn image)
So far I've created a class that uses QWidget and added it to the ui then use the mouse events and QPaintEvent to draw on this widget which works. However the problem I'm not sure how do I zoom on this as well? I tried placing the QWidget inside of a scrollable area but it stops it from registering click events. I also tried extending from QGraphicsViewer instead of QWidget but this stops me from being able to paint as well.
//Class definition
PaintArea::PaintArea(QWidget *parent) : QWidget(parent)
{
this->setMouseTracking(true);
}
I'm mostly looking for a recommendation of how to scrolling and drawing with a mouse on the same widget (Possibly with scroll bar but just wheel scrolling for sure)
Thanks
If you follow the QWidget way, you may want to look carefully to the scribble example that is included with Qt docs. In this example, the drawing is made off-screen on a QImage object, which is then painted by the widget. The problem is to zoom the image.
I prefer your second way: QGraphicsView has a scale() function among many other excellent features. You may do something similar to the scribble example: draw off-screen on a QPixmap image which is set (every time you change the image) into a QGraphicsPixmapItem which belongs to the QGraphicsScene. I've implemented this crude example, borrowing some elements from the scribble example. Use the mouse wheel to zoom the image (it screws the scrolling a bit, sorry).
test.pro
QT += core gui widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
drawablescene.cpp \
main.cpp \
mainwindow.cpp
HEADERS += \
drawablescene.h \
mainwindow.h
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "drawablescene.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
void wheelEvent(QWheelEvent *event) override;
private:
QGraphicsView *m_view;
DrawableScene *m_scene;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include <QGraphicsView>
#include <QWheelEvent>
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent),
m_view(new QGraphicsView(this)),
m_scene(new DrawableScene(this))
{
setCentralWidget(m_view);
m_scene->setSceneRect(0,0,640,480);
m_view->setScene(m_scene);
}
void MainWindow::wheelEvent(QWheelEvent *event)
{
qreal delta = 1 + (event->delta() > 0 ? 0.1 : -0.1);
m_view->scale(delta, delta);
event->accept();
}
drawablescene.h
#ifndef DRAWABLESCENE_H
#define DRAWABLESCENE_H
#include <QObject>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
class DrawableScene : public QGraphicsScene
{
public:
explicit DrawableScene(QObject *parent = nullptr);
private:
void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
void drawLineTo(const QPointF &endPoint);
bool m_modified;
bool m_scribbling;
int m_penWidth;
QColor m_penColor;
QPointF m_lastPoint;
QPixmap *m_image;
QGraphicsPixmapItem *m_item;
};
#endif // DRAWABLESCENE_H
drawablescene.cpp
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include "drawablescene.h"
DrawableScene::DrawableScene(QObject *parent)
: QGraphicsScene(parent),
m_modified(false),
m_scribbling(false),
m_penWidth(3),
m_penColor(Qt::blue)
{
m_image = new QPixmap(640, 480);
m_image->fill(Qt::white);
m_item = addPixmap(*m_image);
}
void DrawableScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && m_scribbling) {
drawLineTo(event->scenePos());
event->accept();
}
else QGraphicsScene::mouseMoveEvent(event);
}
void DrawableScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
m_lastPoint = event->scenePos();
m_scribbling = true;
event->accept();
}
else QGraphicsScene::mousePressEvent(event);
}
void DrawableScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton && m_scribbling) {
drawLineTo(event->scenePos());
m_scribbling = false;
event->accept();
}
else QGraphicsScene::mouseReleaseEvent(event);
}
void DrawableScene::drawLineTo(const QPointF &endPoint)
{
QPainter painter(m_image);
painter.setPen(QPen(m_penColor, m_penWidth, Qt::SolidLine, Qt::RoundCap,Qt::RoundJoin));
painter.drawLine(m_lastPoint, endPoint);
m_modified = true;
m_lastPoint = endPoint;
m_item->setPixmap(*m_image);
}
I want to select an area on a custom video widget and draw rectangle on selected area.
So far I can select an area with QRubberband but I am having trouble with drawing the rectangle after releasing left click.
Whenever I click-drag then release to draw rectangle it gives this error:
QBackingStore::endPaint() called with active painter on backingstore paint device
The program has unexpectedly finished.
Here is my code:
myvideoobject.h
#ifndef MYVIDEOOBJECT_H
#define MYVIDEOOBJECT_H
#include <QObject>
#include <QVideoWidget>
#include <QRubberBand>
#include <QPainter>
#include <QPen>
#include <QPaintEvent>
#include <QRect>
#include <QMouseEvent>
#include <QDebug>
class MyVideoObject : public QVideoWidget
{
Q_OBJECT
public:
explicit MyVideoObject(QWidget *parent = 0);
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void paintEvent(QPaintEvent *ev);
private:
QRubberBand* rubberBand;
QPainter* painter;
//QRect *rectangle;
QPoint origin;
QPoint endPoint;
};
#endif // MYVIDEOOBJECT_H
myvideoobject.cpp
#include "myvideoobject.h"
MyVideoObject::MyVideoObject(QWidget* parent) :
QVideoWidget(parent)
{
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(0,0,50,50);//ileride silebilrisin
}
void MyVideoObject::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin,ev->pos()).normalized());
}
void MyVideoObject::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
if(!rubberBand)
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(QRect(origin,QSize()));
rubberBand->show();
}
void MyVideoObject::mouseReleaseEvent(QMouseEvent *ev)
{
rubberBand->hide();
endPoint = ev->pos();
painter->begin(this);
painter->drawRect(QRect(origin,endPoint));
}
void MyVideoObject::paintEvent(QPaintEvent *ev)
{
QRect rect = ev->rect();
painter = new QPainter(this);
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::black);
painter->drawText(rect,Qt::AlignCenter,"Data");
painter->drawRect(rect);
//painter->setPen(Qt::red);
}
I didn't add mainwindow.cpp and mainwindow.h cuz there isn't much code in those other than selecting video with openfiledialog.
When you create a pointer: QPainter *painter, this can point to any memory since it has garbage. so when you do painter->begin(this) you are accessing uninitialized memory, that's why you get that error. On the other hand in a QWidget such as QVideoWidget should only be painted in the method paintEvent, the strategy is to have variables that save the state of what you want to paint, for example the QRect, and call update to paint it.
myvideoobject.h
#ifndef MYVIDEOOBJECT_H
#define MYVIDEOOBJECT_H
#include <QVideoWidget>
class QRubberBand;
class MyVideoObject : public QVideoWidget
{
public:
MyVideoObject(QWidget *parent = nullptr);
protected:
void mouseMoveEvent(QMouseEvent *ev);
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void paintEvent(QPaintEvent *ev);
private:
QRubberBand *rubberBand;
QPoint origin;
QRect rect;
};
#endif // MYVIDEOOBJECT_H
myvideoobject.cpp
#include "myvideoobject.h"
#include <QMouseEvent>
#include <QPainter>
#include <QRubberBand>
MyVideoObject::MyVideoObject(QWidget *parent):
QVideoWidget(parent),
rubberBand(nullptr){}
void MyVideoObject::mousePressEvent(QMouseEvent *ev)
{
origin = ev->pos();
if(!rubberBand)
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
rubberBand->setGeometry(QRect(origin,QSize()));
rubberBand->show();
QVideoWidget::mousePressEvent(ev);
}
void MyVideoObject::mouseMoveEvent(QMouseEvent *ev)
{
rubberBand->setGeometry(QRect(origin,ev->pos()).normalized());
QVideoWidget::mouseMoveEvent(ev);
}
void MyVideoObject::mouseReleaseEvent(QMouseEvent *ev)
{
rect = rubberBand->geometry();
update();
QVideoWidget::mouseReleaseEvent(ev);
}
void MyVideoObject::paintEvent(QPaintEvent *ev)
{
QVideoWidget::paintEvent(ev);
QPainter painter(this);
painter.save();
painter.setBrush(Qt::red);
if(!rect.isNull())
painter.drawRect(rect);
painter.restore();
}
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.
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.
I have a window based on a semitransparent image:
import QtQuick 1.1
import QtWebKit 1.1
Image {
source: "qrc:/assets/bg.png"
}
And something like this in main window
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setAttribute(Qt::WA_TranslucentBackground);
setStyleSheet("background:transparent;");
/* turn off window decorations */
setWindowFlags(Qt::FramelessWindowHint);
ui = new QDeclarativeView;
ui->setSource(QUrl("qrc:/assets/ui.qml"));\
setCentralWidget(ui);
}
MainWindow::~MainWindow()
{
delete ui;
}
and
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtDeclarative/QDeclarativeView>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QDeclarativeView *ui;
};
#endif // MAINWINDOW_H
I wonder how to make my window draggable across the screen (user presses on an image and drugs window around..)?
Reimplement mousePressEvent() and mouseReleaseEvent() to know when the user is holding the mouse down, then reimplement mouseMoveEvent() and if the user is holding the mouse down, move the widget.
// **Untested code**
protected:
virtual void mousePressEvent(QMouseEvent *event) { _mouseIsDown = true; }
virtual void mouseReleaseEvent(QMouseEvent *event) { _mouseIsDown = false; }
virtual void mouseMoveEvent(QMouseEvent *event) { if(_mouseIsDown) { move(event->pos() + globalPos()); } }
#include <QMouseEvent>
#include <Qpoint>
class MainWindow : public QMainWindow{
...
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
QPoint LastPoint;
QPoint LastTopLeft;
void mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
QPoint Point=event->globalPos();
LastTopLeft=this->frameGeometry().topLeft();
LastPoint=Point;
}
}
void mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton)) {
const QPoint Point=event->globalPos();
QPoint offset=Point-LastPoint;
this->move(LastTopLeft+offset);
}
}
...
}
It worked for me after I removed the first two declarations.