Dots while freehand drawing on QGraphicsView and Problem while remove items from QGraphicsView.



  • Hi,

    I want to draw freehand drawing on QGraphicsView. I am able to draw it. But, when the line draw on QGraphicsView, it also create small small dots. How can i remove these dots ? I am sharing code of mouse press, mouse move and mouse release on QGraphicsView and line draw function where i am adding the line on QGraphicsScene which is associated with QGraphicsView.
    The following code also contains code for Eraser. Eraser is also works but it also remove items which are out of Eraser's area.

    @void WhiteBoardView::mousePressEvent (QMouseEvent *event)
    {
    if(event->button() == Qt::LeftButton)
    {
    vbMousePressed = true;

        if(vbPenSelected)
        {
            /* This code will execute when Pen is selected */
    
            currntPt = previousPt = mapToScene(event->pos());      
            drawLineTo(previousPt,currntPt,vPenForDrawing);
        }
        else if(vbEraserSelected)
        {
            /* This code will execute when Eraser is selected */
    
            rad = vRadiusForEarser;
            pt = mapToScene(event->pos());
    
            EraserLineTo(pt, rad);
        }
    
    
    }
    

    }

    void WhiteBoardView::mouseMoveEvent (QMouseEvent *event)
    {
    vbMouseMoving = true;

    if(vbMousePressed && vbMouseMoving)
    {
        if(vbPenSelected)
        {
            /* This code will execute when Pen is selected */
    
            previousPt = currntPt;
            currntPt = mapToScene(event->pos());
            drawLineTo(previousPt,currntPt,vPenForDrawing);
        }
        else if(vbEraserSelected)
        {
            /* This code will execute when Eraser is selected */
    
            rad = vRadiusForEarser;
            pt = mapToScene(event->pos());
    
            EraserLineTo(pt, rad);
    
        }
    
    }
    

    }

    void WhiteBoardView::mouseReleaseEvent (QMouseEvent *event)
    {
    Q_UNUSED(event);

    if(vbMouseMoving)
    {
        if(vbPenSelected)
        {
    
        }
    
        else if(vbEraserSelected)
        {
            /* Following code is used to remove items from QGraphicsScene  */
    
            mWhiteBoardScene->addEllipse(pt.x()-rad, pt.y()-rad, rad*2.0, rad*2.0,QPen(Qt::blue), QBrush(Qt::transparent));
            listOfItems = mWhiteBoardScene->items(pt.x()-rad, pt.y()-rad, rad*2.0, rad*2.0, Qt::IntersectsItemShape);
    
            for(int i=0; i < listOfItems.size(); i++)
            {
                mWhiteBoardScene->removeItem(listOfItems[i], true);
                delete listOfItems[i];
            }
    
    
            listOfItems.clear();
        }
    
        vbMouseMoving = false;
        vbMousePressed = false;
    }
    

    }

    /* Following function is used to draw line on QGraphicsScene */

    void WhiteBoardView::drawLineTo(const QPointF &previous, const QPointF &current, const QPen& drawPen)
    {
    mWhiteBoardScene->addLine(previous.x(), previous.y(), current.x(), current.y(), drawPen);
    }

    /* Following function is used to Remove Items from QGraphicsScene */

    void WhiteBoardView::EraserLineTo(const QPointF &current, double radius)
    {

    listOfItems = mWhiteBoardScene->items(current.x()-radius, current.y()-radius, radius*2.0, radius*2.0, Qt::IntersectsItemShape);
    
    for(int i=0; i < listOfItems.size(); i++)
    {
        mWhiteBoardScene->removeItem(listOfItems[i], true);
        delete listOfItems[i];
    }
    
    mWhiteBoardScene->addEllipse(current.x()-radius, current.y()-radius, radius*2.0, radius*2.0,QPen(Qt::blue), QBrush(Qt::transparent));
    

    }@

    Thanks in advance ...


  • Moderators

    i think your dots appear because of pixelation.
    Try to set render hint:
    @
    view->setRenderHint( QPainter::Antialiasing );
    @



  • I already set this render hint.


  • Moderators

    ok to the drawLineTo() method add the following debug message and check if alwys correct lines are drawn:
    @
    qDebug() << Q_FUNC_INFO << previous << current;
    @


  • Moderators

    i just compiled and ran the code you posted and i don't get the dots you mentioned. Could you please upload a screenshot showing the issue?



  • Hi Raven,

    You can find screenshot from the below link.

    !http://http://www.freeimagehosting.net/govdu()!

    This is screenshot of my drawing. You can see small small dots.



  • http://www.freeimagehosting.net/govdu

    From the above mentioned link , you can see screenshot.

    Thanks in advance.


  • Moderators

    ok now i know what you mean.... this issue comes from a non-opaque pen/brush color. So that the endings of the lines overlap...

    You have 2 possibilities now:

    1. sub class a QGraphicsItem and do the painting yourself. On every move event you add the current position to the item and in the item's paint event you draw it's points with QPainter::drawPolyline()

    2. instead of adding multiple lines to the scene you add 1 "shape item":http://qt-project.org/doc/qt-4.8/qgraphicspathitem.html to the scene. in every move event you add a line to painter path object "merge it down":http://qt-project.org/doc/qt-4.8/qpainterpath.html#simplified and set i to the shape item.

    I would suggest the 2nd method since it will be easier to implement your eraser with just "removing the eraser shape":http://qt-project.org/doc/qt-4.8/qpainterpath.html#subtracted from the current path in every move event.


  • Moderators

    so a possible solution to 2) could be as simple as:
    @
    WhiteBoardView::WhiteBoardView()
    {
    mDrawnPathItem = mWhiteBoardScene->addPath(QPainterPath());
    mDrawnPathItem->setBrush( QColor(...) );
    mDrawnPathItem->setPen(Qt::NoPen);
    }

    void WhiteBoardView::drawLineTo(const QPointF &previous, const QPointF &current, const QPen& drawPen)
    {
    QGraphicsLineItem lineHelper;
    lineHelper.setLine( QLineF(previous, current) );
    lineHelper.setPen(drawPen);

    QPainterPath path = mDrawnPathItem->path();
        path.setFillRule(Qt::WindingFill);
        path.addPath( lineHelper.shape() );
    path = path.simplified();
    
    mDrawnPathItem->setPath(path);    //mDrawnPathItem is of type QGraphicsPathItem* and was added in the constructor with an empty QPainterPath()
    

    }
    @



  • Thanks a lot Raven.

    It works very fine. But, I have one more problem with this. If i draw a line with a color (for example: Black) , it draws very fine. But, when i start drawing again with different color(for example: Red) , it also changes the color of drawn lines( Black to Red)...

    Once again, thanks a lot....


  • Moderators

    yes sure... solution to your problem was to not create multiple line-items but one single item so get rid of the overlapping edges (dots in your case). Thus a change of color affects the whole item.
    If you need to draw multi color lines, then you need to create for every color a own path.



  • Thanks Raven.. Now, i am using different different path for every color. It works very fine.

    But, i could not understand what you want to say about Eraser concept, sorry.. :(


  • Moderators

    when in "eraser-mode" (in the mouse move event) you create a QPainterPath with the radius and the center of the current mouse position. Now just "subtract":http://qt-project.org/doc/qt-4.8/qpainterpath.html#subtracted the eraser painterpath from every item you have in your graphicsview.
    Thats it.



  • I try this but not working.... :(

    the following is my code.

    @WhiteBoardView::WhiteBoardView()
    {
    /* This is for Red Color */
    mRedPathItem = mWhiteBoardScene->addPath(QPainterPath());
    mRedPathItem->setPen(Qt::NoPen);

     /*  This is for Green Color */
     mGreenPathItem = mWhiteBoardScene->addPath(QPainterPath());
     mGreenPathItem->setPen(Qt::NoPen);
     
     /*  This is for Blue Color */
     mBluePathItem = mWhiteBoardScene->addPath(QPainterPath());
     mBluePathItem->setPen(Qt::NoPen);
    
     /*  This is for Eraser */
     mEraserPathItem = mWhiteBoardScene->addPath(QPainterPath());
     mEraserPathItem->setPen(Qt::NoPen);
    

    }

    /* When in "Eraser Mode(In mouseMoveEvent)", i am calling the following function. */

    void WhiteBoardView::eraseLineTo(const QPointF &current)
    {
    QPainterPath eraserPath = mEraserPathItem->path();

    eraserPath.addEllipse(current, 20,20);
    
    QList<QGraphicsItem*> items = this->items();
    
    for(int i=0; i<items.size(); i++)
    {
        QPainterPath drawnPath = items[i]->shape();
    
        drawnPath.subtracted(eraserPath);
    }
    

    }@


  • Moderators

    you need to save the changes back to the item, since you only get a copy of the shape from the item. And also you don't need to add an eraser-item to the scene and add a circle to it on every call ;)
    @
    void WhiteBoardView::eraseLineTo(const QPointF &current)
    {
    QPainterPath eraserPath;
    eraserPath.addEllipse(current, 20,20);

    QList<QGraphicsItem*> items = this->items();
    
    for(int i=0; i<items.size(); i++)
    {
        QPainterPath drawnPath = items[i]->shape();
        drawnPath.subtracted(eraserPath);
        items[i]->setShape(drawnPath);
    }
    

    }
    @



  • items[i] which is a QGraphicsItem does not have any "setShape" property. I also create a new instance of QGraphicsPathItem and using that i again set the path. But, it also does not work.

    @void WhiteBoardView::EraserLineTo(const QPointF &current, double radius)
    {
    QPainterPath eraserPath = mEraserPathItem->path();
    eraserPath.addEllipse(current, 20,20);

    QList<QGraphicsItem*> items = this->items();
    
    for(int i=0; i<items.size(); i++)
    {
        QPainterPath drawnPath = items[i]->shape();
    
        QGraphicsPathItem *pathItem = new QGraphicsPathItem();
    
        pathItem->setPath(drawnPath.subtracted(eraserPath));
    }
    

    }@


  • Moderators

    sorry...the path property is the right one.

    In your code you create a new QGraphicsPathItem but never add it to the scene. And even if you would add it to the scene you would leave the old items in there.
    Why not holding your own list of the added QGraphicsPathItem objects?
    @
    void WhiteBoardView::EraserLineTo(const QPointF &current, double radius)
    {
    QPainterPath eraserPath = mEraserPathItem->path();
    eraserPath.addEllipse(current, 20,20);

        //m_DrawnItems = QList<QGraphicsPathItem*>
        foreach( QGraphicsPathItem* item, m_DrawnItems)
        {
            QPainterPath drawnPath = item->path();
                  drawnPath.subtracted(eraserPath)
            item->setPath(drawnPath);
        }
    }
    

    @
    so every time you add a linepath to the scene you need to also add it to the m_DrawnItems list



  • thanks sir....
    Now, everything is going fine... :)

    thanks a lot....



  • Hi Raven,

    As u told me about how to do drawing on QGraphicsView and how to remove drawn paths. Now, i am facing a new problem while removing drawn paths.

    If i draw large no. of polygons , then the number of paths will increase and the size of list which maintain all paths(m_DrawnItems) is large. In the following code, which is to remove paths from view, For loop is taking a lot of time in case of large number of path.

    @ void WhiteBoardView::EraserLineTo(const QPointF &current, double radius)
    {
    QPainterPath eraserPath = mEraserPathItem->path();
    eraserPath.addEllipse(current, 20,20);

        //m_DrawnItems = QList<QGraphicsPathItem*>
        foreach( QGraphicsPathItem* item, m_DrawnItems)
        {
            QPainterPath drawnPath = item->path();
                  drawnPath.subtracted(eraserPath)
            item->setPath(drawnPath);
        }
    }@
    

    Is there any way which removes the drawn paths fastly ???



  • Another problem is that i can't draw free hand drawing on images which are drawn on QGraphicsView .....


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.