Should I use QDialog widget to draw line?
-
I have a
QDialog
with a sole purpose to draw lines and display image. In the dialog ui, I have added aQGraphicsView
, and then in the code, I gave it aQGraphicsScene
and created aQGraphicsLineItem
ready to draw.The problem is what widget do I initiate the draw? I need the
mousePressEvent()
,mouseMoveEvent()
andmouseReleaseEvent()
in order to start drawing.I tried the mouseEvent with QDialog, but it doesn't have any event function. I couldn't even get the current mouse position from its event.
void DrawingDialog::mousePressEvent(QMouseEvent *a_pEvent) { a_pEvent-> // autocompleter didn't show anything }
-
I have been following the scribbling example to draw the image and line in a QGraphicsScene. But I don't know why my
QPainter
doesn't work in paintEvent();header
class Canvas : public QGraphicsScene { ... protected: void mousePressEvent(QGraphicsSceneMouseEvent *event) override; void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; void drawForeground(QPainter *painter, const QRectF &rect) override; void paintEvent(QPaintEvent * event); }
source
void Canvas::paintEvent(QPaintEvent *event) { QPainter painter(this); QRect dirtyRect = event->rect(); painter.drawImage(dirtyRect, image, dirtyRect); }
I got the error
canvas.cpp:69:14: error: no matching constructor for initialization of 'QPainter' qpainter.h:127:14: note: candidate constructor not viable: no known conversion from 'Canvas *' to 'QPaintDevice *' for 1st argument
-
Just as the error told you: QGraphicsScene is not a QPaintDevice, you cannot use QPainter like that.
There's even not a paintEvent in QGraphicsScene, only QGraphicsView have that.
The example draws on a non-graphics QWidget, but you are not.
If you want to draw like this, then don't use QGraphicsView / QGraphicsScene, just inherit a QWidget. -
@lansing
Just pick from those two methods (QGraphicsScene + QGraphicsView / QWidget + QPainter), they are totally different.
You shouldn't "paint" by yourself if you use QGraphicsScene + QGraphicsView.
Use QGraphicsScene::addLine to add the line, the painting part will be finished by themselves. -
@lansing
Depending on how complicated it will be.
If you only want to draw like "press, drag, release, done", then you may use QWidget + QPainter.
But you need to save the lines you draw as member variables (the Scribble example save them to a QImage).
If you want move or do other transform operations to the drawn lines, you need to use QGraphicsScene + QGraphicsView.
You may also look at this example: Diagram Scene Example
It have some line drawing thing in a QGraphicsScene (but in this example the line will be deleted when releasing the mouse) -
I have followed the scribble example to use
QWidget
andQPainter
to draw line. I have used QPixmap to hold the line drawing instead of QImage from the example. The drawing works fine until I centered the QPixmap inpaintEvent()
, my drawing wasn't centered along with the QPixmap.void Canvas::mousePressEvent(QMouseEvent *a_pEvent) { if (a_pEvent->button() == Qt::LeftButton) { m_drawing = true; m_lastPoint = a_pEvent->pos(); } } void Canvas::mouseMoveEvent(QMouseEvent *a_pEvent) { if ((a_pEvent->buttons() & Qt::LeftButton) && m_drawing) { drawPointTo(a_pEvent->pos()); } } void Canvas::paintEvent(QPaintEvent *event) { QPainter painter(this); /* center image */ painter.drawPixmap((rect().bottomRight() - m_drawingPixmap.rect().bottomRight()) / 2, m_drawingPixmap); painter.end(); } void Canvas::drawPointTo(const QPointF &a_endPoint) { QPainter painter(&m_drawingPixmap); painter.setPen(QPen(Qt::black, 2)); painter.drawLine(m_lastPoint, a_endPoint); update(); m_lastPoint = a_endPoint; }
-
@lansing
I think that's not hard to understand.
If your pixmap's top left isn't the same with the widget, then they have different coordinate system.
You need to map your points' coordinates from the widget to the pixmap when saving. -
How do I do that? I did a few trials and errors but still couldn't get it right.
So I ended up subclassing a QLabel class and added it to the canvas, and then set the pixmap and move all the paintEvent, mouse event functions to this label class.
Do I not need to do this?
-
@lansing
If you feel the mapping difficult I think it is no problem to put a centered "painting QWidget" inside your canvas.
But what's wrong with just subclass a QWidget and add that to the canvas?
Do you have a reason that you must use a QLabel? -
The QLabel is the "centered Qwidget" you talked of. Because it can hold a QPixmap for the line drawing, have all the mouse event functions and paintEvent, as well as able to retrieve the position.
canvas
Canvas::Canvas(QWidget *a_pParent): QWidget(a_pParent), { m_drawingLabel = new DrawingLabel(this); QHBoxLayout *layout = new QHBoxLayout(); layout->addWidget(m_drawingLabel ); setLayout(layout); } void Canvas::drawFrame(const QPixmap &a_drawingPixmap) { // center the Qlabel when loading in the pixmap int x = (rect().width() - a_drawingPixmap.width()) / 2 ; int y = (rect().height() - a_drawingPixmap.height()) /2; m_drawingLabel ->setGeometry (x, y, a_drawingPixmap.width(), a_drawingPixmap.height()); m_drawingLabel ->setDrawingPixmap(a_drawingPixmap); }
qlabel
void DrawingLabel::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.drawPixmap(0,0,m_drawingPixmap); painter.end(); } void DrawingLabel::setDrawingPixmap(const QPixmap & a_pixmap) { m_drawingPixmap= a_pixmap; update(); } void DrawingLabel::mousePressEvent(QMouseEvent *a_pEvent) { if (a_pEvent->button() == Qt::LeftButton) { m_drawing = true; m_lastPoint = a_pEvent->pos(); } } ... mousePressEvent() mouseReleaseEvent() drawPointTo()
-
@lansing
I mean I don't think it is necessary to use a QLabel as the centered widget since you don't seem to use any QLabel functions.
Why can't you just subclass a QWidget as the "DrawingLabel"?And also, why are you setting the geometry while you are using a layout?
That don't make any sense. -
@lansing
You either use a layout to keep the label centered, or set the geometry by yourself and don't use any layout.
Set geometry to a widget managed by a layout is meaningless, the layout may reset its geometry at any time.
You can use the layout like that:layout->addWidget(m_drawingLabel, Qt::AlignCenter);
void Canvas::drawFrame(const QPixmap &a_drawingPixmap) { m_drawingLabel->setFixedSize(a_drawingPixmap.size()); m_drawingLabel->setDrawingPixmap(a_drawingPixmap); }
-
This post is deleted!
-
I'm not spreading myself too thin right now, I'll stick to one method first until it worked well before I try other methods.
So I got it working under normal condition. I have changed the canvas to subclass a
QScrollArea
because I need to zoom in. I did the zoom function in thewheelEvent()
. However, the problem now is with theQPixmap.scaled
function, the more I zoomed in, the more laggy the program got.void Canvas::wheelEvent(QWheelEvent *a_pEvent) { QPoint delta = a_pEvent->angleDelta(); // zooming if (delta.y() > 0) { m_zoomRatio += 0.6; } else { m_zoomRatio -= 0.6; } m_drawingLabel->setFixedSize(m_drawingPixmap.size() * m_zoomRatio); QSize zoomSize = m_drawingPixmap.size() * m_zoomRatio; m_drawingLabel->setDrawingPixmap(m_drawingPixmap.scaled(zoomSize)); } void Canvas::drawFrame(const QPixmap &a_drawingPixmap) { m_drawingPixmap = a_drawingPixmap; // save a copy for zooming m_drawingLabel->setFixedSize(a_drawingPixmap.size()); m_drawingLabel->setDrawingPixmap(a_drawingPixmap); }
3/24