From 19608edbc520c751e096d97bc1325a8c372a4ee9 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Wed, 25 May 2022 15:48:16 +0400 Subject: [PATCH 1/6] 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/6] 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_ Date: Wed, 8 Jun 2022 13:20:53 +0400 Subject: [PATCH 3/6] feat: add translate for events and signals --- events_and_signals.md | 436 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+) create mode 100644 events_and_signals.md diff --git a/events_and_signals.md b/events_and_signals.md new file mode 100644 index 0000000..fc7b5b5 --- /dev/null +++ b/events_and_signals.md @@ -0,0 +1,436 @@ +# События и сигналы в Qt5 + +В этой части руководства по программированию Qt5 C++ мы говорим о событиях и сигналах. + +События являются важной частью любой программы с графическим интерфейсом. Все приложения с графическим интерфейсом управляются событиями. Приложение реагирует на различные типы событий, которые генерируются в течение его жизни. События генерируются в основном пользователем приложения. Но они могут быть созданы и другими способами, например. Интернет-соединение, оконный менеджер или таймер. В событийной модели есть три участника: + +- источник события +- объект события +- цель события + +Источником события является объект, состояние которого изменяется. Он генерирует События. Объект события (Event) инкапсулирует изменения состояния в источнике события. Цель события — это объект, который необходимо уведомить. Объект-источник события делегирует задачу обработки события цели события. + +Когда мы вызываем метод exec приложения, приложение входит в основной цикл. Основной цикл извлекает события и отправляет их объектам. Qt имеет уникальный механизм сигналов и слотов. Этот механизм сигналов и слотов является расширением языка программирования C++. + +Сигналы и слоты используются для связи между объектами. Сигнал испускается, когда происходит определенное событие. Слот — это обычный метод C++; он вызывается, когда излучается связанный с ним сигнал. + +## Пример клика Qt5 + +В первом примере показан очень простой пример обработки событий. У нас есть одна кнопка. Нажав на кнопку, мы завершаем работу приложения. + +click.h +``` +pragma once + +#include + +class Click : public QWidget { + + public: + Click(QWidget *parent = nullptr); +}; +``` + +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 *eevent) { + + 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::number(x) + "," + QString::number(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. + From 25bb89a73ee5c040bdc9c36b5bba877ab54adc58 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Wed, 8 Jun 2022 13:24:04 +0400 Subject: [PATCH 4/6] fix: refactoring folder with translates --- qt5/Events_and_signals/Events and signals.md | 431 ---------- qt5/Events_and_signals/click.png | Bin 4340 -> 0 bytes qt5/Events_and_signals/moveevent.png | Bin 3435 -> 0 bytes qt5/Events_and_signals/timer.png | Bin 3528 -> 0 bytes qt5/date_and_time.md | 835 ------------------- 5 files changed, 1266 deletions(-) delete mode 100644 qt5/Events_and_signals/Events and signals.md delete mode 100644 qt5/Events_and_signals/click.png delete mode 100644 qt5/Events_and_signals/moveevent.png delete mode 100644 qt5/Events_and_signals/timer.png delete mode 100644 qt5/date_and_time.md diff --git a/qt5/Events_and_signals/Events and signals.md b/qt5/Events_and_signals/Events and signals.md deleted file mode 100644 index ec1cea9..0000000 --- a/qt5/Events_and_signals/Events and signals.md +++ /dev/null @@ -1,431 +0,0 @@ -# События и сигналы в 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 deleted file mode 100644 index acfcb2d076575c6faf0e7e28c1f4bbe9fc29ec5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4340 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 eZhMEPfxn)1UT9wr4qZ(>HEkVTtw-*y9300# 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 diff --git a/qt5/Events_and_signals/timer.png b/qt5/Events_and_signals/timer.png deleted file mode 100644 index 183d5c5a675caeca7a8e06bc0cd7089f6c0bff5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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_ -#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 40b9f14f0c4b0826c117c05d5e8d4f5e735439f6 Mon Sep 17 00:00:00 2001 From: Anton Protopopov Date: Thu, 9 Jun 2022 17:41:30 +0400 Subject: [PATCH 5/6] feat: add translation for layout management article --- layout_management/absolute1.png | Bin 0 -> 3581 bytes layout_management/buttons.png | Bin 0 -> 5808 bytes layout_management/calculator.png | Bin 0 -> 7971 bytes layout_management/layoutmanagement.md | 633 ++++++++++++++++++++++++++ layout_management/nesting.png | Bin 0 -> 15708 bytes layout_management/review.png | Bin 0 -> 9921 bytes layout_management/simpleform.png | Bin 0 -> 5458 bytes layout_management/verticalbox.png | Bin 0 -> 21693 bytes 8 files changed, 633 insertions(+) create mode 100644 layout_management/absolute1.png create mode 100644 layout_management/buttons.png create mode 100644 layout_management/calculator.png create mode 100644 layout_management/layoutmanagement.md create mode 100644 layout_management/nesting.png create mode 100644 layout_management/review.png create mode 100644 layout_management/simpleform.png create mode 100644 layout_management/verticalbox.png diff --git a/layout_management/absolute1.png b/layout_management/absolute1.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1a71b9828c549a36079e588edf72ecab650197 GIT binary patch literal 3581 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 literal 0 HcmV?d00001 diff --git a/layout_management/buttons.png b/layout_management/buttons.png new file mode 100644 index 0000000000000000000000000000000000000000..77105067c1ed80a66b44e8776c535cd6f63c3210 GIT binary patch literal 5808 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 +#include +#include + +class Absolute : public QWidget { + + public: + Absolute(QWidget *parent = nullptr); +}; + +Absolute::Absolute(QWidget *parent) + : QWidget(parent) { + + auto *ledit = new QTextEdit(this); + ledit->setGeometry(5, 5, 200, 150); +} + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Absolute window; + + window.setWindowTitle("Absolute"); + window.show(); + + return app.exec(); +} +``` +Метод setGeometry используется для позиционирования виджета в окне в абсолютных координатах. +``` +auto *edit = new QTextEdit(this); +ledit->setGeometry(5, 5, 200, 150); +``` +Мы создаем виджет QTextEdit и позиционируем его вручную. Метод setGeometry делает две вещи: позиционирует виджет в абсолютных координатах и изменяет размер виджета. +![pic 1](absolute1.png) + +## Qt5 QVBoxLayout + +Класс QVBoxLayout выстраивает виджеты вертикально. Виджеты добавляются в макет с помощью метода addWidget. + +vertical_box.h +``` +#pragma once + +#include + +class VerticalBox : public QWidget { + + public: + VerticalBox(QWidget *parent = nullptr); +}; +``` + +vertical_box.cpp +``` +#include +#include +#include "vertical_box.h" + +VerticalBox::VerticalBox(QWidget *parent) + : QWidget(parent) { + + auto *vbox = new QVBoxLayout(this); + vbox->setSpacing(1); + + auto *settings = new QPushButton("Settings", this); + settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto *accounts = new QPushButton("Accounts", this); + accounts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto *loans = new QPushButton("Loans", this); + loans->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto *cash = new QPushButton("Cash", this); + cash->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + auto *debts = new QPushButton("Debts", this); + debts->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + vbox->addWidget(settings); + vbox->addWidget(accounts); + vbox->addWidget(loans); + vbox->addWidget(cash); + vbox->addWidget(debts); + + setLayout(vbox); +} +``` +В нашем примере у нас есть один менеджер вертикальной компоновки. В него вставляем пять кнопок. Мы делаем все кнопки расширяемыми в обе стороны. +``` +auto *vbox = new QVBoxLayout(this); +vbox->setSpacing(1); +``` +Мы создаем QVBoxLayout и устанавливаем интервал в 1 пиксель между дочерними виджетами. +``` +auto *settings = new QPushButton("Settings", this); +settings->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +``` +Мы создаем кнопку и устанавливаем для нее политику размера. Дочерние виджеты управляются менеджером компоновки. По умолчанию кнопка расширяется по горизонтали и имеет фиксированный размер по вертикали. Если мы хотим изменить его, мы устанавливаем новую политику размера. В нашем случае кнопка расширяется в обе стороны. +``` +vbox->addWidget(settings); +vbox->addWidget(accounts); +``` +Мы добавляем дочерние виджеты в менеджер компоновки с помощью метода addWidget. +setLayout(vbox); + +Мы устанавливаем менеджер QVBoxLayout для окна. + +main.cpp +``` +#include +#include "vertical_box.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + VerticalBox window; + + window.resize(240, 230); + window.setWindowTitle("VerticalBox"); + window.show(); + + return app.exec(); +} +``` + +![pic 2](verticalbox.png) + +## Кнопки + +В следующем примере мы отображаем две кнопки в клиентской области окна. Они будут расположены в правом нижнем углу окна. + +buttons.h +``` +#pragma once + +#include +#include + +class Buttons : public QWidget { + + public: + Buttons(QWidget *parent = nullptr); + + private: + QPushButton *okBtn; + QPushButton *applyBtn; +}; +``` + +buttons.cpp +``` +#include +#include +#include "buttons.h" + +Buttons::Buttons(QWidget *parent) + : QWidget(parent) { + + auto *vbox = new QVBoxLayout(this); + auto *hbox = new QHBoxLayout(); + + okBtn = new QPushButton("OK", this); + applyBtn = new QPushButton("Apply", this); + + hbox->addWidget(okBtn, 1, Qt::AlignRight); + hbox->addWidget(applyBtn, 0); + + vbox->addStretch(1); + vbox->addLayout(hbox); +} +``` +Скажем, мы хотели иметь две кнопки в правом нижнем углу окна. +``` +auto *vbox = new QVBoxLayout(this); +auto *hbox = new QHBoxLayout(); +``` +Мы создаем два менеджера размещения блоков: один вертикальный и один горизонтальный менеджер размещения блоков. +``` +okBtn = new QPushButton("OK", this); +applyBtn = new QPushButton("Apply", this); +``` +Создаем две кнопки. +``` +hbox->addWidget(okBtn, 1, Qt::AlignRight); +hbox->addWidget(applyBtn, 0); +``` +Кнопки размещены внутри менеджера горизонтальной компоновки. с помощью метода addWidget. Эти кнопки выровнены по правому краю. Первый параметр — это дочерний виджет. Второй параметр — коэффициент растяжения, а последний параметр — выравнивание. Установив коэффициент растяжения на 1 для кнопки OK, мы даем ей пространство от левой до правой стороны окна. Виджет не расширяется на все отведенное ему пространство. Наконец, константа Qt::AlignRight выравнивает виджет справа от выделенного пространства. +``` +vbox->addStretch(1); +vbox->addLayout(hbox); +``` +Мы помещаем пустое расширяемое пространство в вертикальное поле, вызывая метод addStretch. Затем мы добавляем горизонтальный макет блока к вертикальному макету блока. + +main.cpp +``` +#include +#include "buttons.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Buttons window; + + window.resize(290, 170); + window.setWindowTitle("Buttons"); + window.show(); + + return app.exec(); +} +``` +![pic 3](buttons.png) + +## Вложенные макеты Qt5 + +Идея следующего примера состоит в том, чтобы показать, что менеджеры компоновки можно комбинировать. Комбинируя даже простые макеты, мы можем создавать сложные диалоги или окна. Для вложения макетов мы используем метод addLayout. + +nesting.h +``` +#pragma once + +#include + +class Layouts : public QWidget { + + public: + Layouts(QWidget *parent = nullptr); +}; +``` + +nesting.cpp +``` +#include +#include +#include +#include "nesting.h" + +Layouts::Layouts(QWidget *parent) + : QWidget(parent) { + + auto *vbox = new QVBoxLayout(); + auto *hbox = new QHBoxLayout(this); + + auto *lw = new QListWidget(this); + lw->addItem("The Omen"); + lw->addItem("The Exorcist"); + lw->addItem("Notes on a scandal"); + lw->addItem("Fargo"); + lw->addItem("Capote"); + + auto *add = new QPushButton("Add", this); + auto *rename = new QPushButton("Rename", this); + auto *remove = new QPushButton("Remove", this); + auto *removeall = new QPushButton("Remove All", this); + + vbox->setSpacing(3); + vbox->addStretch(1); + vbox->addWidget(add); + vbox->addWidget(rename); + vbox->addWidget(remove); + vbox->addWidget(removeall); + vbox->addStretch(1); + + hbox->addWidget(lw); + hbox->addSpacing(15); + hbox->addLayout(vbox); + + setLayout(hbox); +} +``` + +В примере мы создаем окно, состоящее из четырех кнопок и одного виджета списка. Кнопки сгруппированы в вертикальный столбец и размещены справа от виджета списка. Если мы изменим размер окна, размер виджета списка также изменится. +``` +auto *vbox = new QVBoxLayout(); +``` +QVBoxLayout — это столбец для кнопок. +``` +auto *hbox = new QHBoxLayout(this); +``` +QHBoxLayout — это базовый макет для виджетов. +``` +auto *lw = new QListWidget(this); +lw->addItem("The Omen"); +lw->addItem("The Exorcist"); +lw->addItem("Notes on a scandal"); +lw->addItem("Fargo"); +lw->addItem("Capote"); +``` +QListWidget создан. +``` +auto *add = new QPushButton("Add", this); +auto *rename = new QPushButton("Rename", this); +auto *remove = new QPushButton("Remove", this); +auto *removeall = new QPushButton("Remove All", this); +``` +Здесь мы создаем наши четыре кнопки. +``` +vbox->setSpacing(3); +vbox->addStretch(1); +vbox->addWidget(add); +vbox->addWidget(rename); +vbox->addWidget(remove); +vbox->addWidget(removeall); +vbox->addStretch(1); +``` +Создан вертикальный блок с четырьмя кнопками. Мы оставляем немного места между нашими кнопками. Обратите внимание, что мы добавляем коэффициент растяжения вверху и внизу вертикального прямоугольника. Таким образом, кнопки располагаются вертикально по центру. +``` +hbox->addWidget(lw); +hbox->addSpacing(15); +hbox->addLayout(vbox); +``` +Виджет списка и вертикальный блок кнопок помещаются в макет горизонтального блока. Метод addLayout используется для добавления макета в другой макет. +``` +setLayout(hbox); +``` +Мы устанавливаем базовый макет для родительского окна. + +main.cpp +``` +#include +#include "nesting.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Layouts window; + + window.setWindowTitle("Layouts"); + window.show(); + + return app.exec(); +} +``` + +![pic 4](nesting.png) + +##Qt5 FormLayout + +QFormLayout — это простой менеджер компоновки, который управляет формами виджетов ввода и связанными с ними метками. Он размещает своих дочерних элементов в виде двух столбцов. Левый столбец состоит из меток, а правый столбец состоит из виджетов ввода, таких как QLineEdit или QSpinBox. + +form.h +``` +#pragma once + +#include + +class FormEx : public QWidget { + + public: + FormEx(QWidget *parent = nullptr); +}; +``` + +form.cpp +``` +#include +#include +#include +#include "form.h" + +FormEx::FormEx(QWidget *parent) + : QWidget(parent) { + + auto *nameEdit = new QLineEdit(this); + auto *addrEdit = new QLineEdit(this); + auto *occpEdit = new QLineEdit(this); + + auto *formLayout = new QFormLayout; + formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter); + formLayout->addRow("Name:", nameEdit); + formLayout->addRow("Email:", addrEdit); + formLayout->addRow("Age:", occpEdit); + + setLayout(formLayout); +} +``` +В примере создается форма, состоящая из трех меток и трех строк редактирования. +``` +auto *formLayout = new QFormLayout; +``` +Создается экземпляр QFormLayout. +formLayout->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter); + +С помощью метода setLabelAlignment мы устанавливаем выравнивание виджетов меток. +``` +formLayout->addRow("Name:", nameEdit); +``` +Метод addRow добавляет новую строку в нижнюю часть макета формы с заданной меткой и виджетом ввода. + +main.cpp +``` +#include +#include "form.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + FormEx window; + + window.setWindowTitle("Form example"); + window.show(); + + return app.exec(); +} +``` +![pic 5](simpleform.png) + +## Qt5 QGridLayout + +QGridLayout помещает свои виджеты в сетку. Это мощный менеджер компоновки. + +calculator.h +``` +#pragma once + +#include + +class Calculator : public QWidget { + + public: + Calculator(QWidget *parent = nullptr); +}; +``` + +calculator.cpp +``` +#include +#include +#include "calculator.h" + +Calculator::Calculator(QWidget *parent) + : QWidget(parent) { + + auto *grid = new QGridLayout(this); + grid->setSpacing(2); + + QVector values({ "7", "8", "9", "/", + "4", "5", "6", "*", + "1", "2", "3", "-", + "0", ".", "=", "+" + }); + + int pos = 0; + + for (int i=0; i<4; i++) { + for (int j=0; j<4; j++) { + + auto *btn = new QPushButton(values[pos], this); + btn->setFixedSize(40, 40); + grid->addWidget(btn, i, j); + pos++; + } + } + + setLayout(grid); +} +``` +Создаем скелет калькулятора. +``` +auto *grid = new QGridLayout(this); +grid->setSpacing(2) +``` +Мы создаем макет сетки и устанавливаем интервал 2 пикселя между дочерними виджетами. +``` +QVector values({ "7", "8", "9", "/", + "4", "5", "6", "*", + "1", "2", "3", "-", + "0", ".", "=", "+" +}); +``` +Это символы, которые отображаются на кнопках. +``` +for (int i=0; i<4; i++) { + for (int j=0; j<4; j++) { + + auto *btn = new QPushButton(values[pos], this); + btn->setFixedSize(40, 40); + grid->addWidget(btn, i, j); + pos++; + } +} +``` +Мы размещаем шестнадцать виджетов в макете сетки. Каждая из кнопок имеет фиксированный размер. + +main.cpp +``` +#include +#include "calculator.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Calculator window; + + window.setWindowTitle("Calculator"); + window.show(); + + return app.exec(); +} +``` +![pic 6](calculator.png) + +## Обзор + +В следующем примере этой главы мы создаем более сложное окно с помощью менеджера QGridLayout. + +review.h +``` +#pragma once + +#include + +class Review : public QWidget { + + public: + Review(QWidget *parent = nullptr); +}; +``` + +review.cpp +``` +#include +#include +#include +#include +#include "review.h" + +Review::Review(QWidget *parent) + : QWidget(parent) { + + auto *grid = new QGridLayout(this); + grid->setVerticalSpacing(15); + grid->setHorizontalSpacing(10); + + auto *title = new QLabel("Title:", this); + grid->addWidget(title, 0, 0, 1, 1); + title->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + + auto *edt1 = new QLineEdit(this); + grid->addWidget(edt1, 0, 1, 1, 1); + + auto *author = new QLabel("Author:", this); + grid->addWidget(author, 1, 0, 1, 1); + author->setAlignment(Qt::AlignRight | Qt::AlignVCenter); + + auto *edt2 = new QLineEdit(this); + grid->addWidget(edt2, 1, 1, 1, 1); + + auto *review = new QLabel("Review:", this); + grid->addWidget(review, 2, 0, 1, 1); + review->setAlignment(Qt::AlignRight | Qt::AlignTop); + + auto *te = new QTextEdit(this); + grid->addWidget(te, 2, 1, 3, 1); + + setLayout(grid); +} +``` +Код создает окно, которое можно использовать для ввода автора, названия и рецензии на книгу. +``` +auto *grid = new QGridLayout(this); +``` +Менеджер QGridLayout создан. +``` +grid->setVerticalSpacing(15); +grid->setHorizontalSpacing(10); +``` +Мы добавляем вертикальный интервал с помощью метода setVerticalSpacing и горизонтальный интервал с помощью метода setHorizontalSpacing. +``` +auto *title = new QLabel("Title", this); +grid->addWidget(title, 0, 0, 1, 1); +``` +Эти строки кода создают виджет метки и помещают его в макет сетки. Метод addWidget имеет пять параметров. Первый параметр — это дочерний виджет, в нашем случае метка. Следующие два параметра — это строка и столбец в сетке, где мы размещаем метку. Наконец, последними параметрами являются rowspan и colspan. Эти параметры определяют, сколько строк будет охватывать текущий виджет. В нашем случае метка будет охватывать только один столбец и одну строку. +``` +title->setAlignment(Qt::AlignRight | Qt::AlignVCenter); +``` +Метод setAlignment выравнивает метку заголовка в своей ячейке. По горизонтали он выровнен по правому краю. По вертикали он центрирован. +``` +auto *te = new QTextEdit(this); +grid->addWidget(te, 2, 1, 3, 1); +``` +Виджет QTextEdit помещается в третью строку и второй столбец; он охватывает три строки и один столбец. + +main.cpp +``` +#include +#include "review.h" + +int main(int argc, char *argv[]) { + + QApplication app(argc, argv); + + Review window; + + window.setWindowTitle("Review"); + window.show(); + + return app.exec(); +} +``` +![pic 7](review.png) + +Эта часть руководства по Qt5 была посвящена управлению компоновкой. + diff --git a/layout_management/nesting.png b/layout_management/nesting.png new file mode 100644 index 0000000000000000000000000000000000000000..282069ba93d351ec4989abc6a93c011f62c4ee74 GIT binary patch literal 15708 zcmdUWWmJ`I*DV4ff+#ATV$cl|Qi6m^iFB)UgGi@JNs35!$ELeW5NT=Hl$1z!*IC== z9p8B0bG~n!aekg>j7Mefn|)vRb*;7LTyw7d>4lsW9u64}8X6kjv!~)O(aIhYjzAfCxMk&FM1xCn^%=GR=1uGXY<17afy|89qBm6sFB!hTx~#9` ztspA;;_>2@>q&Gp6 z&upTPv1tT9wCmrUCWD`~G^onvKfipnm#Ma8Ydh?PFQz4Xo^dNi&3_A>Ua=OjmNXy# zJ9K?a328cFziPm<)zQQ*L!+=4rii+~c-1V%DG|20TF!>TmyZtCF2k0Oa>ic0e8^!I zP2#3UN6(LO3)>5S*1s@ z`@)l&1B{$$Dx~IwMA+oLgUcjaSBwPY+xvvnw!YCVW4WF(d*ZElcYoDC8OV~RuI-8p zbLTOjvww}Z6rwAxH+MonGr??hVZ^#NvRi%AXFS)SmENd=>uv@f`N3+MAU9beZ7AAT z;(Jz_Z z6S*yY)2dgq?aP--j)WQgzkT$D$uwF9+sDU-^Ld&ci!$*0DqsDEP@q|8IBkw2rk+P` z2+y4l=BwQ&@tZEvvy!#0t{WH)m#a|K>Uu3ML;m|TTja*|_QfXRhP2fRi=ge0?ft;l z?~HE-%07F2mK{fyh=Ue)K2kE4tE9nXwr5oG><+#pI;pLLW^?aZV0Te|`34&!{eva$ zZC3qPVYZ{s8PRUjx}UT$-+X-9bc88UXe0k9lXH9N=iMlWj2o@I8`yA*&HdeExJ6fX zpliLHbejNub2@jt@J%I+yjOX-20RNMDOo+3^Ko5tS$b?#mM09hT-+CO9bELCeBu(% zE<5_p45ZKrzbDF#cA@X?kmPXEv+O5qAgceGnP|8<=fH84$#(eLjXc6k%xT%mD)~@X z{_%LgS1P$yg0V~6@`~yjmvovOc{hTrKC_iKfBPDLLTZ+d*EJP+UUn=sH=RM)@1mi_ zBI$7UP>2OBs?L?+#!Al_?(oj=?TVk-cJzsY0=GPW{6q^ri|ZVXtWV+06%f{`XI*Gx z$EWuk()d&s;c!S)a#@1I)DAx(_m3Kx89LT>WKF?L-sLtW&F9H~R1;1UYe*-1B0FlY zO*xy97o5GxSi#$><*vPaGvlqC#q{@k8%FHr9TqZG-_b|zmmn@eWTKq>eRVImEE?3? z3gyq#t7e5+-AfZ^y)TKFE~61`(`{XNa9J|yMX#R3wtG4e$F~_fGd}b zGx=4S%1Z?W9Yn)(v-DG=Th+Dn^K~I|ilfzZiq*~+2h@qAKEafYe{Tc^L#as`GuWT}K+V3{!BYtWX6&GZSKZpbSL z+8C+wtexkjHwt*Al^bp@^@t>{U-x`D5ryw=Fv5m|aooaDlF&vp6_eP%!+_qg zv%{x_FYf)a?6@EEE9GGV!$$Z^^Bz5;7fe&@(^0P&8R#2!o$Jsesa%*k+ZlGgxvEb_ zc+q7o1y8EWCmyRr9N^0O%Wthu`}PTPe-0x(Lem<6G`J8Byh4a-xs8QQfFX8Pgf}0AuuFXq#C`+HXzK{;f~9<;C*Vl zrE)jp!DbIdA)(=RQ_TrK{#&7`TUWer1D7|=mX}g9d6Y#>%R4w-w?j&{H@+E@4o4}H z9-W%ZILpvFx*VrdJz=`A=h7p}Z5!sJD8XIBgq7=8D?L;ir$e`5qn4p1ZPy^#w3I*U zJyCbgy;mY|q@|&n&^bb9aevR>$n+xKHC!+GNgMWctKJkhG0cVpz7EZrdrtYP?8zMr z>-T9}AVH{<5Z(=^kk zS`YKNamX3iy7a|2c!H-yZ`2fwFq67=7qdp3fmWr}M;p#BJyUZO|L`pph*$zVLqH7d>h`4=z z7AyTH;cH7>C=or|yh!5e!s9SwvgnX)r0>$TQ(J;LEVXAx`9HknvS_pD-<(yD23D^a zmhT=}*s0S@=br^fUwQNz7w^lfJ8?Ok@g8oOGn7BSvN>2?c{y517mqW9YmnZEfjh#L zrb^DU`m7CMK%Hqa7A?ubpB9HO*ErKRyv&wPp((*YxR9>K#8jxP@~UL)#aHPNByAXJ z*jQletat196*g*J<|%ij7}u=A_6z#0*y$2TxVp@-o;5DA(sA%0P-IYT@YxUJ_>_)zxF zos`}Fsu)^)e9~*9g$WlCU*aSkFGoeO>k)Y13HP?e_J*c&&sMjv?wWn=X=$K*WmQAM z{8HjR8Jd|oNBDyy$A>umly6dsOYzwnUPbEAnyrWHor=FO;YyBjD?D_ZnVZCJ)%f%V zf!XTw<|MCYuj275PM6okj>%EAS&f0pA3R@hNzIPz4d<+!R{xqV3ouQ@c1245O64D{ zn0t{kVjaVAxeXsb_qklS`;cvPk@)qy>~{nD6MOnOu9=fA9=c!j&R_8w$YFc&MY=q@ zND$8t>)Y&#mD&$Yvdb#C*B{y(Q;DW`i$5T0L^sr3+@N6^Jb$1-lTT!;==#Cq%~H-> zDamA*hp>~-Xvg8!pV#N-O{DIoQ~?#3=rhUsa?fXIx}u&q+st&)th?O3teK8ZYt?m$ zW$RO5>$s{BrVfpu7hEXX74^~O7xl!qNz$9M4z0Mq!qaTmdwlW5uz8~*XXjjZ6@bHd zxS|+J^EUukG3*<3?@{b14ilZmYt#Dw^2U&JZZeBzxz;CFY#K7pmKJdbBT=nOc4Y6? z`=qGzHsDqFMP?#gmxFaX2c8zfJIYVQuxDoO<73l!`G!5d?#tnTc&^Vr0M;b7WBBs4U% z_F&3ITvD>wsF%vHD@xSeT{w(RK0k5?mPJ>+nnPn{W##JTwza>H)i^RjtgEYATg%!? z642T_ATJ_Ypi@V}{t7M8=oT5$ANP0VEfX1yURy4s|MU zea(7xfNU&}^0SNlnsxL$e0))GsqOEs=*|mK;NcFxi^s7|`%6s}+Z+N~(H|QaJU}C6 z)p`Yw5^S0V=UHvHqQVkXSjf(*Rr$iAZpbvfu<-Ne&-iWCu#z^1k};WAuU>^4>{W$O zi^xsayIm?AGe-+HrL8MnZNq_wZHI@Y4Qsd7EHUhk67i@{W#{QHF_MP`JbCu)Dnvu@ zo@Tju)A)ESm5_7gJK?n|m)$>2E*o{K7Mh}>qIvzd#Qc1^^4PuxQSg6R=!~>opWtU? zWaM){^p1XJW=1AKFnX>nL{Uxchr_g6TURuf)1PGDoQb^}Mh1pYa5$R_ zk-9HcR3zQq>r>mp@WmW&RbYLPqH^-e*RJ7o-Zidv*yx!)-{*CQO*B1GXC|6*Kd}%K z6Lb9a{)%5n$l}pr;$pHdRgUdQ-_M^fbUe=N&i4vD`f41ku<*!Qz6X)B9enY^Pif)^ z(s=tcdaPk$0i)b}>~3lZ&dhuL-9C{FCkA28;m>g6M^`cb_q3Noe-Cf){Wou9FMc$7pFVBDL-u4R$dLS&Epk88VvpmQ^ z##JX=p0TV zp?HCf+OYM>nt>ucsmT6vHD+eDLQja8NGKgs&MPd=`>X9xI)1db&%lYzCSIJr4+D#p{3OYSBm*wr*vG-&Wz$Rx<2i?BU^XwE{1KB{?IR*@zQf?>80_Cf;p>i zK6q$aE^B3h)FKHCiW!@&#JcQ8Jrrp5XZxBdDJiJ5qz(H7b*m4Sf4-A=!Pg%c5@Pf- zNfZ+k^A%_G;cNgKs=`5qNVA#yUTQI3t|5#px9FVt<~vqqM*RN$`*-UTRrMa65Dht~ zXg~`hdzjPzJ1IeOyZ&TdZ>c|h0&*aD$H36=77>xkgP_e#Yfes1icS`dQfpUL0`Isu zikOFHzjvK|ZcqmgnJ$bOCALmaC&F3vu=k2#_u+HH6Ric3nd`c4NnqWe>RL?n=mB_< zS5hMAj^!iX2sSym+i>nXxz&9*S*!XZEW}U;08{S` zk<&(qjB5i8XZz#oMQ<)cSxU;v@`E~>j1<0do#NMsu1BjrCu$ozIyznuctc*kwY5bR zQ~wmL^N@QWM?6C%KvG(o7l0oBxnXZYcWVH#)A3TK({?-ERUDi*P_GGyiFba-THT_c z=<+9IQmcN)Q0H>+J3Ued1rI|x0fQNG@z3GpNjTnMo*nPa0qW(I_d?mIT*`>``}FDc z`RP$DoLZC&EfmY|o|iD5K7IOXe|2nc@Ag%i7D75jWgHrhyC* z%T%*DAaPCX-dkMcpAW7VWK8A@>9Dz}?x?CNC@7?5WIPAb!!5IqUc_@bHH98-KPg7i zXjsC}(z2FF8}^JBd$fUk;aQzF8}{Hk7UZeP07pl|O%D%`j!tb4IvH8AfD5#q1fdm@ z^%UA?&z_l&6)!N(KgS+n@c+JpVkixB@XzW+*NwUZ5>9<=8yg#$IKEJzEdu2a9z58BEMPYsr1!Z- z+6>k58b%*5xaYuYAku~INd~eDCMwiJCP#6b+^TclyUWVj!%^^|PzEiGi3XoSs^ri`m)C#E5nOqpfOs=ql5-If<@ zYWjG^uEJunIvhyZQijzo=9^5_p?PKxNzoM6Wfpv(hTEAUXP=A`-BftFfT_*wE)AHE z7QQcNIFI2n>M1lI;{;aAq?(WUYA8oJSECFkse?NL@WTj_Adb%l9Wpvsy~Gh1Anf`L z6qkxI%g?s2->5$cR@HS2=bdu=2xYD>Pm>pNO~WAZ>sJEd)6FM5=A(_Me7!h3uq()e zjjX*mKS@hZze!BoCUU+NVtPWdAgw?^1-r*20Jk-3@` z!4J)bH}^(#cjiJwRQU7ZKFnH`pM_lZQH0R2J7yv3+Ec&jd#TQL7H5?@lY&ZY;%n1G zONfD?bv`%fs;2xs>ZbRhLPqn*U_uxNMDB^2l1b?lL^wa#W-C#`WEu zUJ;{-N*k!+zcw~{0dAs?&2V@mt7)Tuo}pay+$n@2ki7`mcl(MU@?qs+P2*f z#igVK`dQf6=(xBBHYI7UZ;%iGj=oY*x9T_)U>33M4c&4v^pMilv+4<&J zh(cz;8r5>HQApilh&^@PDXDhYzVna?`Q>(G&d7QypwBEIhyhT>YgB?HB}WZ5v`kEh z4lOj`8c@z2(MI*X82hlfAYp4~>_ zlyY-dp(QdqJZ0%;&t}TUE$5~$&UuY` z;*xA78Ml*zwOrNR8UfCf&6I)6nboJZC%FSwMX`4FTbr`hmtR@ zOvu}Y8C+HbGLn7>FeuEYMKXi6<(9_c=!4JW9`MZ6SbuPSYwVUV&)q)IIoa@P21&~=O z2i-c?*6-g@(10q4)8E43`A2}ZzkU0bqO+>1N;%&a8YmPKdi~8u0r(2Uj_RBp&WxNS zUXnALLpH8$s(|TK^5sk8k$g%tCnu*|t*S330~vkUigeIL zv;a<1ns@+GevOPQG48v|s#E&|^6p04g>C8`eWk{lVr@4IWX;92#L#CXWH^et(5lK2gGkb$V^C8=NvQ3Zk+9*gG?u68HA zA@GZ3W+QKb8!|F69Zg@H=~mmXEjyA~E9>Y`)z{a1d3n8n<>tK}?xEMEeDp2}T4`pD zQoodxyT!%DPvzwu__c*Fu3Vol=@p(^9V_`75wQ(CnXf!NA_9I-Z0C2k0)aP>Bh}xE zL=7%TEcrT-)U%)n?K9X_n~9}^wed)xdwkyo9yxB_$z&NEhaIixUMyo@mmE-2QBv9*RFuDY`}UJJZ|-)-Je-4mFF(S!-tC0bZdnP? z=CP}*Ah3Nsz^yV?0;|dyEMT|K;Np8y!TN`rGu0*}3!VC$Ticy%wya%X&%g0B;~cFz`(lJ*x4B%7yoEzImWvZx$E3T zQnz6CF4H12->`^HKwzWXVtlmPj!7|7ZUGvg%*x8B(o${$iR7dtPg>a+rFP%C7}XkW zg|Cc5Rg$YFq{=QP1@bjhas{lo`CN+r#5>I3GR?2WAMN${yQY9hAG@+&5Nu z3)x(hu>ib&YsQy)yQ1N&yT}qMBZZLj*ETAbz>S8B1b~4A=Vb<|_h&!ug|M6S--l@E zKq1y>k=_!rj0tUJq`(MzPUZayM0fH2@$Lto@|Y|LU?}@NeN27IoXY9Y;)-hLB~$51 z6;w-Y$mtfiYg@&Zk1q`8X?_X`p@V)Hn%NH@KQ4_FPy=}1O~^T!yXl;3%mo+ma4 zdS?Y4o%J88Ayh(#KojX%SRROoB(9BDto+t2sL52IDqATXLFA$Lue{aJLn_2vM1 zfRt>VT*2}W_1?P=fr|muWW?sz9cwBOK(hu6wXfT^p+N+i;M`*OAD?M_94;h}`gJP$ ziXIZ~HUu2Nnp0SJbA)zrBvUyqhAeRQn}24}3>(MBm-zgtUd?onTgw!hc3$Ea@D;p? zO>@p}$~d2NjBB{;qi6T{=lF>F6NGbo`TODekbMU6jkt$G-C4LE7WKQ^S(Z%MORbNL z8d8~1oOhxp9KB0jsHzWFMRG~NMdK&d)zmXjvP9vy$#!xfN@McQpnTB~P};;lrc;{z zP?ogYS{5+bD~?bg3{w#B+OOST+n)=>v8mG=lE>)jcL*<6sO9e5 zR^kbN_aJY1nzmJGkc{lDPd)`o96#`NJyi_50{7ar`)q8z7K^AbAGG!~} zCn(_6YYVnxJ~=)fR_#Y!391N4GtjGtpe`T^xD0w(8#P}dr_J|3Qk2pr6UF|%Cte^d zG_n;8x4+`wt!zIc~i{%aDnlbzD2itC*TC8_~J<;K9Ok zLtT(D#p*79FzAfvtFY2VX>{=pQ&$HC4cipCNEuRPU_DOr%j}+GMz$}KdNFsnp zxgYgJV^y|vlht;5y$M3^mijMOa>uGae*8F`w7&VmlKixJ6}m5=4x?JOv0?+6Se_tg zrGTS-v+WgfNH1pds`Ll?fsKos3Zj~F!f63kU8snM{8H62koNiCzlXEO&k1ocml;wZW5t0>+2Hwe99&}7c{o0r`}e&-qywP7qLssWORRDP%I)^g9cU%8p8#xrsO~nwD@w z?qg%wovS31tt*5R$ag~~{D`}pWR3Yewv>DV6+F{D9|EQxA}V+f`=riJPt{6|Lu*QC zysRXaze?mCME0HG zV0=^EVYwFtXX_o}TzgGpx4jgmJWYqh?2ahOT!%j6H`|)va#^Gz$`wZIuPHCy;V0K)BScz9?;#P^PHCcq~=fO-T^bRdFUJ5amXj0?=I*lEX*K%xlA>V*h>2jPX!_V=}3!JTWsw%@>g;vU)Ic%tsq)g|-0 zH?cSES(sXxDIt(>R_(;&8J-7(b^-Bg4ZvfMbA10MeU2RBKEu zEc8OR6MK|-Qd?JNGL%CIob#_KaEbl)ty_g^%=G?ZpoxJpWgV9Z{b{hR-BQ1IZf-8) z(Vv0L8~!OjGi1r(SAl6rDG;EeqZ<$Bl7ehqYBikz48j)rfZ4gZC#a(2?>`F}5{i#wR$B!f)lJi=o$tMa2NB)GVp0MNf zX}QVA=DRN=%O7F0DqkJzOmUcU%IpxVKRP<9J^CFRTz%&6kAo~TTYUPhx3}Q=lRUTc zukgxnzIG>A4#3Oi=jZu+y7~l$&3RNwx!UzPUzceh=9`2gG$bT0L)UD#im)KyF{SQ9 zaN3%YHv!2&sg$>AWqyHF)@;rb77-z-q@?6_zX0)%ys`sgDtKrq?-hyd4NJxpE~mKl zb%2yqK8~xJdTU=Jlsy83oYy}E9|X9>^IbX+lCS+~@XTQGwBR8JhPMdD3>0fT zXdY0a0JIc2lnB-ERJoA^-z(Ivg~(Aeq}x!_#0*F&FC%lUV%lBc$_=XAkj~p;TCbPU zl?r$R&uZLioYl{?HSvR~gknJR=ux;r4GIRVp}o619X3nX{mA?D^wiYE1b0E#<1Dhgjo~n9M~sq5dWBDzf!C*JWnouxhc7@c zGY0R%?H@v4i~>jidzE~xt0=vTVhLz)5Cmh1?V=oteo(pXDv*wA`C&DV#h1CMpJZDo zsqiKsFTjVCg*6}j`gj8k)rgo(RzHLyYP3DyUJG^>NUbY8GKdSy+AT?tYMoY#+SEYV zg=SH&%oUmVrqsLC-f6V(b*bfK%w=36c7u+urcOU~e5dwmwqu9B8-xfuZ_hu2QoOvq znF+yj7rI!uuF!eURL5oQA&7&2MxkqHf!6QY^XGRtI6|SV4vmV!ZiGe#MW#Vbw2^sN z0+mIh+`Jvss4CFh#%dhcfRc}z^Pu_*2q|lcaR#qV0@b&>eNYP6-_Ab;%T0?cRjNkL z>W|ThvmN1c*`*=gIxKCA`qh;(Wi4m#>XHw_fW`76XM+kl)j2wn)IolJXm{x7qxd!wbzu@*iEWgQ?UOev#=ckN2?b=ASYKl03xA8cEpTx5l29I;JgXYoS~ z#uO?7f`bjA)rMWI6kx(r5f{eBttzcqizE4B*zP47-KOkV`foy7p>z+@p{l0yn zPI5jkc6{HDEaaJ4hpx7SghZ7frDp_cmScQqp<7ErA*ahMx9+xT$kfuR)-r$S-fv8v zj$9Rupd1q-MIiqy2 z6WN$NB_)I(H{}$xoyohFHpSswT9Q2Evr7iNTwC_ZQ-sLgunF#DOpg7k{3Yk5VeZYi z@>ljeBkxPphj#mOIvCcXeu){w&%(!yCD3u&>uk$>%x(Ysux zB}8OUew%typQS_kqYgh*Pd?Ez7UnrskJR&IbokbT?%7A_?q;)(`T8qwl1AAJZFk>l zoq)gB$!SKJkZYF(HSZf_39~FfsCEHPP`a(8rlwY%tk)pALUaZw8X*dLBKCs&658k= z8-ILX&LS?bkWqb8J+>b8DJX(_Nh$tAf4%tyH{KkQQj? znpV1ssio!YD*q)P{~TUVb+}^nPFAu>+)9$mu=v*8 zjIxOzJ{&5V&XA2At+csENJt1J({?f5;SEph80b;p#x;+OL;}fG)X?Y#4CZJ=DIKm=3TY zTI2X_!6usn@Px?(E-!Cy8!#OP05up#R&uq`azyz5MQo=o|3hreobML085tRs=(Sx> zNlgV>3yR!dv)AqT9m=>)e&Rb?Y!GlSX%$%(kd}5I^_nd2WD8S4Es8Vt3LQ`Y3166W zm~J&Kd&3#6R%6csDK`f?n-MsQT9wxC0ipwe3jiVN0_>$cdMYh_kCpYhCn1x{&wOnG zA~qcvPy)ed$t*7JPhU}VC>nC{N9CJwVW|bCvxnr#3Jc8V#58~>D|j>?_HJV;9&|Xg za;s@M==s67h1k9gROI~ZgtARST>NLfn+p(p5aqzk1U(<)G3+!w6H{tZ5}JepsBTwK zGzyA!Gx*{lkB@E5LnV}kIUE0!7b+^>A(TGB*+DA-bBe zITn|Mg@u8Yv{kLP0r3U_8BC90JI4#CAYnBHJyB*`-x+Mk$odnzqIB3jW-_XL$y!;REr7tzs=hEZQ(9l2&-XQGvfQgheuzR03We*kv>O6oT147}#)6WB~Tm*J+Fw^V}Ls;d{ z@8#;8e6+9WHq=9rH`5`1qXZ`(Fs^Qqk##^*N7<$WtP`c|f-Qnl7M$YPU!y}GB)B)I zD0qH2=X!p$SUr+VjA?cpv`mIAlNv$s(s19wt)&|H*XEzpkl`hL7z65jQv~}t#q?z# zx(^cmxA%d?_?&IW2aTul?v}XKRpX>*>@LUZ+$-SG-QPnV5bomG8C`Y*et{am`t<2j zS;t&00X3@bR3-wUnvzzN)H_F1v%0CO{9lqM0Wj#5heAf3$h{sMTO*6B zNz;oBtWLFB;0D>rDOQKz&`hwhvwsF)tcah^axs-{<6D_>DvK9z2>$i!*CR?Mc@%v9 zPr&{+5{L;1lvd6+QqG^E!2G|RP$CQP#Bn{Zbw;SytcY0cWQy1{RQHtp5c0n{soPDV*5ivjK^W2^uo+H zo`*4MuLq?=CD}^0Rez~>9{b}QcbRO>UNt8*@W*Ww^@$U@`ezLxgq8J{ca<59WO8PN z*hn5<(g`C+3Aa0n<0H%}p%=nro{rLj&{I-T2$dsB(;paf7zCqNDwrt@mluLl6iGM z@VGhM{Tr5~9i@Ad%jlK>p0&rz2$@9T_|;W&(40Pk{XR)EzOrU!`gItK(C!$yp4{WS zKZ;y2urdL*Wm;MqYNT?dCpd%nPM|ySzcvJ2-pv7_`eV$T z2gX`a3U^;$9~uS!TQ8WB+kwdo7>S^`PA%L88rcS)<-z*oeOg*hmwj{8RL8%-ALcJ# z!{pH^IGl-k(o_dK7 z7~Syw9QPQQhzgC13rwL$jjV#g1~#mJVj?w+q^wRiOozHVI`RQXV6fJCn{h__1q9eK zgFqIVn0TWxm{I^W`UHAoE08cv%PMbhve0H{XGg)iMuP!B3SrkMI9KrdP@D`7@barh z&r7hXP2ihKxah=eI`bf@!%)hvl@)0))<(-MVmt8~^H1fDykn* zbPm-$LDz_Jkyp~&*?EtJB?wGfv`DPtfWW|a6vX)WFCJJ>Q&Te&NryWhc62=d$Dl;b zr$9R`rW)ou{6A!5}{D02oMBS8DtGI2?f+R7P!M`Pz3pNeC6W!L;<8hDuiEy zVLDtQ=Em`H&5A9gCHNnKq+A&t6yM;*U*I-_Y&ca^!1H+dVUpSO(|p`)RA&)ioiu31 zUgn|dVZS;W3SMpzs38OrG_0(_U|@eqNPr2y2jFT#*Q(4kAHT<1>=6Q70a6Xc6=rAO zz?2QR%(bZr!aO_?a9F5$aj82fq5ul9E6mD4i-w}vKooLz*Dvw8>@$N;>3|7iz<-U? z$(oAP<7X%1#v)}SX%+SVa^y7qmRMHSJb*it00jbJ>KSMNFbD7(xWivLXt!S)xPuBW zi^WW~HWfJ4c^YMJpcr+<@rS`AAB-lh)Bi-x0{5j#ee(0W!_7Sy`WeI9#_%I-@i_?l%3#ZQ4#_VCXR-l{;Q+ zfEyxwY#c8~>t$T|&p3YFT@$OZVsB_7KwmQ&Wt$$W6motdGCqPpyfA%UP)|xY@BB^D zcv_X+^ga(Lfz6OW&%s;G+va0yl|mJ@^-R^Z{v{uf^&wM5&Uj^#OZ+uqyv~n)@c149n|%LXi|jI?XFJ^P&2#`mzixT=XPloc$-(F3!{>&&G8;vs|%FK>m;fNgoM z_C_wd!*B%JkknQ=o!-`!PRd+)B*U0vN({R?YFXs9U=-KV|}004-T6y>x4 z037w3CU^JFO%L>b6W`4X7c8TsbNA-)yZbKu=Kr3vA_xos5O@A*IEkFZG&h}3+~f`1 z?cajI;!j*HJ!~vJAF=MK-oz6AiPf=jv$q6j{nhVL z2mN|81wcverH)s|&b+6Wj^%PK`r@53HDeB?3_jz7I1L%TZx3)xx+YAs_V&pw}F$LJUsG8Bk(KU(TXH+QrF0T%4$|w*3lBFAxeNg6+Kb`huL{^H5^w_Awrb;Z zoFl^@_5a}FZ_4q)!pMLpnRUZ~b2Kt#z`7tPE0gOcL8bAhS=Y+js~2?F;M;-c#8TdW% zftpStziNfrk@E9E{Zv@|{Z)x@I}CLbGyrz%-d(#FZwBltr*HR(PG}xz>n)YKlC{Ub z?P~3g{Q7d{oL9xY(YDlw+&5DMNO66&c4)63duFGnrBNd`xX%u_AH&d@dL>W`AGg^3 zz2;>HPp15(-OPoSQmQG|&ozzS*HXPaWNAiX78H4iT7v65=qz2ApUh-6AXd!#)ziJO zqems>$oq|XUvZA;3f?S8n^K+tRFnLat_vpLYQHGRu+Kc#h?o@dcUF#=Yy^*NOqbE~ z64piFI}R*(vk3>6ikXTZeo&ypWluPLsVPj?)T5#CI;xB_h; zOSuwwNd?3VYtP&0a0cxZQE?eG;w!B6XhnmT`$kuef+n@QZGP9T|M*%NOJe0<5yl&G zs2>1lpcZ;EQ~Ocq4981bWZ9#>U6anbbV4)(-?_m4r&%c(qh{hhgRz{W;ggR<%v9J_ zol8cCyAG6h@QPOVIIA7raFjU!Wyfjm6;a_#Z}lMkDSeyEa6_i|>2AiPCA6`MEVJ)? z*Dt%@Rmw9|%Yk>d0$)o*D(T7s_1wL4N3hf=F?HzZ)|2nH>_#W_EA42^zD{hH4GGt{ zUnI75l*Fr<{{9@E<@w5y&wg@1JyY^SCt^k+TW1r?ww3Ok{@`t{S46F0L=nLT7p}ha zrPa688?vrhh?mnHfh+SZDR<_5su(K?{3RWc>a?A;&BsggtyE@Kq_gx@DG1J9EAxoQO21*9Bl(#RrcB_$-FpI~^poNM{qyJ;<=bop9hQ$!nB3fvj-{Z#Rga=sgH$>h=o-XsCvkH;H^{^@N#rG_#PQ8K+2W|?b z{t@rryFS&$i7%m)yiu*lA);0XnTxcG4RSoA!o4MDFNuuD=*0r#%)Qs%ApO|ZR{`hJ zKf$#E4y$xyC591ZS^|Lg#+*Sm%zKMhm0(d~T)iUg@94;AXvaaOsdrMyycMw0ArAMt?#E322VBs!opPh9}gRM^Y;2OTx1wy~tN@ zvG1m=o(;xP6jVDIaUf8=@YKraXUu!q9!Jk%P^;&Q<6;KneurZb0z2A}rs#|A!FCD{ zBAf!zU68#bcYok{iZw`dTa8NvF3GD9z!{#ZO-_0-$32HZ;li-~&jXrH;`J#Zc^nOGOtlVr==ayNJx_n$hii(Z>mv=-F~g;l z7%zb<(M_X=d(qJA;93`w0Dcb^jKLRtU%3bUNwl4#f{`^UT1w?3lv`710ojm=w^w5! zf_~W+IS$QJoZbf2%c33UxCfhI_&p`$-Cyc`sm?lUwol)Yg#BEp?hnA@1HDZ;p}c_s zgh?~)>Blp><3;H$)dTM~Z292QM4gXcl@-bH47z}N^tXgd-t`CQ%rz49fuXS#kR?Il z`I6o=mL>}xJ%sAm1GsH0|_7tt!_TUTqm^YG1WVPzn(L4lD>9?z&S@T`U zZgK6S9J^{T6n=wt_saAi@3m(=>lwu3x?7(Vcg}~4dx~Z-QyOfsnELJZR8(^R(4fUu z1j2;i}XxZLmxA!6I9@xRxWiM`0o2ko%+-7U+iC~wS=s`lPm>DBn`wY z{8)JkC@=qo<|U2iR8;jfL^tjPw5?R_zqxJy;DNybD*iItJhEq8Mqy1}j*uO~#B^sH zkl-k-F^qXYT5sQU8m!H!PD)A^2@Ma&>C%?#{IL9t$@~TS5h>pd=7v*hNd9x!qnohX z{|b9C-NJgsvFOn_-Q+D`V`EciTowt52{(S?(U|$|8+)3NU1-M=`^7QE8@1$`)zx=Q z%*;xPich$>N^+shOcWYgS`QmN_X=HBx-F4_1`SkGc@JL8xxbd5N_wKz; z7am}Th_8bbUwnW(j4zh=@)A8eJ9{BVYXPTGlWNF%Bdb-9JRUU*OlSm>9Cr~moROt(dj;DB`NuxjFW9J zZ!oXpR8>{9`oK3vP&HfrG=#(`qFe@vy+obVqJNw`TMsw~xI0kziKF@q6|YYz-e2|J zdR2Q@Tns9UxZVPoN_zkkuF?2uxMmrNRoADUglF?cf+`t<7Q=&4u31bJL7RP5=F3!b zLBM8VbZ21W7jH}|)tI+Aq5p4)cb;t&g&|;ZXklmYn|shrg{8fD`NR{O-)y=^D` zh8)+~)Yjk@VFrSmdy>EaR*88Oax4o&0A2`)VGAW(+jJQP`638TdyFMQ;$>g)Tbfv< z?lzpV@h2aRwlIBD58T}%LuAATFrmhDK?L=!^HNPfto+rlXGt3y@6Da)dp=ph_mkFr z4iwKO6ApLgLQ^*0r@{6H1k85fCWzMn=RH*aaO{3LwZ-YF6Z9wOr|6$qIsnqw0ryFs zc0QQjYUE(ChQ#vaPqk3q-Nn#l3{x1n#$g zQ9PeFOm3(}%8s4vVLJF0Qnv&q54ush-Un4R_Om}CNqp%S=QXvb(#+DfGUZ@9UE10d z@lEcx&7>c;S@Wuz%kpIrA5m#sDs z492loyCDA)AL2*28ubHjy47g=7ljl11>X&q%a{`TVQ{v}uu>ulGZiKYZ47BFm@5%{ zwX%{AAD%l>iGT1Ir!#=vHQ(EK6>R|oS7ZxL;y*xgeLS^ecE-gW%?4ZBuI)Z;{suO0 zSt-G8(6yY~0O3*|w+7FAfeWJTokUdKP8Ma1Op=d$k$Nr0%enI(cE?DFp_V6J88quv z+~r?mH!~V}pnuN5#FXuGUzAAlVTK>9=|WIe&4hf4wzfP!T3K(kIL?=?O4>knW>9GE z*I}Lq0m$Kc+*%YumSZ_o2S z^$XFHiZQHqqHik<;hav_ei1N%qXnbuijGCNM|`H{kL)z_{n?Y%{^JC-wBbTB5Ioc% zSx4pRS&JUP@9)`9m#$0j;~BwZjMyIk?nQqega<1e9KCd! zhTpSQE*}&oSBG>Jx>3~IJS#DPg*81C<}*J$mE(!w6oCw$yX|PD??mKL39nngGX0wd z?z1)wJ#nn$UXRuceA`(?mf9?aaeIUP+H4z=ypNP6NI9?&+TETF2QLgzDjsI~7adqI z5yV_ZuHXU~9lW-OC+ukhZu9Nn?_18}%o#TeIx*E~Hx79re<%JlV@PWgH{1FVZ4p8W z^m!ON1$A`_ORE0u#juhPlOYykWcryQt0%;|Vb<~JMk!uztIB8M)QOjxwL&0LzP~v) z<;ot87OLjy7VBBgtamYFB)9irm`1H<|6J!NqeLEnKg?wHx9b``rm3g;;8A_U`!$f- zzdj!Qx#5>VYC%CkJ-xkR*F^HGKWgnJd1Pc{1_L{ojFDN-8vwbvxdv5MM4Wmh-!_WE zd+^Aqsg-qfz7E48trL1| z;#_b1Sc;Cc{>8S3gr=sZpxp#vScm5E4sTlqk6mwXuiUFwU*h6k7#JAHt1HOyWasCz zcM?13+rx(sQ-mGTG$q{;RS&SE9ZdSM`}@uZ z7)&%w_u2hQuHszi6DErIzX!_Xlm88r>heRY2Zr8O-1&j_`d9Te*}2wCuG8OB5}|vP zz)P@bhnbm7S~(Yuk7%_kDNSs$O6Qh7!I##W)FA8wo=Xeh;ZzZnnY&e5M|R68eTtLd#b*K3*fR(LPbS=@bV@a0ey- zfkl9!*gw&78WP7Z9pCafu}Q2#U?4C37i^NU1sS+5-x;kysAl}i&?j;NS=MQWXf@r%`AaE8y9|fpk2P zvgr2f&}4YQV+WT))HO?;y%{Hmm1M}A?C_$0eR`*SoioJ$IleJ8f=qApcj>tO^z&qw zlbQnC_X703Ti#_P-}|$R2tb$9l*>U;3{_8lli%s2dpm)eRhKTu+fKonX&KF{*QUYv zC3%^WW22g8cbP4)p4;DDm?uN$AxpiuET zmgbjy(H@|8`BmZ2X}O4o_QeZlDaShQw2bloslWz^8Z{Dav}~)(D#(%&E*wlH;ldR> ztHU!Y*muaWI@6b|Vq8u0EAza4sd}3}7TnQiwR7NGOP|LF@4lqPcfh_nDFjMiZf$k_5*rm59*@HnS~-+o&P}Prj8k z5~Z2ZL|@w=%QN)Z&~~>kI40iCX9_{CT$6o^-&NAtRcftwAp6NTjvV1^S`v8Trfv`Y zt7s10O`*4>+b-8t(;r32Pro$YfDt2bwr)H5a z=un_!3A@osRRGYxHk#H5*IhSJ`(XQI5px@+@g3hP?gtx9 z`DE}(lf|9k>ID-W&@oR!3-}inX&@7slGc;BoZB_(>35r;Hq^yG?3+x#9==d{D@56- z)l$|`wE^2gvsBE=XFH_<@i`*kpFy_QKm!Oek2YrtglEYV1nd!Tdx<^Yrp&P|^j&|Z z$%DafZwYCRgo}%hR+kopSSmi1UVhy{2!E~kRm+p!GplUyrsPjeRrYaV4o3Q)^8>1IX#wLZng7& ziS_C9!+VL^6Xj;=LlCL*-ST`4y}8x(>{&%WmvmrVPD`yu+57*<6MEnRyo~4ejmg!P zd;B&=oOe#jpw4}d_i`c68@`z6WjXL#?`B5Kjbe1a+|I4vT9fmU``w)By4G0dq}vc= zGQg>>(9w>V5v{wyepgKsa}>eMtiEOEjF*=RT8b{ItFBM5&Q} zp+og7&p*Wc8`$iw^7=r$wjw&~a++LOCxLj*1LYJEy4BXap1>tEvYW2ELe(uSghr6(GIrW{xxlTMIaAbhvzbr*}0bKb$>BJB@NNT$ej9v z2QvwjBaN5oV}t}qf*L{bUxUWK5ea1iyz~8z8KX*PsjxGgge@KfS$;nt8Q})vlPcD0 zp%xiES;=|8QkLeIx41ioAj*8RVIok6Bf*J1L^sJPSlb|=f}E&Izfx=z|Fn0yKD1+e zc0};7(~C9ift=hRToQsLB#&kojANAbK1i)K&|h&3CE0zE2+00BMOWAH9(iUMQ*Nl9 zMzK%72GyOGV-w69nNH+%^mP(4pOtfV-k~=R08SevyJjP~=a5`CEJFZ&X0mOXpzLML zbu>e4wcS}s=%{@*DXoy)dc(2)p^AU5_$p$32>r!7AJEaM_BR$*%$q<~qP~`!1tO|E zSe2Zby3;t0zU@kaUO4e=ik;bepV)+EH2A*(&q+tcv1Z!vuMi05yDwSo8S0^gR(3ZY za4mo=C>ooiZMls!H^Z`~vh-sQ3lzQu+F4MG)5MEiSjW`1gu4533^ynU*>{ta#N8~$ z>4Ht~bf|%=P9P!BFN^2xnmb#N-R-@mL%f_oP|pz7cDeWH;p(>yrHDs+lUWnQ-;^)t zE4fa+h-YVxprCNPe-mw@6~FFGjud&*3nY+`Y44M@=mlm6JXsXqVtwl1vqJCzITBA|zvkQ4WN zSEllAEKZZfw1VuFcmCy;(z%DD>}xkc)!CEvRNj-U6pIO&U8l*|S~j54iSV$T$W~|e zNmAuubJ*qtf7-^>EG4=tKn-Hl@i(+F)A%=eWxrv?QI=cu&d^V;wmtLyG57{KjjEfQ z-L97pPgv6>Z$EsgTw%0PRv9M$RlV6Vt+ET&1}W=@^-@@7xcH2PfXg{N zK3_WciP~}%9~`6G+l&Me%KKfs_`W`(3#@)Wt6|VaZ(!>MuJY((s;|qN}J`3MhZ+noPqM@8F9b z8Yy>gO#L7qbs;BUcw?*-U8i#=%z%1@5&x4TO0f={%=r12Ytz5mq-|%KL zmlI|!{wnP3qQTVy(0r(&jY)Jpz?9l|;wd9h{aOy+oYrddL@r$5I$L3h&kQJFr8Fx+ zgY1YR+Y>waVHY^0LN;`1{KqqbJ;Ta!#9usNIF4BB7zImtBdS2R&}_W6zv=~QSj)t) zdffI)bADzbw)itS9Zv7<&0Z!1&_%f6k_N~sFfB~=Xp$_>AP`Qj8>hCwGJ-0czql=u zN-UUL*2onZ_J#oJvG$rAphs@@t=HqInNL zTi1vbGgP|;Q#DsKw}f1^zU>TooCYuV&nTcqIk8CoN=jZZZbRZTC_9slD#G5_$D98^HvxKH@wvdX?FChLur)PkjO^F{04{QUfk)2bU4_{m$z zOf2=SC+n|5kl-ZN<6$Fa&~S66BfP}T_1=5%n<{)#Qom(u&bF6;7P2jKb=D%Wb~*VB zF^T2ya3)b-2C5JbUv*4YO(C&uJ6S||T*Z!#E*seJg> z0}wy5h9^`F0)0IO|-1Ic@q{$BG1*m3nsozxu))6H5aL zFG6v-N&$Omy=qtT%r|xyP69m3C0C zI0V+JQX5-i=u*TL`UMo>!kvS?fx#iJ;o!VLKG@55IROLsPKWHO>je zlCX5NA_hycAtR6T{!OO)pV=?xZ;f)4C;<}txl~NL2}EWebOk zX0VOgjX@yjj+xZJsU=(tAH(282a9Af1`sPD+;o)z43-l_; zUfDA~J?UqprEgD1f4o>=p{yJJmE?)yaIr@`6Fa0(W@djXuXI}U@{aio$zp%Q?YjDg z-dVdKo3qt-uY^w1UhY_g+W_OH-CsTTmZN0^eB_fnJdl+Okp6JYr}};rOp6~V^3`LB zExG3Z8l#rdYbjk^_RA{5I!t1%_OXxw~YabXh8?h?Hni$o5RdP`@p57{@88xjQ zZLx{2!hp{C0>&|TxLt=UFhp#M<57-hUP9w-JxX*Q8#>&dS#xyhZjto!vuTnPucTV}Q%+CLW-T9BHuK(GP z|KB#`I1|vb$2YVO?KpzXuMKLnDf<(tv2(tfF nV%^V-4)3vi_oq7R8vhl%Q<=-i0(nzH22he$lPi;X6ZF3T#eaDH literal 0 HcmV?d00001 diff --git a/layout_management/simpleform.png b/layout_management/simpleform.png new file mode 100644 index 0000000000000000000000000000000000000000..4f3819bdf16b577a5957b59f9db1d3547d763b74 GIT binary patch literal 5458 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 literal 0 HcmV?d00001 diff --git a/layout_management/verticalbox.png b/layout_management/verticalbox.png new file mode 100644 index 0000000000000000000000000000000000000000..1126cfffd94e469e0ad1825ad88af1e0396b293f GIT binary patch literal 21693 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 Date: Thu, 9 Jun 2022 17:46:47 +0400 Subject: [PATCH 6/6] fix: refactoring folder events and signals article --- events_and_signals/click.png | Bin 0 -> 4340 bytes .../events_and_signals.md | 0 events_and_signals/moveevent.png | Bin 0 -> 3435 bytes events_and_signals/timer.png | Bin 0 -> 3528 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 events_and_signals/click.png rename events_and_signals.md => events_and_signals/events_and_signals.md (100%) create mode 100644 events_and_signals/moveevent.png create mode 100644 events_and_signals/timer.png diff --git a/events_and_signals/click.png b/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/events_and_signals/timer.png b/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_