Should I use QDialog widget to draw line?
-
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; }
-
-
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); }
-
Oh, if you need QScrollArea + zoom, I'm afraid QGraphics* classes are more suitable for that.
For current method, I don't know if this will take any affect, but you can try not scaling the pixmap, but the painter.
Change your paintEvent tovoid DrawingLabel::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.scale(m_zoomRatio, m_zoomRatio); painter.drawPixmap(0,0,m_drawingPixmap); }
And in your wheelEvent, dont' create and set new pixmap, just set the zoomed fixed size.