Reputation: 241
I am trying to create a simple painting application - it is just supposed to draw when you click and drag a cursor (just like Paint). I know I have to use QPainter
but how can I handle it? How to do it? Any help would be really appreciated. I tried lurking through internet but didn't find too much info (I daw drawing lines etc. by code that you launch an app and it is here but I can not find an example of drawing something by user).
Upvotes: 0
Views: 3031
Reputation: 73091
It's a pretty broad question, but here are the basics:
QWidget
class, so that you can override some of its virtual methods later on.show()
on it (just before calling QApplication::exec()
). This object will appear on screen as a very simple window, and it will serve as your user's painting-surface.QPixmap
object that you will use to store the bitmap that the user will draw. Make sure to size the QPixmap
to be at least as big as the maximum size of the window that you want to support. Call fill()
on the QPixmap
to fill it with your favorite background color.mousePressEvent(QMouseEvent *)
method of your object to set a boolean is_mouse_down flag, and also to record the current position of the mouse pointer within the window (by calling pos()
on the QMouseEvent
object that gets passed in to the mousePressEvent()
call and storing that into a member variable of your object).mouseMoveEvent(QMouseEvent *)
method so that if is_mouse_down_is
set to true
, it creates a QPainter
object on the stack -- pass a pointer to the QPixmap
to the QPainter
object's constructor so that the QPainter
will draw into your QPixmap
object. Then call drawLine()
on the QPainter
object to draw a line from the previous mouse position to your current one. Finally, call update()
to tell Qt to call paintEvent()
for you ASAP.mouseReleaseEvent(QMouseEvent *)
method to set is_mouse_down
to false againpaintEvent(QPaintEvent *)
method to create a QPainter
object on the stack -- pass a pointer to (this
) to the QPainter
object's constructor, so that it will paint onto the QWidget
directly. Then call drawPixmap() on the QPainter
object so that it will draw your QPixmap
object onto the widget's visible surface.If you'd like to see a pre-written example, check out the Scribble application included with Qt, in $QTDIR/examples/widgets/widgets/scribble
.
Upvotes: 2
Reputation: 98435
Here's Jeremy's answer in code instead of prose:
// https://github.com/KubaO/stackoverflown/tree/master/questions/simplepaint-39358392
#include <QtWidgets>
// Make a subclass of the QWidget class, so that you can override some of its
// virtual methods
class PaintWidget : public QWidget {
// Create a QPixmap object that you will use to store the bitmap
// that the user will draw [on].
QPixmap m_pixmap;
QPoint m_lastPos;
// Override the paintEvent(QPaintEvent *) [...]
void paintEvent(QPaintEvent *) override {
QPainter painter{this};
painter.drawPixmap(0, 0, m_pixmap);
}
void resizeEvent(QResizeEvent *) override {
// [...] size the QPixmap to be at least as big as the maximum size of the window
// We'll also never let it shrink so as not to lose the already drawn image.
auto newRect = m_pixmap.rect().united(rect());
if (newRect == m_pixmap.rect()) return;
QPixmap newPixmap{newRect.size()};
QPainter painter{&newPixmap};
painter.fillRect(newPixmap.rect(), Qt::white);
painter.drawPixmap(0, 0, m_pixmap);
m_pixmap = newPixmap;
}
// Override the mousePressEvent(QMouseEvent *) [...]
void mousePressEvent(QMouseEvent * ev) override {
m_lastPos = ev->pos();
draw(ev->pos());
}
// Override the mouseMoveEvent(QMouseEvent *) [...]
void mouseMoveEvent(QMouseEvent * ev) override {
draw(ev->pos());
}
void draw(const QPoint & pos) {
QPainter painter{&m_pixmap};
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen({Qt::blue, 2.0});
painter.drawLine(m_lastPos, pos);
m_lastPos = pos;
update();
}
public:
using QWidget::QWidget;
};
int main(int argc, char ** argv) {
QApplication app{argc, argv};
// Create an object of your subclass and call show()
PaintWidget ui;
ui.show();
return app.exec();
}
It is not necessary to override the mouseReleaseEvent
. In a widget, the default behavior is to track the mouse movement only when a mouse button is depressed. The mouseMoveEvent
won't be called unless a button is depressed.
Upvotes: 5