Qt, QTransform rotation

2019-05-09 17:51发布

问题:

I'm trying to draw text "on cylinder". It means, that I have five rows of text. Top row is rotated by the X axis for 10 degrees. The second for 5 degrees. The middle is not rotated at all. The four's row is rotated for -5 degrees. The five's is rotated for -10 degrees. Rows 1, 2, 3 draws OK, but something is wrong with 4,5 rows. What am I doing wrong ? I provides an image for understanding a problem and code snippet:

for( int i = 0; i < iterationsCount; ++i )
{
    const QRect r( x2, y2, textWidth, itemHeight );

    const QString text = sections.at( section ).values.at( index );

    int rsc = 0;


    p->save();

    rsc = widgetHeight / 2 - y;

    p->setTransform(QTransform().rotate(rsc, Qt::XAxis));


    if( type == Section::DaySectionShort ||
        type == Section::DaySectionLong )
    {


        QStringList values = text.split( QLatin1Char( ' ' ) );

        p->setPen(
            lighterColor( opt.palette.color( QPalette::WindowText ), 75 ) );
        p->drawText( r, Qt::AlignLeft | Qt::TextSingleLine, values.at( 0 ) );

        p->setPen( opt.palette.color( QPalette::WindowText ) );
        p->drawText( r, Qt::AlignLeft | Qt::TextSingleLine, values.at( 1 ) );
    }
    else
    {
       p->drawText( r, Qt::AlignLeft | Qt::TextSingleLine, text );
    }

    p->setTransform(QTransform().rotate(-rsc, Qt::XAxis));

    index = nextIndex( index, sections.at( section ).values.size() );
    y += itemHeight + itemTopMargin;

    p->restore();
}

My problem

回答1:

As you have not provided a minimal complete code that reproduces the problem, I cannot guess what is wrong there. But the most probable reason is incorrect rsc calculation. At least the following draft works:

#include <QtCore>
#include <QtGui>
#include <QtWidgets>

class MyWidget: public QWidget
{
public:
    MyWidget(QWidget *parent = nullptr)
        : QWidget(parent)
    {
        QFont f = font();
        f.setPointSize(15);
        setFont(f);
    }

protected:
    void paintEvent(QPaintEvent *event) override
    {
        QWidget::paintEvent(event);
        QPainter p(this);

        const int itemHeight = fontMetrics().height();
        const int itemTopMargin = 15;
        const int xOffset = 15;
        int y = itemHeight;

        for (size_t i = 0; i < 5; ++i) {
            // The angle is in range [-40, 40]. Remove " * 4" for [-10, 10].
            const int rsc = (10 - 5 * i) * 4;
            qDebug() << i << ":\t" << rsc << "\t" << y;

            /*
                Rotation must be performed relative to central point of the
                drawn item. Transformations below are applied in reverse order.
                At first translate item to make it's center in (0, 0). At
                second rotate it relative to X axis. At third move the item to
                desired position.
            */
            QTransform transform;
            transform.translate(xOffset, y + itemHeight / 2);
            transform.rotate(rsc, Qt::XAxis);
            transform.translate(0, - itemHeight / 2);
            p.setTransform(transform);

            p.drawText(QPoint(), QString("(Item no. %1)").arg(i + 1));

            y += itemHeight + itemTopMargin;
        }
    }
};

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    MyWidget widget;
    widget.setMaximumSize(200, 250);
    widget.show();

    return app.exec();
}

The transformation used here is complicated because of need to rotate each item relative to it's central y, not y = 0. This also may be the case.

Font and angles are increased to see considered effects better.