Embedded Qt making a stopwatch

Previous articles: Embedded Qt - write and run your first ARM Qt program by hand

This paper introduces how to write the first embedded Qt program, and realizes the demonstration of an electronic clock.

In this chapter, we will continue to practice Qt, imitate the stopwatch in the mobile phone, and realize a stopwatch with the same function:

Reviewing the last Qt development process, the whole Qt development is achieved by tapping code. In fact, you can also use the UI function of Qt Creator to develop graphical interfaces through graphical configurations. This article uses this method to develop.

1. New Qt project

For the specific steps of creating a Qt project, refer to the previous article: Embedded Qt - write and run your first ARM Qt program by hand , only the differences are explained here.

The first chapter implements page design through code. This chapter uses the UI interface design function of Qt Creator, so check the following creation pages:

The default project structure of Qt after creation is as follows:

Double click the widget.ui to open the UI settings page, as shown in the following figure:

Here is a brief introduction to the following functional areas:

2 Code writing

2.1 ui design

Modify the size of the interface. The resolution of my Linux board sub screen is 800x480, so adjust it to the corresponding size:

Drag a Label from the left side, and then you can modify the font size:

Then drag other required components (PushButton, TextBrowser) and position adjustment components (spring shaped HorizontalSpacer, VericalSpacer) from the left side

For horizontal layout and vertical layout, select the corresponding components, such as 3 buttons and 2 springs in the middle, and click the horizontal layout button in the upper toolbar:

The horizontal layout of the three buttons is as follows:

Then lay out other components in turn:

The font can be adjusted to center display:

Select the largest combined component with the mouse, and drag the edge to adjust it to the appropriate external size. Then select different levels of composite components, adjust the parameters of layoutStretch, and display each component proportionally (equivalent to adjusting the elastic force of each spring component)

Click the triangle icon above the lower left corner to run and check the effect:

Note that the left margin is for the stopwatch dial.

2.2 Introduction to QTimer and QTime

The QTimer class provides a high-level programming interface for timers, providing repeat and single timing.

The QTime class provides the clock time function. The QTime object contains a clock time, which can be expressed in hours, minutes, seconds, and milliseconds since midnight.

Qt Creator provides convenient help documents. You can directly view the use of corresponding function functions in Qt Creator. For example, you can search for QTimer to see the corresponding introduction and available API functions:

The functions of QTimer used in this article are:

  • Start: start the timer
  • stop: stop the timer

Take a look at the introduction of QTime:

The functions of QTime used in this article are:

  • setHMS: set the initial time
  • addMSecs: add a time (millisecond unit)
  • toString: convert time to string format
  • Minute: get the minute
  • Second: get the second
  • msec: Get milliseconds

2.3 Functions of Corresponding Buttons

In order to write more understandable code, before writing the code, you need to change the default name of the corresponding component to a name that is easy to understand. For example, I changed the names of the three buttons to:

  • Btn_Start: Start button with pause/resume function
  • Btn_Reset: reset button
  • Btn_Hit: Dot button, used to record the time of different positions

Then add QTimer and QTime objects manually to realize the timing function of the stopwatch:

2.3.1 Processing of Start Button

The important processing in Qt programming is the signal and slot mechanism, which can be realized manually through the connet function. For the graphic interface design method using Qt Creator, the signal and slot connection usually continue to be realized through the interface: Right click the Start button and select "Go to slot...":

Then there are multiple button signals to choose from, because the start button has the function of pause/resume at the same time. Here, the toggled function is used to realize the function of pause/resume by using the press and release state of the button:

After clicking OK, you will automatically jump to the code page, and automatically generate the corresponding slot function framework. Then you can compile the corresponding business logic code in it:

The specific business logic code of the Start button is as follows. When the button is pressed for the first time, checked is true. At this time, the timer is started, the time stamp is recorded, and the button text is displayed as "Pause". At the same time, the Reset and Dot buttons are grayed out, so that the two buttons cannot be pressed again, because it is meaningless to perform reset and dotting when pausing.

The timer will trigger a timeout every other period of time. Here, ADD_ TIME_ The MSEC is set to 30ms. After the timeout expires, write the corresponding timeout processing function timeout_slot and processing of the corresponding signal and slot.

void Widget::on_Btn_Start_toggled(bool checked)
{
    if (checked)
    {
        timer.start(ADD_TIME_MSEC);
        lastTime = QTime::currentTime();//Record Timestamp
        ui->Btn_Start->setText("suspend");
        ui->Btn_Reset->setEnabled(false);
        ui->Btn_Hit->setEnabled(true);
    }
    else
    {
        timer.stop();
        ui->Btn_Start->setText("continue");
        ui->Btn_Reset->setEnabled(true);
        ui->Btn_Hit->setEnabled(false);
    }
}

connect(&timer, SIGNAL(timeout()), this, SLOT(timeout_slot()));
void Widget::timeout_slot()
{
    //qDebug("hello");
    QTime nowTime = QTime::currentTime();
    time = time.addMSecs(lastTime.msecsTo(nowTime));
    lastTime = nowTime;
    ui->Txt_ShowTime->setText(time.toString("mm:ss.zzz"));
}

After the timeout expires, calculate some time difference between the two times, and then accumulate the time through the addMSecs function.

2.3.2 Processing of reset button

The reset button is also adjusted to the slot by right clicking. Note that the clicked function can be used here, because the reset button only needs to use its click and press function:

The corresponding slot function is implemented as follows:

void Widget::on_Btn_Reset_clicked()
{
    m_iHitCnt = 0;
    timer.stop();
    time.setHMS(0,0,0,0);
    ui->Txt_ShowTime->setText("00:00:00");
    ui->Txt_ShowItem->clear();

    ui->Btn_Start->setText("start");
    ui->Btn_Start->setChecked(false);
    ui->Btn_Reset->setEnabled(false);
    ui->Btn_Hit->setEnabled(false);
}

It is mainly to reset the time to zero, display the situation, and reset the display status of each button to the default display status.

2.3.3 Processing of dotting buttons

Like the reset button, the click button only uses the clicked function. The specific implementation of the corresponding slot function is as follows:

void Widget::on_Btn_Hit_clicked()
{
    QString temp;
    m_iHitCnt++;
    temp.sprintf("--times count %d--", m_iHitCnt);
    ui->Txt_ShowItem->setFontPointSize(9);
    ui->Txt_ShowItem->append(temp);
    ui->Txt_ShowItem->setFontPointSize(12);
    ui->Txt_ShowItem->append(time.toString("[mm:ss.zzz]"));
}

The punctuation function is used to record the time of different positions in the running process of the stopwatch and display it in the text display box on the right.

Here, the setFontPointSize function is used to set the font display of different sizes.

2.4 Realization of stopwatch dial

Previous article: Embedded Qt - write and run your first ARM Qt program by hand , realized the display of a clock dial by means of code. Based on this, this article modifies the code to realize a stopwatch dial that displays seconds and minutes. The specific modified code is as follows:

connect(&timer, SIGNAL(timeout()), this, SLOT(update()));
connect(ui->Btn_Reset, SIGNAL(clicked()), this, SLOT(update()));

void Widget::paintEvent(QPaintEvent *event)
{
    int side = qMin(width(), height());
    //QTime time = QTime::currentTime();

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.translate(width()/3, height()*2/5); //Reference position for drawing
    painter.scale(side/300.0, side/300.0); //Auto Zoom with Window Size

    //Dial (3 concentric circles)
    for (int i=0; i<PANEL_RADIUS_NUM; i++)
    {
        QBrush brush(stPanelParaArr[i].color);
        QPen pen(stPanelParaArr[i].color);
        painter.setBrush(brush);
        painter.setPen(pen);
        painter.drawEllipse(-stPanelParaArr[i].radius, -stPanelParaArr[i].radius, 2*stPanelParaArr[i].radius, 2*stPanelParaArr[i].radius);
    }

    //Seconds scale
    painter.setPen(secondColor);
    for (int i = 0; i < 60; i++)
    {
        if ((i % 5) == 0)
        {
            painter.drawLine(PANEL_RADIUS3-8, 0, PANEL_RADIUS3, 0);
            QFont font("TimesNewRoman", SEC_NUM_SIZE);
            painter.setFont(font);
            painter.drawText(-SEC_NUM_SIZE, -(CLOCK_RADIUS-15), 2*SEC_NUM_SIZE, 2*SEC_NUM_SIZE, Qt::AlignHCenter, QString::number(i==0? 60 : i));
        }
        else
        {
            painter.drawLine(PANEL_RADIUS3-5, 0, PANEL_RADIUS3, 0);
        }
        //Subdivide 5 grids in a second
        for (int j = 0; j < 5; j++)
        {
            painter.rotate(6.0/5);
            if (j != 4)
            {
                painter.drawLine(PANEL_RADIUS3-2, 0, PANEL_RADIUS3, 0);
            }
        }
    }

    //Minute scale
    painter.setPen(minuteColor);
    for (int k = 0; k < 30; k++)
    {
        if ((k % 5) == 0)
        {
            painter.rotate(-90.0);
            painter.drawLine(PANEL_RADIUS4-8, 0, PANEL_RADIUS4, 0);
            painter.rotate(90.0);

            QFont font("TimesNewRoman", MIN_NUM_SIZE);
            painter.setFont(font);
            painter.drawText(-MIN_NUM_SIZE, -(PANEL_RADIUS4-10), 2*MIN_NUM_SIZE, 2*MIN_NUM_SIZE, Qt::AlignHCenter, QString::number(k==0? 30 : k));
        }
        else
        {
            painter.rotate(-90.0);
            painter.drawLine(PANEL_RADIUS4-4, 0, PANEL_RADIUS4, 0);
            painter.rotate(90.0);
        }
        painter.rotate(12.0);
    }

    //Minute needle
    painter.setPen(Qt::NoPen);
    painter.setBrush(minuteColor);
    painter.save();
    painter.rotate(12.0 * (time.minute() + time.second() / 60.0));
    painter.drawConvexPolygon(minuteHand, 3);
    painter.restore();

    //Second needle
    painter.setPen(Qt::NoPen);
    painter.setBrush(secondColor);
    painter.save();
    //painter.rotate(6.0 * time.second());
    painter.rotate(6.0 * (time.second()+time.msec()/1000.0));
    painter.drawConvexPolygon(secondHand, 3);
    painter.restore();

    painter.end();
}

The main modification is to remove the previous hour display and change it into two time rings: the outer second ring and the inner sub ring. The range of the second ring is 060 seconds and the sub ring is 030 minutes.

The display effect of stopwatch dial is as follows:

3 Compile and run

The code is written in Qt Creator in the Window environment. First, compile and view the effect in Windows.

3.1 Compilation in Windows

The running effect in Windows is shown in the right figure below, which can achieve the timing effect similar to the stopwatch in the mobile phone:

3.2 Compilation in Ubuntu

Transfer the QT project source code in Windows:

  • . cpp file
  • . h file
  • . pro file
  • . ui file

Copy it to Ubuntu. Note that the. user file is unnecessary (it is a compilation configuration of the Windows platform).

Then use the ARM platform's compilation tool chain. My tool is "/home/xxpcb/myTest/imx6ull/otherlib/qt/qt-everywhere-src-5.12.9/arm qt/". Here, you need to use its qmake tool to automatically generate Makefile files, and then compile through the make command.

Use qmake to generate Makefile, enter the program source code directory, and execute the qmake command:

/home/xxpcb/myTest/imx6ull/otherlib/qt/qt-everywhere-src-5.12.9/arm-qt/bin/qmake

After successful execution, you can see the automatically generated Makefile file, and then execute the make command to compile the executable file.

3.3 Running in Linux board

Put the executable file on the Linux board with the qt running environment configured, run it and check the effect:
https://www.bilibili.com/video/BV1XW4y1y7pK

Note:

For the specific compilation process in Ubuntu, refer to the previous article: Embedded Qt - write and run your first ARM Qt program by hand

For the configuration of the cross compilation environment of Qt in Ubuntu, refer to the previous article: Embedded Linux Qt environment construction

4 Summary

This article introduces how to use the UI interface design function of Qt Creator to develop Qt, cross compile the code, and put it into the i.MX6ULL Linux environment to test the running situation through an example of a stopwatch.

Tags: Embedded system Qt UI programming language

Posted by sprintlife on Sat, 24 Sep 2022 01:35:19 +0930