
Creating a basic digital clock
It's time to create a new project, so we will create a Qt Widgets application named Fancy_Clock
.
Now, change the window title to Fancy Clock
or any other name that you like. Then, the main window UI needs to be tailored because the clock is displayed at the top of the desktop. The menu bar, status bar, and toolbar are all removed. After that, we need to drag an LCD Number widget into centralWidget
. Next, change the layout of MainWindow
to LayOut Horizontally in order to autoresize the subwidget. The last thing that needs to be done to the UI file is to change frameShape to NoFrame under the QFrame column in the property of lcdNumber
. If you've done this right, you'll get a prototype of a digital clock, as shown here:

In order to update the LCD number display repeatedly, we have to make use of the QTimer
class to set up a timer that emits a signal repetitively. In addition to this, we need to create a slot to receive the signal and to update the LCD number display to the current time. Thus, the QTime
class is also needed. This is how the header file of MainWindowmainwindow.h
will look now:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; private slots: void updateTime(); }; #endif // MAINWINDOW_H
As you can see, the only modification made here is the declaration of a private updateTime
slot. As usual, we're supposed to define this slot in mainwindow.cpp
, whose content is pasted here. Note that we need to include QTimer
and QTime
.
#include <QTimer> #include <QTime> #include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTimer *timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &MainWindow::updateTime); timer->start(1000); updateTime(); } MainWindow::~MainWindow() { delete ui; } void MainWindow::updateTime() { QTime currentTime = QTime::currentTime(); QString currentTimeText = currentTime.toString("hh:mm"); if (currentTime.second() % 2 == 0) { currentTimeText[2] = ' '; } ui->lcdNumber->display(currentTimeText); }
Inside the updateTime
slot, the QTime
class is used to deal with the time, that is, the clock. This class can provide accuracy of up to 1 millisecond, if the underlying operating system supports it. However, QTime
has nothing to do with the time zone or daylight saving time. It is, at least, sufficient for our little clock. The currentTime()
function is a static public function, which is used to create a QTime
object that contains the system's local time.
As for the second line of the updateTime
function, we used the toString
function provided by QTime
to convert the time to a string, and then saved it in currentTimeText
. The arguments that are passed to toString
are in the format of the time string. The full list of expressions can be obtained from Qt Reference Documentation. The colon in the middle of the clock should be flashing, just as in the case of a real digital clock. Hence, we used an if
statement to control this. The colon will vanish when the second's value is even, and it will reappear when the second's value is odd. Here, inside the if
block, we used the [2]
operator to get a modifiable reference of the third character because this is the only way to do direct modifications to a character inside a string. Here, the counting of the currentTimeText
string starts from 0
. Meanwhile, the at()
function of QString
returns a constant character, which you have no right to change. At last, this function will let lcdNumber
display the time string. Now, let's get back to the constructor of MainWindow
. After the initialization of the UI, the first thing it does is to create a QTimer
object. Why can't we use a local variable? The answer to that question is because the local variables will be destroyed after the construction of MainWindow
. If the timer has gone, there's no way to trigger updateTime
repetitively. We don't use a member variable because there is no need to perform the declaration work in the header file, since we won't use this timer elsewhere.
The QTimer
class is used to create a repetitive and single-shot timer. It will emit the timeout
signal at constant intervals after start
is called. Here, we create one timer and connect the timeout
signal to the updateTime
slot so that updateTime
is called every second.
There is another important aspect in Qt called parent-child mechanism. Although it's not as well-known as signals and slots, it plays a crucial role in the development of the Qt applications. Basically speaking, when we create an QObject
child with a parent or explicitly set a parent by calling setParent
, the parent will add this QObject
child to its list of children. Then, when the parent is deleted, it'll go through its list of children and delete each child. In most cases, especially in the design of a UI, the parent-child relationship is set up implicitly. The parent widget or layout automatically becomes the parent object to its children widgets or layouts. In other cases, we have to explicitly set the parent for a QObject
child so that the parent can take over its ownership and manage the release of its memory. Hence, we pass the QObject
parent, which is this, a MainWindow
class to the constructor of QTimer
. This ensures that QTimer
will be deleted after MainWindow
is deleted. That's why we don't have to explicitly write the delete
statements in the destructor.
At the end of the constructor, we need to call updateTime
explicitly, which will allow the clock to display the current time. If we don't do this, the application will display a zero for a second until the timeout
signal is emitted by timer
. Now, run your application; it will be similar to the following screenshot:
