2

I have a QLabel centered in a custom QGraphicsPolygonItem and I'm using a QAction to change the labels text, but when the text changes the label size doesn't change, I want it to resize to the size of the new text and keep it centered. Here's my custom item constrctor:

DiagramItem::DiagramItem(DiagramType diagramType, QMenu *contextMenu,
         QGraphicsItem *parent)
: QGraphicsPolygonItem(parent){
QGraphicsProxyWidget* pMyProxy = new QGraphicsProxyWidget(this);
QLabel *label = new QLabel();
label->setText(QString("I AM A SQARE DADADA"));
label->setTextInteractionFlags(Qt::TextEditorInteraction);
label->setStyleSheet("QLabel { background-color : red; color : blue; }");
pMyProxy->setWidget(label);
pMyProxy->setPos(this->boundingRect().center()-label->rect().center());
...

Here's the slot I'm using to change the text of the label:

void MainWindow::setItemLabel(){
if(!scene->selectedItems().isEmpty())
{
    auto *item = scene->selectedItems().first();
    if(!(item->childItems().isEmpty()))
    {
        auto proxy = static_cast<QGraphicsProxyWidget *>(item->childItems().first());
        if(proxy)
        {
            auto label = qobject_cast<QLabel*>(proxy->widget());
            if(label)
            {
                QDialog *diag = new QDialog(this);
                QComboBox *box = new QComboBox();
                QLineEdit *lt = new QLineEdit();
                QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                                                    | QDialogButtonBox::Cancel);
                QVBoxLayout *mainLayout = new QVBoxLayout();
                connect(buttonBox, SIGNAL(accepted()), diag, SLOT(accept()));
                connect(buttonBox, SIGNAL(rejected()), diag, SLOT(reject()));
                mainLayout->addWidget(lt);
                mainLayout->addWidget(buttonBox);

                diag->setLayout(mainLayout);
                if(diag->exec() == QDialog::Accepted){
                    QString *usrInpt = new QString();
                    *usrInpt = lt->text();
                    label->rect().setWidth(usrInpt->length());
                    label->setText(*usrInpt);
                }
            }
        }
    }
}

Here's what I'm getting as a result, this is before triggering the slot above: BeforeSlotTriggere And here's what I'm getting after the slot is triggered: AfterSlotTriggered

This line isn't doing anything too, and I have no idea why:

label->rect().setWidth(usrInpt->length());

What am I missing?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Matheus Ianzer
  • 425
  • 8
  • 22

1 Answers1

5

You can adjust the size of the QLabel with adjustSize(), but even so the QGraphicsProxyWidget will not change its size causing the problem to persist, to correct we must overwrite boundingRect() and return the appropriate size, in addition to this the way you set the text does not is appropriate, if you are creating a class that has the label inside you could create a setText() method that updates the QLabel without the need to write a lot of code:

class GraphicsProxyWidget: public QGraphicsProxyWidget{
public:
    using QGraphicsProxyWidget::QGraphicsProxyWidget;
    QRectF boundingRect() const{
        if(widget())
            return QRectF(widget()->rect());
        return QGraphicsProxyWidget::boundingRect();
    }
};

class DiagramItem: public QGraphicsPolygonItem{
    QLabel *label;
    GraphicsProxyWidget *pMyProxy ;
public:
    explicit DiagramItem(DiagramType diagramType, QMenu *contextMenu, QGraphicsItem *parent=nullptr):QGraphicsPolygonItem(parent) {
        label = new QLabel;
        pMyProxy = new GraphicsProxyWidget(this);
        pMyProxy->setWidget(label);
        label->setTextInteractionFlags(Qt::TextEditorInteraction);
        label->setStyleSheet("QLabel { background-color : red; color : blue; }");
        setText("I AM A SQARE DADADA");
        ...
    }
    void setText(const QString & text){
       label->setText(text);
       label->adjustSize();
       pMyProxy->setPos(boundingRect().center()-label->rect().center());
    }
};

and then the setItemLabel method would look like this:

void MainWindow::setItemLabel(){
    if(!scene->selectedItems().isEmpty())
    {
        auto *item = scene->selectedItems().first();
        DiagramItem *it = static_cast<DiagramItem *>(item);
        if(it){
            QDialog *diag = new QDialog(this);
            QComboBox *box = new QComboBox();
            QLineEdit *lt = new QLineEdit();
            QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
                                                               | QDialogButtonBox::Cancel);
            QVBoxLayout *mainLayout = new QVBoxLayout();
            connect(buttonBox, SIGNAL(accepted()), diag, SLOT(accept()));
            connect(buttonBox, SIGNAL(rejected()), diag, SLOT(reject()));
            mainLayout->addWidget(lt);
            mainLayout->addWidget(buttonBox);

            diag->setLayout(mainLayout);
            if(diag->exec() == QDialog::Accepted){
                it->setText(lt->text())
            }
        }
    }
}

Example:

#include <QApplication>
#include <QGraphicsProxyWidget>
#include <QGraphicsView>
#include <QLabel>
#include <QTimer>

class GraphicsProxyWidget: public QGraphicsProxyWidget{
public:
    using QGraphicsProxyWidget::QGraphicsProxyWidget;
    QRectF boundingRect() const{
        if(widget())
            return QRectF(widget()->rect());
        return QGraphicsProxyWidget::boundingRect();
    }
};

class DiagramItem: public QGraphicsPolygonItem{
    QLabel *label;
    GraphicsProxyWidget *pMyProxy ;
public:
    explicit DiagramItem(QGraphicsItem *parent=nullptr):QGraphicsPolygonItem(parent) {
        label = new QLabel;
        pMyProxy = new GraphicsProxyWidget(this);
        pMyProxy->setWidget(label);
        label->setTextInteractionFlags(Qt::TextEditorInteraction);
        label->setStyleSheet("QLabel { background-color : red; color : blue; }");
        setText(QString("I AM A SQARE DADADA"));
        setBrush(Qt::green);
    }
    void setText(const QString & text){
       label->setText(text);
       label->adjustSize();
       pMyProxy->setPos(boundingRect().center()-label->rect().center());
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QGraphicsView w;
    QGraphicsScene *scene = new QGraphicsScene;
    w.setScene(scene);
    auto it = new DiagramItem;
    QPolygonF myPolygon({QPointF(-120, -80), QPointF(-70, 80),
                         QPointF(120, 80), QPointF(70, -80),
                         QPointF(-120, -80)});
    it->setPolygon(myPolygon);
    scene->addItem(it);
    QTimer::singleShot(1000, [it](){
        it->setText("some text");
    });
    w.show();
    return a.exec();
}

enter image description here

enter image description here

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks for the reply! Now the new text is centered, but the red background is still larger than the text, I thought `adjustSize()` would take care of it, why is that? – Matheus Ianzer Apr 19 '18 at 01:15
  • Yes, I did copy your code, all I did was separate function headers to .h and implementation to .cpp. I think maybe I'm not overriding `boundingRect()` correctly since I don't really know for sure where to put it, sorry for the newbie c++ struggle, but where should I place overridden functions from Qt headers? – Matheus Ianzer Apr 19 '18 at 02:26
  • 1
    @MatheusIanzer Never mess with working code until you confirm that it works. "All I did" is irrelevant - everyone says that. It's the software engineering equivalent of "hold my beer, watch this". Get it working as-is first, then commit to git, then change a small thing, verify that it still works, commit, and keep going like that, in small chunks. And yes, use git, even on little examples. Make it a habit. Then you'll embrace change instead of dreading it. – Kuba hasn't forgotten Monica Apr 20 '18 at 04:06