Important: Please read the Qt Code of Conduct -

"Not so basic" drawing application

  • Hi there, I am looking for suggestions how to implement a basic drawing program that consists of a pixmap brush that leaves imprints of itself on another pixmap (the canvas) when the mouse key is pressed, at the appropriate location.

    I tried to find something like that in the examples, but I didn't find anything. Any suggestions?


  • Finger Paint Example maybe?
    You only use QMouseEvent instead of QTouchEvent.


  • ah yes, I missed this one, will take a look

    I actually did half the work already, but now I need to find a way to continiously do it while the mouse is pressed and moved, currently I only print the brush on the canvas in the location of click only upon mouse click.

  • Too late.

  • You still have a chance to redeem yourself ;)

    I have another problem - when I move the mouse faster there is nasty spacing in between the painting.


    I suppose I can fix that if I increase the rate at which events are updated, since QWidget is optimized for basic GUI stuff it doesn't update nearly as fast enough to produce smooth lines when the mouse is moved faster, a performance optimization that makes sense but not in the current case.

    So how can I increase the frequency with which events are polled?

  • have a look at the scribble example. It does what you want. at least when testing I couldn't get your results , but maybe you are much faster than I am ;-)

  • Why don't you change the logic of the painting instead? It looks like now you are paiting a point whereever you find the mouse, but why don't you draw a line between where your mouse last was and your mouse is now instead?

  • [quote author="Andre" date="1330617520"]Why don't you change the logic of the painting instead? It looks like now you are paiting a point whereever you find the mouse, but why don't you draw a line between where your mouse last was and your mouse is now instead?[/quote]

    Because this is not the way a drawing application works. If I wanted to just create lines, I would have done exactly that. I need drawing logic that can draw with different stencils / brushes much like photoshop, and in fact the user needs to be able to create his own custom brushes. The location of brushes must be randomized, the size - dynamic, brushes must rotate and all that stuff, scatter and so on, this cannot be achieved by drawing lines between locations on the screen.

    There is nothing wrong with the logic of the painting as it is, I tested it with very big stencils and performance is great, the bottleneck is the update rate of the event loop.

    How can I control it, so I can make it faster while drawing?

  • You can not control it, that's the point. Perhaps you should not use lines as such, but you should probably use the last and the current position of the mouse to do your rendering. You simply cannot rely on getting a mouse move event for every pixel on your screen you pass over.

    You could perhaps use the moving speed in some way, using not only the last and the previous position, but also the time between these events. That would allow you to gauge if the user is very quick, or your system is just a bit slow. That might result in a different stroke in terms of your painting.

  • I see I will have to interpolate to get the in-between polling locations...

    I noticed photoshop has an option on the brush called "spacing" and with it disabled, it behaves EXACTLY the same way as my test application. In fact the spacing in photoshop is even larger, probably because the application is heavy on the cpu.

  • So, my next logical question is if there is a way to "draw a line" but not with a pen but by dragging a pixmap or a QBrush? I was just looking through the doc and all the methods for drawing lines involve QPen or a stroke which doesn't seem to be able to consist of an image.

    If not, I will have to do go back to the tedious interpolation...

  • Well, a QPen consists of a QBrush consists of a QPixmap.

  • Yes, but it works nowhere near the way I need it to. Here is what it looks like:

    I don't need to fill the "volume" of the line with a pattern of the QBrush, I need to paint by dragging the brush for every pixel of the line. Notice the subtle difference? :)

  • Have you looked at the scribble example?

  • Yes, it only uses an outline pen, it will work for the image posted above but it wont work for something like this:


    The whole point is to not be restricted to a plain line (like scribble example is) but be able to paint by dragging the stencil you want to draw with.

    Here is what scribble draws with:

    @painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
    painter.drawLine(lastPoint, endPoint);@

    And in fact, my very first post states that I failed to find what I need in the examples ;)

  • Looks like this code will do exactly what you just showed above in your second example, and that you showed as an example of what you wanted...

  • There seems to be a form of miscommunication here, so lets go through everything step by step.

    1 - this is my "brush" or stencil:

    2 - this is what happens when I put the brush inside a QPixmap, which I put inside a QBrush, which I put inside a QPen

    The line is simply filled with a tiled pattern of the stencil
    and the code for all of this:
    @ QPainter painter(this);
    QPixmap brush("c:/brush.png");
    QBrush myBrush(Qt::red, brush);
    QPen myPen;
    painter.drawLine(10, 10, 200, 50);@

    note that I use the same method as in the scribble example, BUT this method only works for either solid or dashed lines, not for the stencil

    3 - here is what dragging the stencil to draw should actually result it:

    drawLine can only draw strokes, not fills, strokes can only be solid or dashed but not pixmap, when a brush is set to a pen it tiles to fill the line, does not actually drag to draw it.

    From DOC:

    bq. The brush is used to fill strokes generated with the pen.

    I don't need to fill the stroke with the brush, I need to DRAW it with the brush.
    Is there a method to achieve the desired result?

  • Wouldn't it as simple as interpolating between the two points, and simply blitting the stencil at every point in between? Just guessing here...

  • That was what I suggested many posts back as an alternative, in case there is no QPainter method to do that. It's just that you guys kept on insisting there is ;)

  • Or you can use GIMP ;) .

    Please mark thread as solved if you found the solution.

  • ^^ And how exactly is your post helpful? From the many images I posted you should have concluded I already have a commercial image editor. And how exactly will GIMP help me to draw lines with stencils in my application? And thanks for your suggestion but I have plenty more questions on this topic, but those will have to wait till tomorrow. Geez... hunt rank much?

    Anyway, I was able to do it with interpolation, the following is an actual screenshot, but it is a primitive, quick and dirty way to interpolate, and it shows - the lines are quite jagged, nowhere nearly as smooth as those in the images above, which I made in photoshop, will have to do some optimization tomorrow.

  • Perhaps you can study how Krita works? From wat I read in the past, it is quite advanced in terms of brush handling.

  • Reinventing the wheel is usually a bad idea, but looking at the source code for Krita all I find is method calls within method calls within method calls, never really reaching the actual drawing logic. The project is so vast it will probably take me less time to reinvent the wheel in that particular case...

    Perhaps if someone here is familiar with the project can give me a few pointers on where to look...

    As for reinventing the wheel, I do realize I am stepping out of Qt land into generic algorithms so I will take it elsewhere.

  • BTW, here is my interpolation logic, it is fairly primitive, but I ain't no programmer yet, and I do realize Qt might have a better API for this, so any recommendations are welcome!

    @void Widget::drawLine()
    QPointF point, drawPoint;
    point = newPos - lastPos;
    int length = point.manhattanLength();
    double xInc, yInc;

    xInc = point.x() / length;
    yInc = point.y() / length;
    drawPoint = lastPos;
    for (int x=0; x < length; ++x) {


    Edit: One optimization that comes to mind looking at the code now is use the rx and ry methods of QPoint that return references to use the += on and save the extra function call...

Log in to reply