paintEvent is not painting complete objects



  • I am trying this piece of code below:

    widget.h

    #ifndef WIDGET_H
    #define WIDGET_H

    #include <QWidget>
    #include <QLabel>
    #include <QPainter>

    namespace Ui {
    class Widget;
    }

    class Widget : public QWidget
    {
    Q_OBJECT

    public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    void paintEvent(QPaintEvent *e);
    void operation();
    void drawLabel();
    
    int flag = 0;
    int startX, startY;
    QString labelText;
    

    private:
    Ui::Widget *ui;
    };

    #endif // WIDGET_H

    widget.cpp

    #include "widget.h"
    #include "ui_widget.h"

    Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
    {
    ui->setupUi(this);
    }

    Widget::~Widget()
    {
    delete ui;
    }

    void Widget::paintEvent(QPaintEvent *e)
    {
    QPainter *painter = new QPainter(this);
    if(flag == 1)
    {
    painter->setPen(QPen(Qt::black, 1));
    painter->drawLine(startX, startY, startX+30, startY);
    painter->drawLine(startX+50, startY, startX+80, startY);
    drawLabel();
    }
    }

    void Widget::drawLabel()
    {
    QLabel *label = new QLabel(this);
    label->setStyleSheet("border: 1px solid black");
    label->setGeometry(startX+30, startY-10, 20, 20);
    label->setText(labelText);
    label->show();
    }

    void Widget::operation()
    {
    int found = 1;

    if(found)
    {
        labelText = "2";
        startX = 20;
        startY = 50;
        flag = 1;
        update();
    
        labelText = "3";
        startX = 100;
        startY = 50;
        flag = 1;
        update();
    }
    

    }

    main.cpp

    #include "widget.h"
    #include <QApplication>

    int main(int argc, char *argv[])
    {
    QApplication a(argc, argv);
    Widget w;
    w.operation();
    w.show();

    return a.exec();
    

    }

    I want to draw a label between two lines side by side, but when I run the above code label with labelText 3, between two lines is visible. labelText 2, between two lines is not painted. I don,t understand why? Can anybody help me to solve this?


  • Moderators

    @NIXIN
    you are doing multiple mistakes in your code.

    1. you are creating widgets on every paintEvent call! This is very bad design.
    2. in your Widget::operation() you update your data and call update() to immediately set the data again and call update() again. You should know that update() schedules a paint-event, where multiple calls to update() still result in a single paint-event (in the next event loop iteration). So it doesn't repaint immediately. There is a repaint() method for this, but as i said you already have a bad design by creating widgets on every paintEvent call.

    You should draw the text using QPainter instead creating a QLabel every time. But still the label text "2" would never be rendered, since you immediately overwrite it afterwards.



  • can you provide a small piece of code, how to do it?


  • Moderators

    @NIXIN

    void Widget::paintEvent(QPaintEvent *e)
    {
        QPainter painter(this);  // do create the painter on the stack
        ....
        drawLabel( p );
    }
    
    void Widget::drawLabel(QPainter & p)
    {
    QRect rect(startX+30, startY-10, 20, 20);
    p.setPen( QPen::QPen(Qt::black, 1.0, Qt::SolidLine) );
    p.setBrush( Qtt::NoBrush );
    p.drawRect( rect );
    p.drawText( rect, Qt::AlignCenter, labelText );
    }
    

    But as i said, this only draws the last label text set. You should store your data (position, label text,...) in a list (and call update() once). And draw each using drawLabel() for example.



  • That's fine, what I want to know is how to not delete the drawing from previous paintevent,
    because as per your statement:
    " But still the label text "2" would never be rendered, since you immediately overwrite it afterwards."
    I want to keep the drawing for both:

    if(found)
    {
    labelText = "2";
    startX = 20;
    startY = 50;
    flag = 1;
    update();

    labelText = "3";
    startX = 100;
    startY = 50;
    flag = 1;
    update();
    

    }


  • Moderators

    @NIXIN
    as i said store your data (e.g. struct) in a list and draw each item separately while iterating over the list in the paintEvent()



  • Can you please provide a small code


  • Moderators

    @NIXIN
    come on thats not that hard...

    struct Data {
        Data(QString t, int x, int y, int f)
             : labelText(t), startX(x), startY(y), flag(f)
        {
        }
    
        QString labelText;;
        int startX;;
        int startY;
        int flag;
    }
    QList<Data> dataList;
    ...
    void Widget::operation()
    {
    int found = 1;
    
    if(found)
    {
        dataList.clear();
    
        dataList << Data("2", 20, 50, 1);
        dataList << Data("3", 100, 50, 1);
        update();
    }
    
    }
    
    void Widget::paintEvent(QPaintEvent *e)
    {
        QPainter painter(this);  // do create the painter on the stack
        ....
        foreach( Data d, dataList )
             drawLabel( p, data );
    }
    
    void Widget::drawLabel(QPainter & p, const Data & d)
    {
    QRect rect(d.startX+30, d.startY-10, 20, 20);
    p.setPen( QPen::QPen(Qt::black, 1.0, Qt::SolidLine) );
    p.setBrush( Qt::NoBrush );
    p.drawRect( rect );
    p.drawText( rect, Qt::AlignCenter, d.labelText );
    }
    




  • How about composing the widget instead of painting it.
    Put two QFrame with a HLine style and a label in a QVBoxLayout. So much easier!



  • @VRonin Depends on what he wants to achieve.
    Is it a widget, than I agree with you.
    Is it some CAD-drawing (looks like a diagram symbol to me), then I would prefer drawing.
    For the latter the Graphics View Framework would be more practical though.


Log in to reply
 

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