Evgenii Legotckoi
Evgenii Legotckoi20 августа 2015 г. 8:45

Qt/C++ - Урок 009. QTimer или Как работать с таймером в Qt?

Немного поговорим о применении класса QTimer в Qt. Это небольшая легкая тема после серии объемных статей про QSqlTabelModel и вытекающих из неё последствий. А то уже у самого серое вещество закипает.

Таймеры нам могут понадобиться для создания опроса устройств по ЛВС через стек TCP/IP с определенной периодичностью или для ежечасной проверки данных или активных подключений к серверу. Да для чего угодно!? И тут нам на помощь приходит QTimer, который Мы рассмотрим на примере ежесекундного вывода времени в QLabel.

Программный код был написан в QtCreator 3.3.1 на основе Qt 5.4.1.

Структура проекта для QTimer

Используем минимум файлов в нашем проекте:

  • QDataMapperWidget.pro - профайл;
  • mainwindow.h - заголовочный файл основного окна приложения;
  • mainwindow.cpp - исходный код окна;
  • main.cpp - основной исходный файл, с которого стартует приложение;
  • mainwindow.ui - формочка основного окна приложения;
  • А формочку нарисуем в Дизайнере QtCreator. Впрочем там и рисовать нечего. Кинули QLabel в середину и готово.

mainwindow.h

Всё, что нам надо для счастья в этом проекте - это слот, который будет реагировать на срабатывание QTimer, да сам объекта этого класса.

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QFont>
#include <QTimer>
#include <QTime>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    /* Будем использовать только один слот */
private slots:
    void slotTimerAlarm();

private:
    Ui::MainWindow *ui;
    /* Да сам объект QTimer */
    QTimer *timer;
};

#endif // MAINWINDOW_H

mainwindow.cpp

А теперь несколько строчек по запуску таймера. По-моему комментариев больше, чем кода. Обычно так на Assembler'е пишут - 20 % кода и 80% комментариев.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    /* Немножко подшаманим QLabel, чтобы он был больше,
     * и заметнее в пустующем окне
     * */
    QFont font("Times", 28, QFont::Bold);
    ui->label->setFont(font);

    /* При первом запуске приложения поместим текущее время в QLabel
     * */
    ui->label->setText(QTime::currentTime().toString("hh:mm:ss"));

    /* Инициализируем Таймер и подключим его к слоту,
     * который будет обрабатывать timeout() таймера
     * */
    timer = new QTimer();
    connect(timer, SIGNAL(timeout()), this, SLOT(slotTimerAlarm()));
    timer->start(1000); // И запустим таймер
}

MainWindow::~MainWindow()
{
    delete ui;
}

/* Слот для обработки timeout() таймера
 * */
void MainWindow::slotTimerAlarm()
{
    /* Ежесекундно обновляем данные по текущему времени
     * Перезапускать таймер не требуется
     * */
    ui->label->setText(QTime::currentTime().toString("hh:mm:ss"));
}

Итог

В результате при запуске обнаружим, как каждую секунду у Нас меняется время в окне приложения

QTimer example

Рекомендуем хостинг TIMEWEB
Рекомендуем хостинг TIMEWEB
Стабильный хостинг, на котором располагается социальная сеть EVILEG. Для проектов на Django рекомендуем VDS хостинг.

Вам это нравится? Поделитесь в социальных сетях!

N
  • 8 августа 2017 г. 6:03

Добрый день! Появилась проблемка. Есть клиент-серверное приложение. Нужно послать с сервера к клиентам сообщение через определенные промежутки времени.  Реализовал это таким образом, что если у нас в QList лежит больше 1 сокета, то сначало посылается сообщение 1 клиенту, а потом включается таймер, но перед этим записывалось значение i в глобальную переменну(i взято из for). Использовал QTimer::singleshot(2000,this,Slot(slotZ()));. происходит вызов другой функции, где значение сокета берется из списка, по номеру как раз взятого из глобальной переменны, но почему то заместо того чтобы послать на 2 и 3 клиент через 2 сек сообщение, он посылает 2 сообщения на последний клиент.

void MyServer::slotWriteClient()
{
    if(lis.length() != 0)
    {
        QString str;


        for(int i = 0; i < lis.length(); i++)
        {
            socet = lis.at(i);
            if(lineEdit_4->text() == NULL){
                str = QString::number(i + 1) + " Client";
                sendToClient(socet,
                             "Server Response: Received \"" + str + "\""
                             );
            }
            else
            {
                str = lineEdit_4->text();
                
                if(i >= 1)
                {    

                    socn = i;
//                    QTimer *timer = new QTimer(this);
//                    timer->setInterval(2000);
//                    connect(timer, SIGNAL(timeout()), this, SLOT(slotZad(i)));

//                    timer->start();
                    QTimer::singleShot(2000, this, SLOT(slotZad()));

                }
                else
                    sendToClient(socet, str);
            }
        }
    }
    else
        m_ptxt->append("Пуст");
}

void MyServer::slotZad()
{
    QString str;

    qDebug() << socn;
    socet = lis.at(socn);
    str = lineEdit_4->text();
    sendToClient(socet, str);
}
Evgenii Legotckoi
  • 8 августа 2017 г. 6:35
Добрый день!
Цикл for успевает отработать и сформировать переменную socn до того, как слот slotZad отработает хотя бы раз. При этом цикл for выполнится полностью. В результате в переменной socn будет использоваться переменная i равная последнему индексу.
Вам нужно переделать участок с QTimer::singleShot как-то иначе, например, прерывать цикл for, как только запустили QTimer::singleShot. А в слоте slotZad() инкрементировать переменную socn с проверкой на выход за пределы списка сокетов. И если есть ещё не обработанные сокеты, то запускать заново QTimer::singleShot в слоте slotZad().

Дополнительное code review:
Вместо этого
if(lineEdit_4->text() == NULL){
используйте метод QString::isEmpty()
if(lineEdit_4->text().isEmpty()){

P/S/ В дальнейшем создавайте темы с подобными вопросами на форуме сайта. Вопрос, конечно, имеет отношение к статье, но косвенное.

N
  • 8 августа 2017 г. 7:30

Спасибо! Учту.

AC
  • 6 сентября 2022 г. 15:40

Вижу вы используете
new QTimer();
А кто будет память освобождать?
Почему вы вообще используете указатель QTimer *timer; а не объявите поле QTimer timer;?

Evgenii Legotckoi
  • 7 сентября 2022 г. 3:16
  • (ред.)

Потому что 7 лет назад я был бестолковее, чем сейчас.

f
  • 7 сентября 2022 г. 23:00

QTimer унаследован от QObject и ему передан this, идиома Qt предпологает что при вызове деструктора обьекта класса MyServer, обьект *timer тоже будет освобожден. Поправьте если ошибаюсь!

Evgenii Legotckoi
  • 12 сентября 2022 г. 3:04

Да, именно так. Но в коде без this написано - это ошибка в статье.

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь
e
  • ehot
  • 1 апреля 2024 г. 0:29

C++ - Тест 003. Условия и циклы

  • Результат:78баллов,
  • Очки рейтинга2
B

C++ - Тест 002. Константы

  • Результат:16баллов,
  • Очки рейтинга-10
B

C++ - Тест 001. Первая программа и типы данных

  • Результат:46баллов,
  • Очки рейтинга-6
Последние комментарии
k
kmssr9 февраля 2024 г. 5:43
Qt Linux - Урок 001. Автозапуск Qt приложения под Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко5 февраля 2024 г. 12:50
Qt WinAPI - Урок 007. Работаем с ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 декабря 2023 г. 21:30
Boost - статическая линковка в CMake проекте под Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 декабря 2023 г. 19:38
Boost - статическая линковка в CMake проекте под Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 декабря 2023 г. 8:01
Qt/C++ - Урок 056. Подключение библиотеки Boost в Qt для компиляторов MinGW и MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Сейчас обсуждают на форуме
a
a_vlasov14 апреля 2024 г. 16:41
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Евгений, добрый день! Такой вопрос. Верно ли следующее утверждение: Любое Android-приложение, написанное на Java/Kotlin чисто теоретически (пусть и с большими трудностями) можно написать и на C+…
Павел Дорофеев
Павел Дорофеев14 апреля 2024 г. 12:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex4 апреля 2024 г. 14:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…
P
Pisych27 февраля 2023 г. 15:04
Как получить в массив значения из связанной модели? Спасибо, разобрался:))
AC
Alexandru Codreanu19 января 2024 г. 22:57
QML Обнулить значения SpinBox Доброго времени суток, не могу разобраться с обнулением значение SpinBox находящего в делегате. import QtQuickimport QtQuick.ControlsWindow { width: 640 height: 480 visible: tr…

Следите за нами в социальных сетях