From 19608edbc520c751e096d97bc1325a8c372a4ee9 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Wed, 25 May 2022 15:48:16 +0400 Subject: [PATCH 1/2] feat: add translation for 'date and time' article --- qt5/date_and_time.md | 835 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 835 insertions(+) create mode 100644 qt5/date_and_time.md diff --git a/qt5/date_and_time.md b/qt5/date_and_time.md new file mode 100644 index 0000000..82e72cf --- /dev/null +++ b/qt5/date_and_time.md @@ -0,0 +1,835 @@ +## Дата и время в Qt5 + +В этой части учебника по программированию на Qt5 C++ мы поговорим о времени и дате. + +В Qt5 есть классы QDate, QTime и QDateTime для работы с датой и временем. QDate - это класс для работы с календарной датой в григорианском календаре. В нем есть методы для определения даты, сравнения или манипулирования датами. Класс QTime работает с часовым временем. Он предоставляет методы для сравнения времени, определения времени и различные другие методы манипулирования временем. QDateTime - это класс, который объединяет объекты QDate и QTime в один объект. + +В этой главе мы создавали программы командной строки; поэтому нам не нужен модуль Qt GUI. Мы можем добавить объявление QT -= gui в файл проекта. + + +## Инициализация объектов даты и времени в Qt5 + +Объекты даты и времени могут быть инициализированы двумя основными способами. Мы инициализируем их в конструкторе объекта или можем создать пустые объекты и заполнить их данными позже. + +~~~ +#include +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate dt1 { 2020, 4, 12 }; + out << "The date is " << dt1.toString() << endl; + + QDate dt2; + dt2.setDate(2020, 3, 3); + out << "The date is " << dt2.toString() << endl; + + QTime tm1 { 17, 30, 12, 55 }; + out << "The time is " << tm1.toString("hh:mm:ss.zzz") << endl; + + QTime tm2; + tm2.setHMS(13, 52, 45, 155); + out << "The time is " << tm2.toString("hh:mm:ss.zzz") << endl; +} +~~~ +Мы инициализируем объект даты и времени обоими способами. +~~~ +QDate dt1 { 2020, 4, 12 }; +~~~ +Конструктор объекта QDate принимает три параметра: год, месяц и день. +~~~ +out << "The date is " << dt1.toString() << endl; +~~~ +Дата выводится на консоль. Мы используем метод toString для преобразования объекта даты в строку. +~~~ +QTime tm2; +tm2.setHMS(13, 52, 45, 155); +~~~ + +Создается пустой объект QTime. Мы заполняем объект данными с помощью метода setHMS. Параметрами являются часы, минуты, секунды и миллисекунды. +~~~ +out << "The time is " << tm2.toString("hh:mm:ss.zzz") << endl; +~~~ +Мы выводим объект QTime на консоль. Мы используем специальный формат, который включает также миллисекунды, которые по умолчанию опущены. +~~~ +$ ./init +The date is Sun Apr 12 2020 +The date is Tue Mar 3 2020 +The time is 17:30:12.055 +The time is 13:52:45.155 +~~~ +Qt5 текущая дата и время +В следующем примере мы выводим текущее местное время и дату на консоль. +~~~ +#include +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate cd = QDate::currentDate(); + QTime ct = QTime::currentTime(); + + out << "Current date is: " << cd.toString() << endl; + out << "Current time is: " << ct.toString() << endl; +} +~~~ +Обратите внимание, что файл не должен называться time.cpp. +~~~ +QDate cd = QDate::currentDate(); +~~~ +Статическая функция QDate::currentDate возвращает текущую дату. +~~~ +QTime ct = QTime::currentTime(); +~~~ +Статическая функция QTime::currentTime возвращает текущее время. +~~~ +out << "Current date is: " << cd.toString() << endl; +out << "Current time is: " << ct.toString() << endl; +~~~ +Мы используем метод toString для преобразования объектов даты и времени в строки. +~~~ +$ ./current +Current date is: Thu Dec 3 2020 +Current time is: 10:21:48 +~~~ + +## Qt5 сравнение дат + +Реляционные операторы можно использовать для сравнения дат. Мы можем сравнить их положение в календаре. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate dt1 { 2020, 4, 5 }; + QDate dt2 { 2019, 4, 5 }; + + if (dt1 < dt2) { + + out << dt1.toString() << " comes before " + << dt2.toString() << endl; + } else { + + out << dt1.toString() << " comes after " + << dt2.toString() << endl; + } +} +~~~ +Пример сравнения двух дат. +~~~ +QDate dt1 { 2020, 4, 5 }; +QDate dt2 { 2019, 4, 5 }; +~~~ +Мы имеем две разные даты. +~~~ +if (dt1 < dt2) { + + out << dt1.toString() << " comes before " + << dt2.toString() << endl; +} else { + + out << dt1.toString() << " comes after " + << dt2.toString() << endl; +} +~~~ +Мы сравниваем даты с помощью оператора сравнения lower than (<) и определяем, какая из них расположена раньше в календаре. +~~~ +$ ./compare +Sun Apr 5 2020 comes after Fri Apr 5 2019 +~~~ +Операторы сравнения можно легко использовать и для объектов QTime и QDateTime. + + +## Qt5 определение високосного года + + + Високосный год - это год, содержащий дополнительный день. Причина появления дополнительного дня в календаре заключается в разнице между астрономическим и календарным годом. В календарном году ровно 365 дней, а в астрономическом - 365,25 дня, т.е. время, за которое Земля совершает один оборот вокруг Солнца. + +Разница составляет 6 часов, что означает, что за четыре года мы теряем один день. Поскольку мы хотим, чтобы наш календарь был синхронизирован с временами года, мы добавляем один день к февралю каждые четыре года. (Есть исключения.) В григорианском календаре в феврале високосного года 29 дней вместо обычных 28. А год длится 366 дней вместо обычных 365. + +Статический метод QDate::isLeapYear определяет, является ли год високосным. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QList years({2010, 2011, 2012, 2013, 2014, 2015, 2016, 2020, 2024}); + + for (int year: years) { + + if (QDate::isLeapYear(year)) { + + out << year << " is a leap year" << endl; + } else { + + out << year << " is not a leap year" << endl; + } + } +} +~~~ + +В примере у нас есть список годов. Мы проверяем каждый год, является ли он високосным. +~~~ +QList years({2010, 2011, 2012, 2013, 2014, 2015, 2016, 2020, 2024}); +~~~ +Инициализируем список годов. +~~~ +for (int year: years) { + + if (QDate::isLeapYear(year)) { + + out << year << " is a leap year" << endl; + } else { + + out << year << " is not a leap year" << endl; + } +} +~~~ +Мы проходим по списку и определяем, является ли данный год високосным. Функция QDate::isLeapYear возвращает булево значение true или false. +~~~ +$ ./leapyear +2010 is not a leap year +2011 is not a leap year +2012 is a leap year +2013 is not a leap year +2014 is not a leap year +2015 is not a leap year +2016 is a leap year +2020 is a leap year +2024 is a leap year +~~~ + + +## Предопределенные форматы даты в Qt5 + +В Qt5 есть несколько встроенных форматов даты. Метод toString объекта QDate принимает формат даты в качестве параметра. По умолчанию в Qt5 используется формат даты Qt::TextDate. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate cd = QDate::currentDate(); + + out << "Today is " << cd.toString(Qt::TextDate) << endl; + out << "Today is " << cd.toString(Qt::ISODate) << endl; + out << "Today is " << cd.toString(Qt::SystemLocaleShortDate) << endl; + out << "Today is " << cd.toString(Qt::SystemLocaleLongDate) << endl; + out << "Today is " << cd.toString(Qt::DefaultLocaleShortDate) << endl; + out << "Today is " << cd.toString(Qt::DefaultLocaleLongDate) << endl; + out << "Today is " << cd.toString(Qt::SystemLocaleDate) << endl; + out << "Today is " << cd.toString(Qt::LocaleDate) << endl; +} +~~~ + В примере мы показываем восемь различных форматов даты для текущей даты. +~~~ +out << "Today is " << cd.toString(Qt::ISODate) << endl; +~~~ +Здесь мы выводим текущую дату в формате Qt::ISODate, который является международным стандартом для отображения дат. +~~~ +$ ./predefineddateformats +Today is Thu Dec 3 2020 +Today is 2020-12-03 +Today is 12/3/20 +Today is Thursday, December 3, 2020 +Today is 12/3/20 +Today is Thursday, December 3, 2020 +Today is 12/3/20 +Today is 12/3/20 +~~~ + + +## Пользовательские форматы даты в Qt5 + +Дата может быть представлена в различных других форматах. В Qt5 мы можем создавать и свои собственные форматы дат. Другая версия метода toString принимает строку формата, в которой мы можем использовать различные спецификаторы формата. Например, спецификатор d обозначает день как число без ведущего нуля. Спецификатор dd обозначает день как число с ведущим нулем. В следующей таблице перечислены доступные выражения формата даты: + +| Выражение | Вывод | +| ---------- | ----------------------------------------------------------------- | +| d | День как число без ведущего нуля (от 1 до 31) | +| dd | День в виде числа с ведущим нулем (от 01 до 31). | +| ddd | Сокращенное локализованное имя дня (например, от 'Mon' до 'Sun'). Используется QDate::shortDayName. | +| dddd | Длинное локализованное имя дня (например, от 'Monday' до 'Sunday'). Используется QDate::longDayName. | +| M | Месяц в виде числа без ведущего нуля (от 1 до 12). | +| MM | Месяц в виде числа с ведущим нулем (от 01 до 12) | +| MMM | Сокращенное локализованное название месяца (например, от 'Jan' до 'Dec'). Используется QDate::shortMonthName. | +| MMMM | Длинное локализованное название месяца (например, от "январь" до "декабрь"). Используется QDate::longMonthName. | +| yy | Год в виде двузначного числа (от 00 до 99). | +| yyyy | Год как четырехзначное число. Если год отрицательный, дополнительно добавляется знак минус. | + +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate cd = QDate::currentDate(); + + out << "Today is " << cd.toString("yyyy-MM-dd") << endl; + out << "Today is " << cd.toString("yy/M/dd") << endl; + out << "Today is " << cd.toString("d. M. yyyy") << endl; + out << "Today is " << cd.toString("d-MMMM-yyyy") << endl; +} +~~~ + +У нас есть четыре пользовательских формата даты. +~~~ +out << "Today is " << cd.toString("yyyy-MM-dd") << endl; +~~~ + + Это международный формат даты. Части даты разделяются символом тире. ГГГГ - это год, состоящий из четырех цифр. ММ - это месяц как число с ведущим нулем (от 01 до 12). И dd - день как число с ведущим нулем (от 01 до 31). +~~~ +out << "Today is " << cd.toString("yy/M/dd") << endl; +~~~ +Это еще один распространенный формат даты. Части разделяются символом косой черты (/). Спецификатор M обозначает месяц как число без ведущего нуля (от 1 до 12). +~~~ +out << "Today is " << cd.toString("d. M. yyyy") << endl; +~~~ +Этот формат даты используется в Словакии. Части разделяются символом точки. День и месяц не содержат ведущих нулей. Сначала идет день, затем месяц, а последним - год. +~~~ +$ ./customdateformats +Today is 2020-12-03 +Today is 20/12/03 +Today is 3. 12. 2020 +Today is 3-December-2020 +~~~ + +## Qt5 предопределенные форматы времени + + +Время имеет несколько предопределенных форматов. Стандартные спецификаторы формата идентичны тем, которые используются в форматах даты. По умолчанию в Qt5 используется формат времени Qt::TextDate. + +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QTime ct = QTime::currentTime(); + + out << "The time is " << ct.toString(Qt::TextDate) << endl; + out << "The time is " << ct.toString(Qt::ISODate) << endl; + out << "The time is " << ct.toString(Qt::SystemLocaleShortDate) << endl; + out << "The time is " << ct.toString(Qt::SystemLocaleLongDate) << endl; + out << "The time is " << ct.toString(Qt::DefaultLocaleShortDate) << endl; + out << "The time is " << ct.toString(Qt::DefaultLocaleLongDate) << endl; + out << "The time is " << ct.toString(Qt::SystemLocaleDate) << endl; + out << "The time is " << ct.toString(Qt::LocaleDate) << endl; +} +~~~ + В примере мы показываем восемь различных форматов текущего времени. +~~~ +out << "The time is " << ct.toString(Qt::ISODate) << endl; +~~~ +Здесь мы выводим текущее время в формате Qt::ISODate, который является международным стандартом для отображения времени. +~~~ +$ ./predefinedtimeformats +The time is 10:59:05 +The time is 10:59:05 +The time is 10:59 AM +The time is 10:59:05 AM CET +The time is 10:59 AM +The time is 10:59:05 AM CET +The time is 10:59 AM +The time is 10:59 AM +~~~ + +## Пользовательские форматы времени в Qt5 + + +Мы можем создавать дополнительные форматы времени. Мы создаем пользовательский формат времени, в котором мы используем спецификаторы формата времени. В следующей таблице приведен список доступных выражений формата. + +| Выражение | Вывод | +| ---------- | ----------------------------------------------------------------- | +| h | час без ведущего нуля (от 0 до 23 или от 1 до 12, если отображается AM/PM) | +| hh | час с ведущим нулем (от 00 до 23 или от 01 до 12, если отображается AM/PM) | +| H | час без ведущего нуля (от 0 до 23, даже при отображении AM/PM) | +| HH | час с ведущим нулем (от 00 до 23, даже при отображении AM/PM) | +| m | минута без ведущего нуля (от 0 до 59) | +| mm | минуты с ведущим нулем (от 00 до 59) | +| s | секунда без ведущего нуля (от 0 до 59) | +| ss | секунда с ведущим нулем (от 00 до 59) | +| z | миллисекунды без ведущих нулей (от 0 до 999) | +| zzz | миллисекунды с ведущими нулями (от 000 до 999) | +|AP or A | используйте индикацию AM/PM. AP будет заменен на "AM" или "PM". | +|ap or a | использовать индикацию am/pm. ap будет заменен либо на "am", либо на "pm". | +|t | часовой пояс (например, "CEST") | + + +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QTime ct = QTime::currentTime(); + + out << "The time is " << ct.toString("hh:mm:ss.zzz") << endl; + out << "The time is " << ct.toString("h:m:s a") << endl; + out << "The time is " << ct.toString("H:m:s A") << endl; + out << "The time is " << ct.toString("h:m AP") << endl; +} +~~~ +У нас есть четыре пользовательских формата времени. +~~~ +out << "The time is " << ct.toString("hh:mm:ss.zzz") << endl; +~~~ +В этом формате у нас есть час, минута и секунда с ведущим нулем. Мы также добавляем миллисекунды с ведущими нулями. +~~~ +out << "The time is " << ct.toString("h:m:s a") << endl; +~~~ +Этот спецификатор формата времени использует час, минуту и секунду без ведущего нуля и добавляет идентификаторы периода am/pm. +~~~ +$ ./customtimeformats +The time is 11:03:16.007 +The time is 11:3:16 am +The time is 11:3:16 AM +The time is 11:3 AM +~~~ + + +## Qt5 получение дня недели + +Метод dayOfWeek возвращает число, представляющее день недели, где 1 - понедельник, а 7 - воскресенье. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate cd = QDate::currentDate(); + int wd = cd.dayOfWeek(); + + QLocale locale(QLocale("en_US")); + + out << "Today is " << locale.dayName(wd) << endl; + out << "Today is " << locale.dayName(wd, QLocale::ShortFormat) << endl; +} +~~~ + В примере мы выводим короткое и длинное названия текущего дня недели. +~~~ +QDate cd = QDate::currentDate(); +~~~ +Получаем текущую дату. +~~~ +int wd = cd.dayOfWeek(); +~~~ +Из текущей даты получаем день недели. +~~~ +out << "Сегодня " << locale.dayName(wd) << endl; +~~~ +Получаем длинное имя дня недели. +~~~ +out << "Сегодня " << locale.dayName(wd, QLocale::ShortFormat) << endl; +~~~ +Мы получаем длинное имя дня недели. +~~~ +$ ./weekday +Today is Thursday +Today is Thu +~~~ + + +## Номер дня + +Мы можем вычислить количество дней в конкретном месяце с помощью метода daysInMonth и количество дней в году с помощью метода daysInYear. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + QList months; + + months.append("January"); + months.append("February"); + months.append("March"); + months.append("April"); + months.append("May"); + months.append("June"); + months.append("July"); + months.append("August"); + months.append("September"); + months.append("October"); + months.append("November"); + months.append("December"); + + QDate dt1 { 2020, 9, 18 }; + QDate dt2 { 2020, 2, 11 }; + QDate dt3 { 2020, 5, 1 }; + QDate dt4 { 2020, 12, 11 }; + QDate dt5 { 2020, 2, 29 }; + + out << "There are " << dt1.daysInMonth() << " days in " + << months.at(dt1.month()-1) << endl; + out << "There are " << dt2.daysInMonth() << " days in " + << months.at(dt2.month()-1) << endl; + out << "There are " << dt3.daysInMonth() << " days in " + << months.at(dt3.month()-1) << endl; + out << "There are " << dt4.daysInMonth() << " days in " + << months.at(dt4.month()-1) << endl; + out << "There are " << dt5.daysInMonth() << " days in " + << months.at(dt5.month()-1) << endl; + + out << "There are " << dt1.daysInYear() << " days in year " + << QString::number(dt1.year()) << endl; +} +~~~ +Создаются пять объектов даты. Мы вычисляем количество дней в этих месяцах и в конкретном году. +~~~ +QDate dt1 { 2020, 9, 18 }; +QDate dt2 { 2020, 2, 11 }; +QDate dt3 { 2020, 5, 1 }; +QDate dt4 { 2020, 12, 11 }; +QDate dt5 { 2020, 2, 29 }; +~~~ +Создается пять объектов QDate. Каждый из них представляет отдельную дату. +~~~ +out << "There are " << dt1.daysInMonth() << " days in " + << months.at(dt1.month()-1) << endl; + +~~~ +Мы используем метод daysInMonth, чтобы получить количество дней в объекте даты. +~~~ +out << "There are " << dt1.daysInYear() << " days in year " + << QString::number(dt1.year()) << endl; +~~~ +А здесь мы получаем количество дней в году, используя метод daysInYear для объекта date. +~~~ +$ ./nofdays +There are 30 days in September +There are 29 days in February +There are 31 days in May +There are 31 days in December +There are 29 days in February +There are 366 days in year 2020 +~~~ + +## Qt5 проверка достоверности даты + + +Существует метод isValid, который проверяет, является ли дата действительной. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QList dates { + QDate(2020, 5, 11), QDate(2020, 8, 1), + QDate(2020, 2, 30) + }; + + for (int i=0; i < dates.size(); i++) { + + if (dates.at(i).isValid()) { + + out << "Date " << i+1 << " is a valid date" << endl; + } else { + + out << "Date " << i+1 << " is not a valid date" << endl; + } + } +} +~~~ + + В примере мы проверяем достоверность трех дней. +~~~ +QList dates { + QDate(2020, 5, 11), QDate(2020, 8, 1), + QDate(2020, 2, 30) +}; +~~~ +Первые два дня действительны. Третий день недействителен. В феврале 28 или 29 дней. +~~~ +if (dates.at(i).isValid()) { + + out << "Дата " << i+1 << " является действительной датой" << endl; +} else { + + out << "Дата " << i+1 << " не является действительной датой" << endl; +} +~~~ +В зависимости от результата метода isValid, мы выводим сообщение о валидности даты в консоль. +~~~ +$ ./validity +Date 1 is a valid date +Date 2 is a valid date +Date 3 is not a valid date +~~~ + + +## Qt5 addDays, daysTo + +Мы можем легко вычислить дату через n дней от определенной даты. Для этого мы используем метод addDays. Метод daysTo возвращает количество дней до выбранной даты. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate dt { 2020, 5, 11 }; + QDate nd = dt.addDays(55); + + QDate cd = QDate::currentDate(); + int year = cd.year(); + QDate xmas { year, 12, 24 }; + + out << "55 days from " << dt.toString() << " is " + << nd.toString() << endl; + out << "There are " << QDate::currentDate().daysTo(xmas) + << " days till Christmas" << endl; +} +~~~ +Мы получаем дату на 55 дней позже - 11 мая 2020 года. Мы также получаем количество дней до Рождества. +~~~ +QDate dt { 2020, 5, 11 }; +QDate nd = dt.addDays(55); +~~~ +Метод addDays возвращает QDate, которая находится через 55 дней после заданной даты. +~~~ +QDate xmas { год, 12, 24 }; +... +out << "До Рождества осталось " << QDate::currentDate().daysTo(xmas) + << " дней до Рождества" << endl; +~~~ +Мы используем метод daysTo для вычисления количества дней до Рождества. +~~~ +$ ./daystofrom +55 days from Mon May 11 2020 is Sun Jul 5 2020 +There are 21 days till Christmas +~~~ + +Класс Qt5 QDateTime + +Объект QDateTime содержит календарную дату и часовое время. Он представляет собой комбинацию классов QDate и QTime. У него много похожих методов, а использование идентично этим двум классам. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + QDateTime cdt = QDateTime::currentDateTime(); + + out << "The current datetime is " << cdt.toString() << endl; + out << "The current date is " << cdt.date().toString() << endl; + out << "The current time is " << cdt.time().toString() << endl; +} +~~~ +В примере извлекается текущее время даты. +~~~ +out << "The current datetime is " << cdt.toString() << endl; +~~~ +Эта строка кода выводит текущее время на терминал. +~~~ +out << "Текущая дата - " << cdt.date().toString() << endl; +~~~ +Эта строка извлекает часть даты из объекта datetime с помощью метода date. +~~~ +$ ./datetime +The current datetime is Thu Dec 3 12:29:42 2020 +The current date is Thu Dec 3 2020 +The current time is 12:29:42 +~~~ + +## Юлианский день + +Юлианские сутки - это непрерывный счет дней с начала юлианского периода. Он используется в основном астрономами. Его не следует путать с юлианским календарем. Юлианский период начался в 4713 году до нашей эры. Номер юлианского дня 0 присвоен дню, начинающемуся в полдень 1 января 4713 года до нашей эры. Номер юлианского дня (JDN) - это количество дней, прошедших с начала этого периода. Юлианская дата (JD) любого момента - это номер юлианского дня для предшествующего полудня плюс доля дня, прошедшего с этого момента. (Qt5 не вычисляет эту дробь.) Помимо астрономии, юлианские даты часто используются в военных программах и программах для мэйнфреймов. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate cd = QDate::currentDate(); + + out << "Gregorian date for today: " << cd.toString(Qt::ISODate) << endl; + out << "Julian day for today: " << cd.toJulianDay() << endl; +} +~~~ + В примере мы вычисляем григорианскую дату и юлианский день на сегодня. +~~~ +out << << "Julian day for today: " << cd.toJulianDay() << endl; +~~~ +Юлианский день возвращается с помощью метода toJulianDay. +~~~ +$ ./juliandate +Gregorian date for today: : 2020-12-03 +Julian day for today: 2459187 +~~~ +С помощью юлианской даты легко производить вычисления. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDate bordate(1812, 9, 7); + QDate slavdate(1805, 12, 2); + + QDate cd = QDate::currentDate(); + + int j_today = cd.toJulianDay(); + int j_borodino = bordate.toJulianDay(); + int j_slavkov = slavdate.toJulianDay(); + + out << "Days since Slavkov battle: " << j_today - j_slavkov << endl; + out << "Days since Borodino battle: " << j_today - j_borodino << endl; +} +~~~ +В примере подсчитывается количество дней, прошедших с момента двух исторических событий. +~~~ +QDate bordate(1812, 9, 7); +QDate slavdate(1805, 12, 2); +~~~ +У нас есть две даты сражений наполеоновской эпохи. +~~~ +int j_today = cd.toJulianDay(); +int j_borodino = bordate.toJulianDay(); +int j_slavkov = slavdate.toJulianDay(); +~~~ +Вычисляем юлианские дни для сегодняшнего дня и для битв при Славкове и Бородино. +~~~ +out << << "Days since Slavkov battle: " << j_today - j_slavkov << endl; +out << "Days since Borodino battle: " << j_today - j_borodino << endl; +~~~ +Вычисляем количество дней, прошедших после двух сражений. +~~~ +$ дата +Thu 03 Dec 2020 12:33:56 PM CET +$ ./battles +Days since Slavkov battle: 78529 +Days since Borodino battle: 76058 +~~~ +3 декабря 2020 года прошло 78529 дней со дня Славковского сражения и 76058 дней со дня Бородинского сражения. + + +## Время по Гринвичу(UTC) + +Наша планета представляет собой сферу. Она вращается вокруг своей оси. Земля вращается в сторону востока. Поэтому Солнце восходит в разное время в разных местах. Земля вращается один раз примерно за 24 часа. Поэтому мир разделен на 24 часовых пояса. В каждом часовом поясе существует свое местное время. Это местное время часто дополнительно изменяется в результате перехода на летнее время. + +Существует прагматическая необходимость в едином глобальном времени. Единое глобальное время помогает избежать путаницы в часовых поясах и переходе на летнее время. В качестве основного стандарта времени было выбрано UTC (универсальное координированное время). UTC используется в авиации, при составлении прогнозов погоды, планов полетов, разрешений авиадиспетчеров и карт. В отличие от местного времени, UTC не меняется со сменой времен года. +~~~ +#include +#include + +int main(void) { + + QTextStream out(stdout); + + QDateTime cdt = QDateTime::currentDateTime(); + + out << "Universal datetime: " << cdt.toUTC().toString() << endl; + out << "Local datetime: " << cdt.toLocalTime().toString() << endl; +} +~~~ +В примере мы вычисляем текущее время. Мы выражаем время в формате UTC и локальном времени. +~~~ +out << "Universal datetime" << cdt.toUTC().toString() << endl; +~~~ +Метод toUTC используется для получения времени UTC. +~~~ +out << "Local datetime" << cdt.toLocalTime().toString() << endl; +~~~ +Метод toLocalTime используется для получения локального времени. +~~~ +$ ./utclocal +Universal datetime: Thu Dec 3 11:36:19 2020 GMT +Local datetime: Thu Dec 3 12:36:19 2020 +~~~ +Пример был запущен в Братиславе, где действует центральное европейское время (CET)-UTC + 1 час. + + + +## Эпоха Unix + +Эпоха - это момент времени, выбранный в качестве начала определенной эпохи. Например, в западных христианских странах эпоха времени начинается с 0-го дня, когда родился Иисус. Другой пример - французский республиканский календарь, который использовался в течение двенадцати лет. Эпоха была началом республиканской эры, которая была провозглашена 22 сентября 1792 года, в день провозглашения Первой республики и отмены монархии. + +У компьютеров тоже есть свои эпохи. Одна из самых популярных - эпоха Unix. Эпоха Unix - это время 00:00:00 UTC 1 января 1970 года (или 1970-01-01T00:00:00Z ISO 8601). Дата и время на компьютере определяются в соответствии с количеством секунд или тиков часов, прошедших с момента определения эпохи для данного компьютера или платформы. + +Время Unix - это количество секунд, прошедших с момента эпохи Unix. +~~~ +$ date +%s +1606995554 +~~~ +Команда Unix date может быть использована для получения времени Unix. В данный конкретный момент с момента эпохи Unix прошло 1606995554 секунды. +~~~ +#include +#include +#include + +int main(void) { + + QTextStream out(stdout); + + time_t t = time(0); + out << t << endl; + + QDateTime dt; + dt.setTime_t(t); + out << dt.toString() << endl; + + QDateTime cd = QDateTime::currentDateTime(); + out << cd.toTime_t() << endl; +} +~~~ +В примере мы используем две функции Qt5 для получения времени Unix и преобразования его в человекочитаемую форму. +~~~ +#include +~~~ +Мы включаем стандартный заголовочный файл времени C++. +~~~ +time_t t = time(0); +out << t << endl; +~~~ +С помощью стандартной функции времени C++ мы получаем время Unix. +~~~ +QDateTime dt; +dt.setTime_t(t); +out << dt.toString() << endl; +~~~ +Функция setTime_t используется для преобразования времени Unix в DateTime, которое форматируется в человекочитаемую форму. +~~~ +QDateTime cd = QDateTime::currentDateTime(); +out << cd.toTime_t() << endl; +~~~ +Функция Qt5's toTime_t также может быть использована для получения времени Unix. +~~~ +$ ./unixepoch +1606995613 +Thu Dec 3 12:40:13 2020 +1606995613 +~~~ +В этой главе мы работали с временем и датой в Qt5. + From a2a5573c3972999b3287fd7bb9cb2ba9857787df Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Tue, 7 Jun 2022 16:01:19 +0400 Subject: [PATCH 2/2] feat: add transtale for Events and signals --- qt5/Events_and_signals/Events and signals.md | 431 +++++++++++++++++++ qt5/Events_and_signals/click.png | Bin 0 -> 4340 bytes qt5/Events_and_signals/moveevent.png | Bin 0 -> 3435 bytes qt5/Events_and_signals/timer.png | Bin 0 -> 3528 bytes 4 files changed, 431 insertions(+) create mode 100644 qt5/Events_and_signals/Events and signals.md create mode 100644 qt5/Events_and_signals/click.png create mode 100644 qt5/Events_and_signals/moveevent.png create mode 100644 qt5/Events_and_signals/timer.png diff --git a/qt5/Events_and_signals/Events and signals.md b/qt5/Events_and_signals/Events and signals.md new file mode 100644 index 0000000..ec1cea9 --- /dev/null +++ b/qt5/Events_and_signals/Events and signals.md @@ -0,0 +1,431 @@ +# События и сигналы в Qt5 + +В этой части руководства по программированию Qt5 C++ мы говорим о событиях и сигналах. + +События являются важной частью любой программы с графическим интерфейсом. Все приложения с графическим интерфейсом управляются событиями. Приложение реагирует на различные типы событий, которые генерируются в течение его жизни. События генерируются в основном пользователем приложения. Но они могут быть созданы и другими способами, например. Интернет-соединение, оконный менеджер или таймер. В событийной модели есть три участника: + +- источник события +- объект события +- цель события + +Источником события является объект, состояние которого изменяется. Он генерирует События. Объект события (Event) инкапсулирует изменения состояния в источнике события. Цель события — это объект, который необходимо уведомить. Объект-источник события делегирует задачу обработки события цели события. + +Когда мы вызываем метод exec приложения, приложение входит в основной цикл. Основной цикл извлекает события и отправляет их объектам. Qt имеет уникальный механизм сигналов и слотов. Этот механизм сигналов и слотов является расширением языка программирования C++. + +Сигналы и слоты используются для связи между объектами. Сигнал испускается, когда происходит определенное событие. Слот — это обычный метод C++; он вызывается, когда излучается связанный с ним сигнал. + +## Пример клика Qt5 + +В первом примере показан очень простой пример обработки событий. У нас есть одна кнопка. Нажав на кнопку, мы завершаем работу приложения. +click.h +``` +pragma once + +#include + +class Click : public QWidget { + + public: + Click(QWidget *parent = nullptr); +}; +``` +This is the header file. + +click.cpp +``` +#include +#include +#include +#include "click.h" + +Click::Click(QWidget *parent) + : QWidget(parent) { + + auto *hbox = new QHBoxLayout(this); + hbox->setSpacing(5); + + auto *quitBtn = new QPushButton("Quit", this); + hbox->addWidget(quitBtn, 0, Qt::AlignLeft | Qt::AlignTop); + + connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit); +} + +``` +Мы отображаем QPushButton в окне. +``` +connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit); +``` +Метод connect подключает сигнал к слоту. Когда мы нажимаем кнопку Quit, генерируется сигнал clicked. qApp — это глобальный указатель на объект приложения. Он определен в заголовочном файле . Метод quit вызывается, когда испускается сигнал щелчка. + +main.cpp +``` +#include +#include "click.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Click window; + + window.resize(250, 150); + window.setWindowTitle("Click"); + window.show(); + + return app.exec(); +} +``` +Это основной файл. + +![Click](click.png) + +В следующем примере мы реагируем на нажатие клавиши. +keypress.h +``` +#pragma once + +#include + +class KeyPress : public QWidget { + + public: + KeyPress(QWidget *parent = 0); + + protected: + void keyPressEvent(QKeyEvent * e); +}; +``` + +keypress.cpp +``` +#include +#include +#include "keypress.h" + +KeyPress::KeyPress(QWidget *parent) + : QWidget(parent) +{ } + +void KeyPress::keyPressEvent(QKeyEvent *event) { + + if (event->key() == Qt::Key_Escape) { + qApp->quit(); + } +} +``` +Приложение завршается, если мы нажимаем Esc. +``` +void KeyPress::keyPressEvent(QKeyEvent *e) { + + if (e->key() == Qt::Key_Escape) { + qApp->quit(); + } +} +``` +Один из способов работы с событиями в Qt5 — переопределить обработчик событий. QKeyEvent — это объект события, который содержит информацию о том, что произошло. В нашем случае мы используем объект события, чтобы определить, какая клавиша была фактически нажата. +main.cpp +``` +#include +#include "keypress.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + KeyPress window; + + window.resize(250, 150); + window.setWindowTitle("Key press"); + window.show(); + + return app.exec(); +} +``` + +## QMoveEvent + +Класс QMoveEvent содержит параметры событий для событий перемещения. События перемещения отправляются виджетам, которые были перемещены. +move.h +``` +#pragma once + +#include + +class Move : public QWidget { + + Q_OBJECT + + public: + Move(QWidget *parent = 0); + + protected: + void moveEvent(QMoveEvent *e); +}; +``` + +move.cpp +``` +#include +#include "move.h" + +Move::Move(QWidget *parent) + : QWidget(parent) +{ } + +void Move::moveEvent(QMoveEvent *e) { + + int x = e->pos().x(); + int y = e->pos().y(); + + QString text = QString::number(x) + "," + QString::number(y); + + setWindowTitle(text); +} +``` +В нашем примере программирования кода мы реагируем на событие перемещения. Мы определяем текущие координаты x, y левого верхнего угла клиентской области окна и устанавливаем эти значения в заголовок окна. +``` +int x = e->pos().x(); +int y = e->pos().y(); +``` +Мы используем объект QMoveEvent для определения значений x, y. +``` +QString text = QString::число(x) + "," + QString::число(y); +``` +Мы конвертируем целочисленные значения в строки. +``` +setWindowTitle(text); +``` +Метод setWindowTitle задает текст заголовка окна. +main.cpp +``` +#include +#include "move.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Move window; + + window.resize(250, 150); + window.setWindowTitle("Move"); + window.show(); + + return app.exec(); +} +``` +![QMoveEvent](moveevent.png) + +## Отключение сигнала + +Сигнал может быть отключен от слота. Следующий пример показывает, как мы можем это сделать. +disconnect.h +``` +#pragma once + +#include +#include + +class Disconnect : public QWidget { + + Q_OBJECT + + public: + Disconnect(QWidget *parent = 0); + + private slots: + void onClick(); + void onCheck(int); + + private: + QPushButton *clickBtn; +}; +``` +В заголовочном файле мы объявили два слота. Слоты — это не ключевое слово C++, это расширение Qt5. Эти расширения обрабатываются препроцессором до компиляции кода. Когда мы используем сигналы и слоты в наших классах, мы должны предоставить макрос Q_OBJECT в начале определения класса. В противном случае препроцессор будет жаловаться. +disconnect.cpp +``` +#include +#include +#include +#include "disconnect.h" + +Disconnect::Disconnect(QWidget *parent) + : QWidget(parent) { + + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->setSpacing(5); + + clickBtn = new QPushButton("Click", this); + hbox->addWidget(clickBtn, 0, Qt::AlignLeft | Qt::AlignTop); + + QCheckBox *cb = new QCheckBox("Connect", this); + cb->setCheckState(Qt::Checked); + hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop); + + connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick); + connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck); +} + +void Disconnect::onClick() { + + QTextStream out(stdout); + out << "Button clicked" << endl; +} + +void Disconnect::onCheck(int state) { + + if (state == Qt::Checked) { + connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick); + } else { + disconnect(clickBtn, &QPushButton::clicked, this, + &Disconnect::onClick); + } +} +``` + +В нашем примере у нас есть кнопка и флажок. Флажок подключает и отключает слот от сигнала нажатия кнопок. Этот пример должен быть выполнен из командной строки. +``` +connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick); +connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck); +``` +Здесь мы подключаем сигналы к нашим пользовательским слотам. +``` +void Disconnect::onClick() { + + QTextStream out(stdout); + out << "Button clicked" << endl; +} +``` +Если мы нажмем кнопку Click, мы отправим текст «Кнопка нажата» в окно терминала. +``` +void Disconnect::onCheck(int state) { + + if (state == Qt::Checked) { + connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick); + } else { + disconnect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick); + } +} +``` +Внутри слота onCheck мы подключаем или отключаем слот onClick от кнопки Click в зависимости от полученного состояния. +main.cpp +``` +#include +#include "disconnect.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Disconnect window; + + window.resize(250, 150); + window.setWindowTitle("Disconnect"); + window.show(); + + return app.exec(); +} + +``` + +## Таймер + +Таймер используется для выполнения одиночных или повторяющихся задач. Хорошим примером использования таймера являются часы; каждую секунду мы должны обновлять нашу метку, отображающую текущее время. +timer.h +``` +#pragma once + +#include +#include + +class Timer : public QWidget { + + public: + Timer(QWidget *parent = 0); + + protected: + void timerEvent(QTimerEvent *e); + + private: + QLabel *label; +}; +``` +timer.cpp +``` +#include "timer.h" +#include +#include + +Timer::Timer(QWidget *parent) + : QWidget(parent) { + + QHBoxLayout *hbox = new QHBoxLayout(this); + hbox->setSpacing(5); + + label = new QLabel("", this); + hbox->addWidget(label, 0, Qt::AlignLeft | Qt::AlignTop); + + QTime qtime = QTime::currentTime(); + QString stime = qtime.toString(); + label->setText(stime); + + startTimer(1000); +} + +void Timer::timerEvent(QTimerEvent *e) { + + Q_UNUSED(e); + + QTime qtime = QTime::currentTime(); + QString stime = qtime.toString(); + label->setText(stime); +} +``` +В нашем примере, мы отобразим на экране местное время. +``` +label = new QLabel("", this); +``` +Для отображения времени мы используем метку виджета. +``` +QTime qtime = QTime::currentTime(); +QString stime = qtime.toString(); +label->setText(stime); +``` +Здесь мы определяем текущее местное время. Мы устанавливаем его в метку виджета. +``` +startTimer(1000); +``` +Мы запускаем таймер. Каждые 1000 мс генерируется событие таймера. +``` +void Timer::timerEvent(QTimerEvent *e) { + + Q_UNUSED(e); + + QTime qtime = QTime::currentTime(); + QString stime = qtime.toString(); + label->setText(stime); +} +``` +To work with timer events, we must reimplement the timerEvent method. +main.cpp +``` +#include +#include "timer.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Timer window; + + window.resize(250, 150); + window.setWindowTitle("Timer"); + window.show(); + + return app.exec(); +} +``` +![Timer](timer.png) + +Эта глава была посвящена событиям и сигналам в Qt5. + diff --git a/qt5/Events_and_signals/click.png b/qt5/Events_and_signals/click.png new file mode 100644 index 0000000000000000000000000000000000000000..acfcb2d076575c6faf0e7e28c1f4bbe9fc29ec5b GIT binary patch literal 4340 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 eZhMEPfxn)1UT9wr4qZ(>HEkVTtw-*y9300# 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 literal 0 HcmV?d00001 diff --git a/qt5/Events_and_signals/timer.png b/qt5/Events_and_signals/timer.png new file mode 100644 index 0000000000000000000000000000000000000000..183d5c5a675caeca7a8e06bc0cd7089f6c0bff5a GIT binary patch literal 3528 zcmeHK`8O197awKIE+JvalD^p$Ef{MeQDoouF_oA3qBP0Aj4U%5 zeG$f3#z?j?Vk|Sf)1UDE{J!^`&%Ni~bMNPK&vTyhob#mIvA)62bA|^10PtIwo7%D> zgN1r-PL@~JJRZsl>`-G1J8qUmbNfAIrOCJf2i+6 zNGJ>v5)5#J1p9@+WlbJe9Cp*&8vqt8|J-YH)x$aS`5r+qBkNeMtS|ml+V;cZc8}OAsWi z_L}c?9v$h6WLjSEyXwc~a>5mdp{o8$YbBE>R4>_>lHbi8fR3*@ls#tuJAVvN z8zSPkDu=$B>n{xV{oF>3jAGFp{&P87$KX*S+{#o9b*s8qs^z(?VV7WWb36$ahg8u` zS=in<Tsuu~Lp!rO4C>J%N3MF*Wz~{@wJPu9)Tdd2LW1ufu;j+(Ub8oc^C>~x^5_fnlm*?m zoshKk8*)Tdz}pe=p6*^@mV}B3;ynt3zSJPf1ozE|lGeiZcApIZQI#%|e>KoUg#**e zVH7oI%lV-XX}drNkS%Va6oWXFwA%>z6`sq58`^>(N>UfDG52YD97v#Ys#iqDZ*A?G z=xq&tz&DYanLFK$b->wrUba-Abxx1z+^SIxDK?M!F|1Euc=0Dk^GV30m09#~>sk<5q)`$pcG%%Dseb)I-Us3PB zH3-DHg&X9}WEqlxp^ZmctBkhoX3w>vc&)BZbM%f<5EV50MIhJ!{6N=h;b6Iz=k(Bk zoZS_v%55^1{!;=W?Valwlbu<|5MNaHx7n-Kt%?e`_#C?KGczHCCB+oVyq~sQ)?Z|J z`RL4jGV|Cco&!#y1at9a$hK5nv+JP+_naH%t#YON%W3%`qfPfD*N!w$A*ZAl4g_0! z$84S*-dv6?nHk@TilfFEXT7vx?H1eewrIrUA=?!v@yhv>@Yg&8+=Ay(tq}gQy1sBw08H4Bu_^n1nmn8`C3*s?3`6(tUo{j1BuE^=bHLY_+ zwf+IUD2)6<3~)bE`}UX^t)o@s{E36z#~Pzc#D3KXc~^J|+3u2~V27h7$wG*K%Fh&3 zg1#tcROT&7viMWKxJSTII}Ml4#%SfNj>qMS%ATH$cPy_E2YDGiJaW~eMN7WlvEiv} zc|PTO hv8kOtUKJ>oY&BIyW zu7mrEt!_|p!o1qziCGi`htlWoePv5z-wy?%br6HU^|zF5(E=%@wmaAQT|aA0My7X!;0#^#5cY+|Z6p{N=~&Cp|j zt=t-Yctz~~YoB*?8KtbtW#gKoo)zh0v;lOp5I=q6w*OSNfNARf$LD`g93F8f#|M6Y zrrQIod->M8lww~cZ3Nl=LUr{Hkx`G*?x>(y4+mG1-JAK4kWDUU;|9?tM+#zvVNbzT94$hPy-axUjQ4h&|Z z14Eu>+Gr)df)|lT;1-{n*u?x^oQ0aIrL?;DWmFdw26jWzMTYv@W-ad*zX*sQnFh7~ z3NWuf8$%WI;);Htr$Xw4OGo3`NZoW?$&Cok5RQ1K2q6;B{K<}O71$kh8p_|izI176 zP8#3U$@zfW^iiyP36f%Idg!zK?Tm23d4zBRJ6kT%4PHSvF;#0sw+fH(sr#JdQ1=n~ zFOhNBYU1x08=vkGS>Sm%@@8I~RH?#~Q8rf`&WPP!Sq04)eXdW-hptm{NAig?P7TT1 z3>|^iLpk-YABq#K{xRNDymf$c3rI^XrvD;;{E9DFRG#?U{(Lp-;d)&j?rq=_{Nb6y zlSrw65$L7Wx>_6AtWPzWu=61b?d zqU{j$R*_@&a^r#l5j}jCcY$5(*4gubjsT$aRQbeNw`sh61iO@kZO zSPPey^vr8U!%+g`hr{Ci`17-0>e5Qzze(a0Hy^WwD)jY8VlzdgdtOV3%n{dqpy{v9 z`sA{tfjz@?y!TBu1cdaNP`+Ir(?oW+^ybFJ&Q9-f{YxCv#VSSqmMt6)PFQKb74~}S zbnr#2i#!<|e#qU)mgrXmGM;9OPJay+ZqglZF2_8XdJ*O#lPsUqvJ2hyKn!bt{k(sr z0*RDKi~!u9Kdw?TG4%+%{-AEoK+K-j#?{c^={wWhC(?NAdwAN8iGo{UX#K@qLyh<~ zSOzUFlx=}l@N;K9tj*!&V5Vw_4f?`&u1ilh)hwy8^W2ivu{YMp8?=Nhr^)YxT5;8d zPESzclnWmB`@*{t-0Yl;m2W-Kf5Gr++AB-KCO{HzF*_+7&(@(v?rV9|0Ny(ZoXNmH zu}J7o@y{+@Qs@aqfe_7^L3rjfgQX!#vZsv6B=16NE!Z2IbSGkzpZtIsm;DXG_acJ0 zC6&Z)Zc8HUm7c~ei!@=M^$Wm)C8hPVxsW;{)T_)LEiv@z@wJymJ$k4J+?MOlgZWWL zX&4WE#@TGhBEww4JW_2~_np%vq_Dki!6u=0DFGT^P|O7hgi=rPuSP<3HyQWO^F^Vh zy47AaT}p_l8~;8LmQ`H1BYfz#jI}ucfk0JBaHmGfm4%Rh&RSys_