БлогNot. Qt: делаем календарь в таблице QTextTable

Qt: делаем календарь в таблице QTextTable

Вообще-то в Qt5 есть готовый виджет Calendar, котрый можно кинуть на форму, созданную на основе QWidget, затем щелкнуть по форме вне виджета

, нажать Ctrl+H, чтобы его растянуть по форме, потом нажать Ctrl+R - и приложение готово:

Увы, табличку в документ Word отсюда не скопируешь, да и непонятно, как не показывать дни соседнего месяца в первой или последней неделе текущего.

Намного ли сложнее сделать такое вручную? Давайте попробуем, заодно посмотрев полезные приёмы работы с таблицей QTextTable, её ячейками QTextTableCell и форматами QTextCharFormat, QTextBlockFormat (полный аналог - форматы строчного и блочного элементов HTML). Да и вообще, логика работы с таблицей QTextTable такая же, как с разметкой HTML.

Таблицу мы делаем просто из ячеек с цифрами, её можно будет выделить, скопировать, и затем вставить в тот же Word.

Виджет основан на QMainWindow, описание класса очень просто (файл mainwindow.h):

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QDate>
#include <QMainWindow>

class QTextBrowser;

class MainWindow : public QMainWindow {
 Q_OBJECT
 public:
  MainWindow();
 public slots:
  void setFontSize(int size); //выбор шрифта
  void setMonth(int month); //выбор месяца
  void setYear(QDate date); //выбор года
 private:
  void insertCalendar();
  int fontSize;
  QDate selectedDate;
  QTextBrowser *editor;
};

#endif

Основные действия в реализации класса mainwindow.cpp закомментированы:

#include <QtWidgets>
#include "mainwindow.h"

MainWindow::MainWindow() { //конструктор
 selectedDate = QDate::currentDate();
 fontSize = 10;

 QWidget *centralWidget = new QWidget;

 QLabel *dateLabel = new QLabel(tr("Дата:"));
 QComboBox *monthCombo = new QComboBox;
 for (int month = 1; month <= 12; ++month)
  monthCombo->addItem(QDate::longMonthName(month));
 QDateTimeEdit *yearEdit = new QDateTimeEdit;
 yearEdit->setDisplayFormat("yyyy");
 yearEdit->setDateRange (QDate(1918, 1, 1), QDate(9998, 1, 1));
 monthCombo->setCurrentIndex (selectedDate.month() - 1);
 yearEdit->setDate (selectedDate);

 QLabel *fontSizeLabel = new QLabel(tr("Шрифт:"));
 QSpinBox *fontSizeSpinBox = new QSpinBox;
 fontSizeSpinBox->setRange(6, 72);
 fontSizeSpinBox->setValue(10);

 editor = new QTextBrowser; //компонента для календаря
 insertCalendar(); //главный метод

 connect(monthCombo, SIGNAL(activated(int)), this, SLOT(setMonth(int)));
 connect(yearEdit, SIGNAL(dateChanged(QDate)), this, SLOT(setYear(QDate)));
 connect(fontSizeSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setFontSize(int)));

 QHBoxLayout *horizontalLayout = new QHBoxLayout; //панель навигации
 horizontalLayout->addWidget(dateLabel);
 horizontalLayout->addWidget(monthCombo);
 horizontalLayout->addWidget(yearEdit);
 horizontalLayout->addSpacing(20);
 horizontalLayout->addWidget(fontSizeLabel);
 horizontalLayout->addWidget(fontSizeSpinBox);
 horizontalLayout->addStretch(1);

 QVBoxLayout *centralLayout = new QVBoxLayout;
 centralLayout->addLayout(horizontalLayout);
 centralLayout->addWidget(editor, 1);

 centralWidget->setLayout(centralLayout);
 setCentralWidget(centralWidget);
}

void MainWindow::insertCalendar() {
 editor->clear(); //очистить
 QTextCursor cursor = editor->textCursor();
 cursor.beginEditBlock(); //создать курсор и поставить в начало

 QDate date(selectedDate.year(), selectedDate.month(), 1);
  //создать дату - 1-е число выбранного в панели месяца

 QTextTableFormat tableFormat; //создать формат таблицы
 tableFormat.setAlignment(Qt::AlignHCenter); //выравнивание
 tableFormat.setBackground(QColor("#EEEEEE")); //фоновый цвет
 tableFormat.setCellPadding(4); //отступ от края ячейки
 tableFormat.setCellSpacing(0); //промежуток между ячейками
 QVector <QTextLength> constraints; //7 столбцов по 15% шириной
 constraints << QTextLength(QTextLength::PercentageLength, 15)
             << QTextLength(QTextLength::PercentageLength, 15)
             << QTextLength(QTextLength::PercentageLength, 15)
             << QTextLength(QTextLength::PercentageLength, 15)
             << QTextLength(QTextLength::PercentageLength, 15)
             << QTextLength(QTextLength::PercentageLength, 15)
             << QTextLength(QTextLength::PercentageLength, 15);
 tableFormat.setColumnWidthConstraints(constraints);

 QTextTable *table = cursor.insertTable(1, 7, tableFormat);
  //создать таблицу из 1 строки и 7 описанных выше столбцов

 QTextCharFormat format = cursor.charFormat(); //общий формат
 format.setFontPointSize(fontSize); //поставить размер шрифта

 QTextCharFormat boldFormat = format;
 boldFormat.setFontWeight(QFont::Bold); //жирный

 QTextCharFormat highlightedFormat = boldFormat;
 highlightedFormat.setBackground(Qt::yellow); //подсвеченный жёлтым

 QTextBlockFormat centerAlignment; //равнять по центру
 centerAlignment.setAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
 QTextBlockFormat rightAlignment; //равнять направо
 rightAlignment.setAlignment(Qt::AlignRight);

 for (int weekDay = 0; weekDay < 7; weekDay++) { //подписи дней недели
  QTextTableCell cell = table->cellAt(0, weekDay); //в нулевой строке
  QTextCursor cellCursor = cell.firstCursorPosition();
  cellCursor.setBlockFormat(centerAlignment);
  cellCursor.insertText(QString("%1").
   arg(QDate::longDayName(weekDay+1)),boldFormat);
 }

 table->insertRows(table->rows(), 1); //вставить подписи

 while (date.month() == selectedDate.month()) { //для текущего месяца
  int weekDay = date.dayOfWeek(); //1=Пн, ...,  7 =Вс
  QTextTableCell cell = table->cellAt(table->rows()-1, weekDay-1);
  QTextCursor cellCursor = cell.firstCursorPosition();
  cellCursor.setBlockFormat(rightAlignment);
  //текущую дату - желтым, иначе обычным
  if (date == QDate::currentDate())
   cellCursor.insertText(QString("%1").arg(date.day()), highlightedFormat);
  else
   cellCursor.insertText(QString("%1").arg(date.day()), format);
  date = date.addDays(1); //следующий день
  if (weekDay == 7 && date.month() == selectedDate.month())
   table->insertRows(table->rows(), 1); //добавить строчку, если пора
 }

 cursor.endEditBlock(); //завершить редактирование
 setWindowTitle(tr("Календарь на %1 %2"). //титул окна
  arg(QDate::longMonthName(selectedDate.month())).
  arg(selectedDate.year()));
}

 void MainWindow::setFontSize(int size) {
  fontSize = size;
  insertCalendar();
 }

 void MainWindow::setMonth(int month) {
  selectedDate = QDate(selectedDate.year(), month + 1, selectedDate.day());
  insertCalendar();
 }

 void MainWindow::setYear(QDate date) {
  selectedDate = QDate(date.year(), selectedDate.month(), selectedDate.day());
  insertCalendar();
 }

Вот что вышло. Это можно масштабировать и т.д.

вид окна приложения
вид окна приложения

 Скачать этот пример в архиве .zip с проектом Qt 5.X (4 Кб)

06.04.2016, 12:54 [11222 просмотра]


теги: c++ программирование дата qt

К этой статье пока нет комментариев, Ваш будет первым