c++qtqgraphicsitemqpainterqrect

Getting QRectF with text by click on QGraphicsItem


If I have some painter, some rectangle and some string:

QPainter* pPainter;
//Initializing it

QRectF RectF;
//Initializing it

std::string strText = "Some string";

And I draw the rectangle with text using painter on some QGraphicsItem object and then we draw it on the scene:

pPainter->drawText(RectF, Qt::AlignCenter, strText);

Note: I cannot modify the code above, only to add something.

My goal is to get that text after a click on the rectangle. Suppose, that I've found mouseclick coordinates correctly.

Is there any way to get rectangle and its text using the coordinates of click? Or maybe I should hold some list of such rectangles to process them next? I've thought about use of itemAt() method, but I couldn't get rectangle that way.

std::string GetTextByCoordinates(int x, int y)
{
  //What to do here?
}

Update: Method paint is used in class that inherited from QGraphicsItem (CustomItem), and there is several text rectangles on such items.

Method "GetTextByCoordinates" supposed to be called from that CustomItem object.


Solution

  • Since you draw something on a widget, you can operate only with pixels that are drawn. You have no information about this pixels origin. So you need some additional information.

    The normal way to manipulate logical objects drawn on scene is to place QGraphicsItems on the scene. There are QGraphicsRectItem QGraphicsSimpleTextItem for your case. It looks like this:

    class CustomItem : public QGraphicsItem
    {
    public:
        <...>   // Methods like boundingRect and others also must be reimplemented.
    
        void addText(const QString &text, const QRectF &containerRect)
        {
            // As this items are "this" children, you even don't need to
            // reimplement paintEvent.
            QGraphicsRectItem *rectItem =
                new QGraphicsRectItem(containerRect, this);
            QGraphicsSimpleTextItem *textItem =
                new QGraphicsSimpleTextItem(text, rectItem);
        }
    
        QString getTextByCoordinates(int x, int y)
        {
            for (const auto *child: childItems()) {
                const QGraphicsRectItem *rect =
                    qgraphicsobject_cast<const QGraphicsRectItem *>(child);
                if (rect == nullptr)
                    continue;
    
                const QGraphicsItem *text = rect->childItems().first();
                return qgraphicsitem_cast<const QGraphicsSimpleTextItem *>(text)->text();
            }
    
            return "";
        }
    };
    

    If you really cannot modify the code with painter, you must remember all rectangles and texts on them:

    class CustomItem : public QGraphicsItem
    {
    private:
        struct RectText
        {
            QRectF      rect;
            std::string text;
        };
    
        QList<RectText> _rectTexts;
    
    public:
        <...>
    
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                   QWidget *widget = nullptr);
        {
            <...>
    
            _rectTexts << {RectF, strText};
        }
    
        std::string GetTextByCoordinates(int x, int y)
        {
            for (const auto &rt:    _rectTexts) {
                if (rt.rect.contains(x, y))
                    return rt.text;
            }
    
            return "";
        }
    };
    

    See no another ways. Text recognize by bitmap is not considered : )