Перевод книги Julian’а Smart’а – Глава XIII – Структуры данных (Часть 2)

Читать первую честь этой главы.

Хранение и обработка дат и времени

wxWidgets предоставляет достаточно комплексный класс wxDateTime для хранения даты и времени с множеством доступных операций, таких как форматирование, часовые пояса, различные арифметические операции и {т.д.} Статические функции дают информацию о текущей дате и времени, а также методы получения информации о високосном годе. Советуем использовать этот класс, даже если вам необходимо просто хранить информацию о времени и дате. Вспомогательные классы wxTimeSpan и wxDateSpan дают возможность легко изменять существующие объекты wxDateTime.

wxDateTime

Класс wxDateTime содержит слишком много методов, чтобы все их рассматривать здесь. Полную документацию по API вы можете найти в документации wxWidgets. В этом разделе мы дадим описание только самым часто используемым методами и операциям.

Хотя при работе класс времени предполагает, что время считается по гринвичу (Greenwich Mean Time — GMT), вам не надо об этом заботится, так как обычно вы будете работать в одном часовом поясе (локальном времени). Таким образом, все конструкторы и модификаторы wxDateTime, составляющие дату или время из компонентов (например из часов, минут и секунд) предполагают, что эти значения даются для локального времени. Все методы, возвращающие компоненты даты или времени (месяц, день, час, минуту, секунду и т.п.) также дают правильные значения для локального часового пояса, поэтому вам ничего не нужно делать, чтобы получать правильные результаты для вашей локального часового пояса. Чтобы узнать об управлении часовым поясом, обратитесь к документации.

Конструкторы и модификаторы wxDateTime

Объект wxDateTime может быть сконструирован из значения типа time_t (время Unix), информации о дате, информации о времени или полной информации о дате и времени. Для каждого конструктора существует соответствующий метод Set, который изменяет существующий объект, так, чтобы он имел определенные время или дату. Аналогично, существуют модификаторы для индивидуальных компонентов, такие как SetMonth или SetHour, которые меняют только одну компоненту даты или времени.

  • wxDateTime(time_t) создает объект с датой и временем в соответствии со значением времени Unix.
  • wxDateTime(const struct tm&) создает объект, используя данные из стандартной структуры tm языка C.
  • wxDateTime(wxDateTime_t hour, wxDateTime_t minute = 0, wxDateTime_t second = 0, wxDateTime_t millisec = 0) создает объект, руководствуясь заданной информацией о времени.
  • wxDateTime(wxDateTime_t day, Month month = Inv_Month, int year = Inv_Year, wxDateTime_t hour = 0, wxDateTime_t minute = 0, wxDateTime_t second = 0, wxDateTime_t millisec = 0) создает объект, руководствуясь заданной информацией о времени и дате.

Аксессоры wxDateTime

Аксессоры для wxDateTime обычно имеют понятные имена: GetYear, GetMonth, Getday, GetWeekDay, GetHour, GetMinute, GetSecond, GetMillisecond, GeTDayOfYear, GetWeekOfYear, GetWeekOfMonth и GetYearDay. wxDateTime также имеет следующие методы:

  • GetTicks возвращает дату и время в формате времени Unix (число секунд прошедших с полночи 1 января 1970 года).
  • IsValid указывает находится ли в объекте допустимая дата (можно сконструировать объект, который содержит недопустимую дату).

Получаем сегодняшнюю дату

Класс wxDateTime содержит два статических метода для получения текущего времени:

  • wxDateTime::Now создает объект wxDateTime с текущей датой с точностью до секунды.
  • wxDateTime::UNow создает объект wxDateTime с текущей датой с точностью до милисекунды.

Ввод и форматирование даты

Функции данного раздела преобразовывают объект wxDateTime в текст и из текста. Преобразование даты в текст достаточно тривиально: вы можете использовать форматирование даты и времени в соответствии с текущей локалью (FormatDate and FormatTime), использовать международный стандарт представления даты, определенный в ISO 8601 (FormatISODate и FormatISOTime) или определить произвольный стандарт, используя метод Format.

Создание даты из строки гораздо более интересная задача, потому что существует множество различных форматов. В самом простом случае ее можно считать с помощью ParseFormat, который может разобрать любую дату в определенном формате. ParseRfc822Date считывает дату в формате из RFC 822, который определяет формат даты для электронной почты в Интернете.

Самыми интересными функциями являются ParseTime, ParseDate и ParseDateTime, которые пытаются считать дату и/или время в произвольном формате, позволяя их определить различными путями. Эти функции можно использовать для разбора пользовательского ввода, который обычно не соответствует никакому предопределенному формату. Например, ParseDateTime может разбирать строки наподобие tomorrow (Завтра), March first (Первое марта) и даже next Sunday (Следующее воскресенье).

Сравнение дат

Два объекта wxDateTime можно легко сравнить, используя одну из многих функций сравнения. Все эти методы возвращают true или false.

Следующие методы сравнивают с другим объектом класса wxDateTime: IsEqualTo (равен), IsEarlierThan (раньше чем), IsLaterThan (позже чем), IsSameDate (одна и та же дата) и IsSameTime (одно и то же время).

Следующие методы делают сравнения используя два других объекта wxDateTime: IsStrictlyBetween (точно между) и IsBetween (между). Разница между этими двумя методами в том, что IsStrictlyBetween возвращает false, если wxDateObject равен одному из краевых значений промежутка, тогда как IsBetween вернет в таком случае true.

Арифметика дат

Библиотека wxWidgets содержит два очень продвинутых класса для выполнения арифметических операций с объектами wxDateTime: wxTimeSpan и wxDateSpan. wxTimeSpan просто содержит разницу в милисекундах и всегда дает быстрый и предсказуемый результат. С другой стороны время имеет и другие важные единицы измерения, такие как недели и месяцы. wxDateSpan пытается осуществить арифметические операции наиболее естественным путем, однако результат таких операций не всегда хорошо определен. Например, сложение 31 января и 1 месяца даст результат 28 (или 29) февраля, который является последним днем февраля, а не 31 февраля (этот день в феврале не существует). Конечно в данном случае мы получаем то, что ожидаем, однако вы очень удивитесь когда увидите, что вычитание того же самого интервала из 28 февраля даст результат 28 января (а не 31 января с которой мы начинали).

Можно выполнять множество различных операций с датами, но не все из них имеют смысл. Например, умножение даты на число является некорректной операцией, однако умножение временного интервала на число корректно.

  • Сложение: Значения класса wxTimeSpan или wxDateSpan можно прибавить к wxDateTime и в результате получить новый объект wxDateTime. Также можно сложить два интервальных класса и получить другой объект того же самого класса.
  • Вычитание: Вычитать можно те же самые объекты, как и в операции сложения. Кроме того можно взять разность двух объектов класса wxDateTime, которая будет иметь тип wxTimeSpan.
  • Умножение: Объекты wxTimeSpan и wxDateSpan могут быть умножены на целое число. Результатом данной операции является объект того же самого типа.
  • Унарный минус: Можно взять отрицание объектов wxTimeSpan или wxDateSpan. Результатом является интервал с тем же самым значением, но противополножным направлением во времени.

Следующий небольшой пример показывает использование wxDateSpan и wxTimeSpan для изменения времени, сохраненного в объекте класса wxDateTime. Обратитесь к официальной документации за полным списком доступных методов.

void TimeTests()
{
    // Взять текущую дату и время
    wxDateTime DT1 = wxDateTime::Now();

    // Промежуток в 2 недели и 1 день (т.е. в 15 дней)
    wxDateSpan Span1(0, 0, 2, 1);

    // Вычитаем 15 дней от сегодня
    wxDateTime DT2 = DT1 - Span1;

    // Статическое создание однодневной разницы
    wxDateSpan Span2 = wxDateSpan::Day();

    // Промежуток 3 теперь равен 14 дням
    wxDateSpan Span3 = Span1 - Span2;

    // 0 дней (промежуток определен как 2 недели)
    int Days = Span3.GetDays();

    // 14 дней (2 недели)
    int TotalDays = Span3.GetTotalDays();

    // 2 две недели в прошлое
    wxDateSpan Span4 = -Span3;

    // Промежуток в 3 месяца
    wxDateSpan Span5 = wxDateSpan::Month() * 3;

    // 10 часов, 5 минут и 6 сукунд
    wxTimeSpan Span6(10, 5, 6, 0);

    // Добавляем определенный промежуток к DT2
    wxDateTime DT3 = DT2 + Span6;

    // Span7 в 3 раза дольше, чем Span6, но направлен в прошлое
    wxTimeSpan Span7 = (-Span6) * 3;

    // SpanNeg должно быть true, т.к. промежуток отрицателен
    bool SpanNeg = Span7.IsNegative();

    // Статическое создание одночасовой разницы
    wxTimeSpan Span8 = wxTimeSpan::Hour();

    // Один час не длиннее 30+ часов (сравниваются абсолютные значения)
    bool Longer = Span8.IsLongerThan(Span7);
}

Вспомогательные структуры данных

wxWidgets использует несколько внутренних структур данных для передачи в качестве параметров и возвращения результатов из открытых методов объектов. Прикладные программисты могут также использовать эти вспомогательные функции в своих проектах.

wxObject

Класс wxObject является базовым для всех классов библиотеки wxWidgets. Именно он отвечает за реализацию получения информации о типе времени выполнения, подсчета ссылок, объявление виртуального деструктора и дополнительные отладочные версии операторов new и delete. Класс wxClassInfo хранит мета-данные о классе и используется в некоторых методах класса wxObject.

MyWindow* window = wxDynamicCast(FindWindow(ID_MYWINDOW), MyWindow);

Метод IsKindOf получает в качестве параметра указатель на wxClassInfo и возвращает true, если объект относится к данному типу. Например,

bool tmp = obj->IsKindOf(CLASSINFO(wxFrame));

Методу Ref передается параметр класса const wxObject&, который заменяет текущие данные объекта на ссылку на указанные в параметре. Число ссылок на текущий хранимый объект уменьшается, возможно освобождаются данные, а число ссылок на объект из параметра увеличивается.

UnRef уменьшает число ссылок на ассоциированные с ним данные и удаляет данные в случае, если число ссылок уменьшилось до нуля.

Класс wxLongLong

Класс wxLongLong представляет 64-битные целые числа. Когда возможно используется родной 64-битный тип платформы, во всех остальных случаях используется эмулирующий его код. В результате вы можете использовать этот тип также как и любой другой (встроенный) целочисленный тип. Заметим, что число типа wxLongLong является числом со знаком. Если вам необходимо хранить беззнаковые числа, то используйте для этого тип wxULongLong, который имеет почти похожий API, кроме некоторых логических операторов (таких как взятие модуля числа). Для этих классов определены обычные математические операции, а также несколько дополнительных методов:

  • Abs возвращает абсолютное значение wxLongLong. Если данный метод вызвать у константного объекта, то возвратится копия числа. Для неконстантного объека метод изменит сам объект и возвратит ссылку на него.
  • ToLong возвращает результат преобразования в тип long. Метод вызывает исключение в debug-версии, если при этом происходит потеря точности.
  • ToString возвращает строковое представление значения числа.

wxPoint и wxRealPoint

Тип wxPoint используется библиотекой для хранения пары целочисленных координат (точки) на экране или в окне. Как легко понять по названию, класс хранит пару значений x и y. Данные члены класса являются открытыми, а поэтому с ними можно работать непосредственно. Для wxPoint реализованы операторы + и -, которые позволяют прибалять или вычитать из текущий координат значения типа wxPoint или wxSize. wxRealPoint хранит вещественные (double) координаты вместо целочисленных, а также реализует операторы + и -, но только для вещественных точек.

Создать объект wxPoint очень несложно:

wxPoint myPoint(50, 60);

wxRect

Этот класс используется для хранения информации о прямоугольной области и обычно используется библиотекой wxWidgets для рисования или в элементах управления, таких как wxDC или wxTreeCtrl. Класс wxRect содержит поля x и y, а также width (ширина) и height (высота), которые являются открытыми. Прямоугольники можно складывать и вычитать друг из друга. Также класс поддерживает несколько других полезных методов.

  • GetRight возвращает координату x правой границы прямоугольника.
  • GetBottom возвращает координату y нижней границы прямоугольника.
  • GetSize возвращает размер прямоугольника (высоты и ширину) в виде объекта wxSize.
  • Inflate увеличивает размер прямоугольника на заданную величину, которая может быть одинаковой для обоих направлений (один параметр) или разной для разных (два параметра).
  • Метод Inside определяет, располагается ли данная точка внутри прямоугольника. Точку можно определить как пару координат или как объект wxPoint.
  • Intersects принимает в качестве параметра другой прямоугольник wxRect и определяет перекрываются ли они.
  • Offset перемещает прямоугольник на заданное смещение. Смещение можно задать пару значений или как объект wxPoint.

Объект wxRect можно создать тремя способами. Следующие три объекта определяют один и тот же прямоугольник:

wxRect myRect1(50, 60, 100, 200);
wxRect myRect2(wxPoint(50, 60), wxPoint(150, 260));
wxRect myRect3(wxPoint(50, 60), wxSize(100, 200));

wxRegion

Класс wxRegion представляет простую или сложную область на холсте или окне. Данный класс использует технологию подсчета ссылок, а поэтому операции копирования и присваивания выполняются для него очень быстро. В основном wxRegion используется для определения областей отсечения или обновления.

Метод Contains возвращает true, если данная пара координат, wxPoint, прямоугольник или wxRect находятся внутри данной области.

GetBox возвращает объект класса wxRect, представляющий прямоугольник, содержащий область.

Intersect возвращает true, если выбранный прямоугольник wxRect или wxRegion пересекает область.

Offset перемещает область на определенное смещение. Смещение определяется в виде пары координат x и y.

Методы Subtract (вычитание), Union (объединение) или Xor (исключающее или) меняет регион различными способами, предлагая для этого десяток перегруженных функций. У всех этих методов есть версии, принимающие в качестве параметров wxRegion или wxPoint. Обратитесь к документации, чтобы получить полный список доступных методов.

Следующий пример иллюстрирует четыре самых используемых метода инициализации wxRegion. Все следующие строки создают объекты, представляющие одну и ту же область:

wxRegion myRegion1(50, 60, 100, 200);
wxRegion myRegion2(wxPoint(50,60), wxPoint(150, 260));
wxRect myRect(50, 60, 100, 200);
wxRegion myRegion3(myRect);
wxRegion myRegion4(myRegion1);

Можно использовать класс wxRegionIterator, чтобы пройтись по всем прямоугольникам в данной области, например для перерисовки поврежденной области экрана в обработчике соответствующего события, как показано в следующем примере:

// Вызывается когда окно необходимо перерисовать
void MyWindow::OnPaint(wxPaintEvent& event) {
    wxPaintDC dc(this);

    wxRegionIterator upd(GetUpdateRegion());
    while (upd) {
        wxRect rect(upd.GetRect());

        // перерисовываем прямоугольник
        ... тут идет код ...
        upd++;
    }
}

wxSize

Класс wxSize используется внутри wxWidgets для хранения целочисленных размеров окна, элементов управления, объектов на холсте и {т.д.} Данный объект также часто возвращается методами, которые возвращают информацию о размере.

GetHeight и GetWidth возвращают высоту и ширину.

SetHeight и SetWidth принимают целочисленный параметр, определяющий новое значение для высоты или ширины.

Метод Set устанавливает новые параметры для размера.

Объет очень легко создать, указав высоту и ширину:

wxSize mySize(100, 200);

wxVariant

Класс wxVariant является контейнером для любого типа. Значение данного типа может изменяться в процессе выполнения программы, возможно вместе с типом. Этот класс может применяться для уменьшения размера кода в некоторых задачах, таких как редактор различных типов данных или реализации протокола удаленного вызова процедур.

wxVariant может сохранять значения типа bool, char, double, long, wxString, wxArrayString, wxList, wxDateTime, указатель на void и массив wxVariant. Однако, любое приложение может расширить возможности хранения в wxVariant. Для этого необходимо создать наследника от wxVariantData и использовать вариант конструктора класса wxVariant с параметром wxVariantData или оператор присваивания, чтобы присвоить классу wxVariant значение вашего типа. Настоящие значения для пользовательских типов необходимо получать через специальные методы объекта wxVariantData. Это отличается от использования стандартных типов для которых можно вызывать встроенные функции, такие как GetLong.

Помните, что не все типы данных могут быть автоматически преобразованы в другие типы. Например, отсутствует преобразование из логического типа в объект wxDateTime и из целочисленного в wxArrayString. Интуиция должна вам подсказать какого рода преобразования существуют. Вы всегда можете узнать текущий хранимый тип, используя для этого метод GetType. Далее приведен простой пример использования wxVariant:

wxVariant Var;

// Сохраняем wxDateTime и получаем wxString
Var = wxDateTime::Now();
wxString DateAsString = Var.GetString();

// Сохраняем wxString, а получаем вещественное число
Var = wxT("10.25");
double StringAsDouble = Var.GetDouble();

// Тип должен быть "string" (строка)
wxString Type = Var.GetType();

// Это недопустимое преобразование, так как нельзя преобразовать строку
// в число, поэтому метод возвратит 0
char c = Var.GetChar();

Итоги

Структуры данных, существующие в wxWidgets позволяют вам легко передавать/получать структурированные данные в/из библиотеки wxWidgets и внутри своего приложения. Мощные функции и классы для обработки информации, такие как wxRegEx, wxStringTokenizer, wxDateTime и wxVariant покроют большинство ваших потребностей в хранении и обработке данных без привлечения сторонних библиотек.

Далее мы рассмотрим средства, предоставляемые wxWidgets для работы с файлами и потоками.

Leave a Reply

Your email address will not be published. Required fields are marked *

Please leave these two fields as-is: