Позиционирование QGraphicsSimpleTextItem в QGraphicsScene с нестандартным sceneRect - PullRequest
0 голосов
/ 09 апреля 2019

Я хочу создать простую графическую сцену (в подклассе QGraphicsScene):

Вот что я пытаюсь сделать:

enter image description here

Размеры синего прямоугольника являются динамическими, и стрелка и метка также могут быть нарисованы в разных местах. SceneRect () определяет систему координат относительно одной переменной (по сути, высоты синего прямоугольника).

Я могу нарисовать прямоугольник и линии в ожидаемых местах, но когда я добавляю QGraphicsSimpleTextItem для метки, я не могу правильно расположить его.

Я создаю simpleTextItem, добавляю его в сцену, затем измеряю его ширину и высоту (используя boundingRect ()), который дает мне ш / ч в пикселях. Затем я пытаюсь преобразовать эту ширину и высоту в координаты сцены, используя mapRectToScene (), но не получаю то, что ожидаю. Я получаю те же значения, что и в пикселях.

Я посмотрел в отладчике результаты всех методов item-> mapRectTo / From, и, похоже, ничто не дает мне того, чего я ожидаю. Каждый метод возвращает нетрансформированный boundingRect из текстового элемента.

Что я должен сделать, чтобы получить правильные смещения (в координатах сцены) для label-> setPos (), чтобы получить метку там, где я хочу (слева от стрелки, выровненной по горизонтали с серединой стрелки)? ??

void MyGraphicsScene::updateScene()
{
// Setup is that "thickness_" is a variable and the scene coordinate system
// is set up around this value. In my testing I have thickness_ = 1.0, so the
// coordinate system is -1.5 to 1.5 in X and Y.
//
// Scene rect centered at 0,0
// setSceneRect(-1.5*thickness_, -1.5*thickness_, 3.0*thickness_, 3.0*thickness_);


    clear();
    QColor bkgColor("#888888");
    setBackgroundBrush(QBrush(bkgColor));

    double centX = 0.0;
    double centY = 0.0;
    double boxLeft  = centX - thickness_/2.0;
    double boxRight = centX + thickness_/2.0;
    double boxTop   = centY - thickness_/2.0;
    double boxBot   = centY + thickness_/2.0;

    // The sample volume cross-section as a light blue box
    QColor boxColor("lightblue");
    QColor lineColor("black");

    QBrush boxBrush(boxColor);
    QPen   boxPen(lineColor);
    boxPen.setWidth(1);
    boxPen.setCosmetic(true);
    QGraphicsRectItem *rect = addRect(boxLeft, boxTop, thickness_, thickness_, boxPen, boxBrush);

    // Mid-section line
    QPen linePen(lineColor);
    linePen.setWidth(3);
    linePen.setCosmetic(true);
    QGraphicsLineItem *line = addLine(boxLeft, centY, boxRight, centY, linePen);

    // Draw a position arrow
    double y = centY;
    QColor arrowColor("red");
    QPen arrowPen(arrowColor);
    arrowPen.setWidth(3);
    arrowPen.setCosmetic(true);

    double arrowLength = 0.2*thickness_;

    QGraphicsLineItem *arrowLine = addLine(centX - thickness_/2.0 - arrowLength, y,
                                           centX - thickness_/2.0, y, arrowPen);

    // Arrowhead
    line = addLine(boxLeft - arrowLength*.1, y - (0.3*zStep_), boxLeft, y, arrowPen);
    line = addLine(boxLeft - arrowLength*.1, y + (0.3*zStep_), boxLeft, y, arrowPen);

// All works as expected until I try to create and place the label...

    // Arrow Label
    QGraphicsSimpleTextItem *label = new QGraphicsSimpleTextItem("Focus");
    label->setBrush(QColor("black"));
    label->font().setBold(true);
    label->setFlag(QGraphicsItem::ItemIgnoresTransformations);
    addItem(label);

    // Measure the size of the SimpleTextItem (gives me a rect in pixels the size of the text string: 43w 18h)
    QRectF itemBR  = label->boundingRect();

    // I expect this to be in "scene" coordinates so width and height are pixels transformed to scene space
    QRectF itemSceneBR = label->mapRectToScene(itemBR); // But it is the same as itemBR...

    // Set the position of the label to the left of the arrow, offset Y to align with middle of line
    double offsetX = itemSceneBR.width();        // = 43.0... no transform done
    double offsetY = itemSceneBR.height()*0.5;   // =  9.0... no transform done

    // Empirically, I expect about this in scene coordinates:
    offsetX = 0.6;
    offsetY = 0.12;

    label->setPos(boxLeft - arrowLength - offsetX, y - offsetY);

    QGraphicsView *theView = (QGraphicsView *)views().at(0);
    theView->fitInView(sceneRect(), Qt::KeepAspectRatio);
}

Новая информация: Я решил это путем преобразования ширины и высоты моего textItem boundingRect (itemBR в приведенном выше коде) в координаты сцены следующим методом:

double GrTestMain::scaleFromPixels(QGraphicsView *theView, int 
pixelDimension, bool isHorizontal)
{
    double length = 0.0;

    if(isHorizontal)
    {
        length = pixelDimension / qAbs(theView->viewportTransform().m11());
    }
    else
    {
    length = pixelDimension / qAbs(theView->viewportTransform().m22());
    }

    return length;
}

Мне не очень нравится это решение, но оно работает. Кажется, что это должно быть проще, но любой метод, который я пытался преобразовать QGraphicsSimpleTextItem в координаты сцены (item-> mapRectTo ... () и т. Д.), Не дал мне того, что я ожидал.

...