
Добавляем подпись для лампочки - Виджеты в Qt. Часть 4
Сегодня мы будем расширять функционал нашего виджета. На этот раз мы добавим подпись под нашей лампочкой, для работы будет использован проект из предыдущей статьи.
Очищаем и оптимизируем код
Для начала добавим поля для размеров самой лампочки, для этого добавим новое поле класса виджета:
private:
int lampSize;
Добавим геттер и сеттер:
int QLampWidget::getLampSize() const
{
return lampSize;
}
void QLampWidget::setLampSize(int value)
{
lampSize = value;
this->setFixedWidth(value);
this->setFixedHeight(value);
}
Так как лампочка у нас круглая, нам достаточно одной переменной, для указания размера.
Внесем изменения в метод paintEvent()
void QLampWidget::paintEvent(QPaintEvent *event)
{
installEventFilter(this);
QString onColor = this->color;
QColor mainColorOn = QColor(onColor);
QColor subColorOn = QColor(onColor);
subColorOn.setHsl(0,100,95,0);
QString aoffColor = this->offColor;
QColor mainColorOff = QColor(aoffColor);
QColor subColorOff = QColor(aoffColor);
subColorOff.setHsl(0,100,95,0);
QLinearGradient linearGrad(QPointF(4, 4), QPointF(this->getLampSize()-4, this->getLampSize()-4));
if (this->getStatus()==QLampWidget::on)
{
linearGrad.setColorAt(0, subColorOn);
linearGrad.setColorAt(1, mainColorOn);
} else {
linearGrad.setColorAt(0, subColorOff);
linearGrad.setColorAt(1, mainColorOff);
}
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor("#f00"), 0.1));
painter.setBrush(linearGrad);
painter.drawEllipse(QRectF(4,4,this->getLampSize()-8,this->getLampSize()-8));
}
С прошлых статей у нас осталось слишком много конструкторов, давайте сократим их количество:
QLampWidget::QLampWidget(QWidget *parent)
{
this->setParent(parent);
this->setLampSize(32);
this->setStatus(QLampWidget::on);
this->color = "#f00";
this->offColor = "#808080";
}
QLampWidget::QLampWidget()
{
this->setLampSize(32);
this->setStatus(QLampWidget::on);
this->color = "#f00";
this->offColor = "#808080";
}
QLampWidget::QLampWidget(QString color, QString offcolor, int status, int size, QString id)
{
this->setLampSize(size);
this->color = color;
this->offColor = offcolor;
this->setStatus(status);
this->setProperty("id",id);
}
Внесем изменения в конструктор главной формы – изменим код создания наших лампочек:
lamp = new QLampWidget("#557d00","#F00",QLampWidget::on, 32, "1");
lamp2 = new QLampWidget("#557d00","#F00",QLampWidget::off, 32, "2");
Запустим и проверим, что всё работает, как и раньше.
Добавляем надпись
Добавим в метод paintEvent() строки
painter.drawText(QPoint(0,36),"Caption");
painter.setBrush(QColor(Qt::transparent));
painter.setPen(QPen(QColor("#00f"), 1));
painter.drawRect(0,0,this->rect().width(),this->rect().height());
Запустим:
Как видите текст хоть и появился, но размеры виджета что по высоте, что по ширине не позволяют ему нормально отобразиться.
Давайте это исправим – в paintEvent(), после строки:
QPainter painter(this);
добавим
QFontMetrics metrics(painter.font());
int heightOfText = metrics.height();
this->setFixedHeight(this->getLampSize()+heightOfText);
И немного опустим текст:
painter.drawText(QPoint(0,40),"Caption");
Запустим:
Уже лучше, но надпись не помещается по ширине, давайте это исправим – добавим, под только что добавленными строчками:
int widthOfText = metrics.horizontalAdvance("Caption");
this->setFixedWidth(widthOfText);
Запустим:
Вроде неплохо, но если мы увеличим размер надписи, то получим следующее:
Наша лампочка не выравнивается, относительно текста, давайте исправим и это:
painter.drawEllipse(QRectF(widthOfText / 2 - (this->getLampSize()-8) / 2, 4,this->getLampSize()-8,this->getLampSize()-8));
В данном случае мы сначала находим середину подписи, а потом вычитаем реальный размер лампочки деленный на 2. На самом деле наша лампочка на 8 пикселов меньше, это необходимо, чтобы изображение не обрезалось у края виджета.
Так же нам нужно исправить градиент, после всех правок метод изменился:
void QLampWidget::paintEvent(QPaintEvent *event)
{
QString onColor = this->color;
QColor mainColorOn = QColor(onColor);
QColor subColorOn = QColor(onColor);
subColorOn.setHsl(0,100,95,0);
QString aoffColor = this->offColor;
QColor mainColorOff = QColor(aoffColor);
QColor subColorOff = QColor(aoffColor);
subColorOff.setHsl(0,100,95,0);
QPainter painter(this);
QFontMetrics metrics(painter.font());
int heightOfText = metrics.height();
this->setFixedHeight(this->getLampSize()+heightOfText);
int widthOfText = metrics.horizontalAdvance("Caption 1234567890");
this->setFixedWidth(widthOfText);
QLinearGradient linearGrad(
QPointF(widthOfText / 2 - (this->getLampSize()-8) / 2,
4),
QPointF(widthOfText / 2 - (this->getLampSize()-8) / 2 + this->getLampSize()-8,
this->getLampSize()-8));
if (this->getStatus()==QLampWidget::on)
{
linearGrad.setColorAt(0, subColorOn);
linearGrad.setColorAt(1, mainColorOn);
} else {
linearGrad.setColorAt(0, subColorOff);
linearGrad.setColorAt(1, mainColorOff);
}
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor("#f00"), 0.1));
painter.setBrush(linearGrad);
painter.drawEllipse(
QRectF(widthOfText / 2 - (this->getLampSize()-8) / 2, 4,
this->getLampSize()-8, this->getLampSize()-8));
painter.drawText(QPoint(0,40),"Caption 1234567890");
painter.setBrush(QColor(Qt::transparent));
painter.setPen(QPen(QColor("#00f"), 1));
painter.drawRect(0,0,this->rect().width(),this->rect().height());
}
Запустим:
На этот раз всё отображается правильно.
Меняем текст подписи
До сих пор мы использовали фиксированную подпись, давайте добавим возможность задавать произвольный текст.
Добавим поле класса и сеттер/геттер для текста:
private:
QString caption;
QString QLampWidget::getCaption() const
{
return caption;
}
void QLampWidget::setCaption(const QString &value)
{
caption = value;
repaint();
}
Изменим метод paintEvent() – изменив строки
int widthOfText = metrics.horizontalAdvance("Caption 1234567890");
painter.drawText(QPoint(0,40),"Caption 1234567890");
на
int widthOfText = metrics.horizontalAdvance(this->getCaption());
painter.drawText(QPoint(0,40),this->getCaption());
добавим в конструктор главной формы строку:
lamp2->setCaption("Caption 1234567890");
Запустим:
Кнопка без метки не отрисовывается! Почему? Все очень просто – при вычислении ширины виджета мы используем ширину текста, а если текста нет, или текст меньше размеров лампы, виджет не отображается или отрисовывается неправильно.
Давайте это исправим:
void QLampWidget::paintEvent(QPaintEvent *event)
{
installEventFilter(this);
QString onColor = this->color;
QColor mainColorOn = QColor(onColor);
QColor subColorOn = QColor(onColor);
subColorOn.setHsl(0,100,95,0);
QString aoffColor = this->offColor;
QColor mainColorOff = QColor(aoffColor);
QColor subColorOff = QColor(aoffColor);
subColorOff.setHsl(0,100,95,0);
QPainter painter(this);
QFontMetrics metrics(painter.font());
int heightOfText = metrics.height();
this->setFixedHeight(this->getLampSize()+heightOfText);
int widthOfText = metrics.horizontalAdvance(this->getCaption());
float xPos = 0;
if (widthOfText > this->getLampSize())
{
this->setFixedWidth(widthOfText);
xPos = widthOfText / 2 - (this->getLampSize()-8) / 2;
}
else
{
xPos = 4;
this->setFixedWidth(this->getLampSize());
}
QLinearGradient linearGrad(
QPointF(xPos,
4),
QPointF(xPos + this->getLampSize()-8,
this->getLampSize()-8));
if (this->getStatus()==QLampWidget::on)
{
linearGrad.setColorAt(0, subColorOn);
linearGrad.setColorAt(1, mainColorOn);
} else {
linearGrad.setColorAt(0, subColorOff);
linearGrad.setColorAt(1, mainColorOff);
}
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor("#f00"), 0.1));
painter.setBrush(linearGrad);
painter.drawEllipse(
QRectF(xPos, 4,
this->getLampSize()-8, this->getLampSize()-8));
painter.drawText(QPoint(0,40),this->getCaption());
painter.setBrush(QColor(Qt::transparent));
painter.setPen(QPen(QColor("#00f"), 1));
painter.drawRect(0,0,this->rect().width(),this->rect().height());
}
Запустим:
Здесь мы проверяем ширину текста и если она больше, чем размер лампы – вычисляем координаты, если меньше – отрисовываем как раньше, без надписи.
Заключение
Сегодня мы добавили для лампочки подпись.
Добавили поле для хранения размера самой лампочки и методы для доступа к этим размерам.
Добавили подпись для лампочки, поле и методы для доступа к тексту подписи.
Реализовали механизм, автоматически изменяющий ширину виджета, если надпись шире, чем сама лампочка.
Добавили функционал позволяющий отрисовывать лампочку без текста.
В следующей статье мы доработаем подпись – добавим методы для изменения цвета, шрифта и размера шрифта надписи.
Исходный код проекта вы можете найти на GitFlic.
Добавить комментарий