Paint text and make it follow a circular path.



  • Hi everyone,

    I am trying to paint some text that will be able to follow the hands of my analog clock.

    So as the seconds hand for example moves, the text will move with it and keep staying at its tip.

    I managed to draw some text and rotate it so as to move following a circle each second. The thing is though that I want only the position of the text to change not the orientation of the text itself.

    Until now I have something like this

    @ painter.save();

                        painter.rotate((360 * (time.second() / 60.0)));
                        posx = cos(((360 * (time.second() / 60.0)) * M_PI / 180) - ((90) * M_PI / 180)) * (-minSecondsViewPosY()) + 0;
                            posy = sin(((360 * (time.second() / 60.0)) * M_PI / 180) - ((90) * M_PI / 180)) * (-minSecondsViewPosY()) + 0;
                        
                        painter.setPen(Qt::black);
                        QFont font = painter.font() ;
                        font.setPointSize(9);
                        painter.setFont(font);
                        painter.drawText(0, 30,time.toString("ss"));
    
                        painter.restore();@
    

    How can I manage move the text in order to follow the clocks' second hand while keeping it oriented correctly?



  • Hi, I don't have an answer for you but I'd be interested to see how you solve this! Sounds like a fun little project!



  • I will of curse post the solution if I come up with one :)


  • Lifetime Qt Champion

    Hi,

    So you would like to keep the text horizontal but at the tip of the hand is that right ?



  • Well in a moment of boredom as I listened in on my 4th conference call today I started to play with Qt Analog Clock example and taking your idea I came up with the code below.

    I didn't try to de-rotate the text as I kind of like the effect. An analog/digital clock all in one. Just replace the entire paintEvent() in the Analog Clock example.

    @void AnalogClock::paintEvent(QPaintEvent *)
    {
    static const QPoint hourHand[3] = {
    QPoint(7, 8),
    QPoint(-7, 8),
    QPoint(0, -40)
    };
    static const QPoint minuteHand[3] = {
    QPoint(7, 8),
    QPoint(-7, 8),
    QPoint(0, -70)
    };

    QColor hourColor(127, 0, 127);
    QColor minuteColor(0, 127, 127, 191);
    
    QFont font;
    
    int side = qMin(width(), height());
    QTime time = QTime::currentTime();
    
    QPainter painter(this);
    
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width() / 2, height() / 2);
    painter.scale(side / 200.0, side / 200.0);
    
    painter.setPen(Qt::NoPen);
    painter.setBrush(hourColor);
    
    //
    // Hours
    //
    painter.save();
    
    painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
    painter.drawConvexPolygon(hourHand, 3);
    
    painter.setPen(Qt::black);
    font = painter.font();
    font.setPointSize(9);
    painter.setFont(font);
    painter.drawText(-7, -38, time.toString("hh"));
    
    painter.restore();
    
    painter.setPen(hourColor);
    for (int i = 0; i < 12; ++i) {
        painter.drawLine(88, 0, 96, 0);
        painter.rotate(30.0);
    }
    
    painter.setPen(Qt::NoPen);
    painter.setBrush(minuteColor);
    
    //
    // Minutes
    //
    painter.save();
    painter.rotate(6.0 * (time.minute() + time.second() / 60.0));
    painter.drawConvexPolygon(minuteHand, 3);
    
    painter.setPen(Qt::black);
    font = painter.font();
    font.setPointSize(9);
    painter.setFont(font);
    painter.drawText(-7, -68, time.toString("mm"));
    
    painter.restore();
    
    painter.setPen(minuteColor);
    for (int j = 0; j < 60; ++j) {
        if ((j % 5) != 0)
            painter.drawLine(92, 0, 96, 0);
        painter.rotate(6.0);
    }
    
    painter.save();
    
    painter.rotate((360 * (time.second() / 60.0)));
    
    painter.setPen(Qt::black);
    painter.drawLine( 0,0, 0, -75 );
    font = painter.font() ;
    font.setPointSize(9);
    painter.setFont(font);
    painter.drawText(-7, -78, time.toString("ss"));
    
    painter.restore();
    

    }@



  • Hi SGaist, yes that exactly was the idea. Basically what SysTech has done only that the text should remain horizontal so it can be easier to read. I tried doing it using simple math so I can just draw the text on the circumference of an imaginary circle but the result was not that smooth.

    What I thought was rotate the painted text counter-clockwise while the painter is translated at (width()/2, height()/2) so the text rotates on its' self, then use translate again at (0, 0) and then apply the normal rotation so it will also follow the seconds tip. Probably due to lack of experience I failed though.

    SysTech, yeah thats pretty much what I wanted to achieve, so thanks for the code. Yet I do believe that it would be easier for someone trying to read the values if the text was properly oriented.


  • Lifetime Qt Champion

    Then why not just reset the rotation and draw the text at the coordinates you want ?



  • No worries. I was not trying to provide the final answer. But when I did the code to just write out the text I really liked the way it looks. To me, rotating the text to be upright isn't required. I can instantly read the numbers no matter what the orientation. Obviously, a personal preference but SGaist had my other suggestion already posted.

    Just don't rotate the painter for the text output. This will cause the text to be oriented upright. Then all you need to figure out as SGaist says is the coordinates to draw at. I think you started in that direction with your first post using sin/cos.

    Basically you want to convert between polar and rectangular coordinates. So you could think of the current end position of each hand as your polar coordinate then you simply have to map it to an X/Y rectangular coordinate and draw away.

    I enjoyed this diversion as I listened to business managers drone on about going this way or that way with our product line and bicker about how difficult everything is.



  • The thing is though that if I do as you suggest the result is not that smooth as it is when setting the rotation for the painter , even though I used double precision for my coordinates. That is way I am hoping to find some trick with the rotation and transformation functions provided by Qt. Something that I do believe can be done, I'll post the solution here as soon as I find it.



  • I had some some time today and looked at this again, its embarrassing to say that I started doing this without actually realizing the Qt coordinate system.

    Anyway adjusting this to SysTechs' example it should be something like this for the seconds

           @    painter.rotate((360 * (time.second() / 60.0))-90);
    
               QFont font = painter.font() ;
    
                painter.setPen(Qt::black);
                font = painter.font() ;
                font.setPointSize(9);
                painter.setFont(font);
    
                painter.translate(70, 0); // this might be too high
                painter.rotate(-(360 * (time.second() / 60.0))+90);
    
                painter.drawText(-0, -0, time.toString("ss"));
    
               painter.restore(); @
    

Log in to reply
 

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