Добавляем подпись для лампочки - Виджеты (компоненты) в Qt5. - АлтунинВВ.Блог - всё об IT-технологиях!
Среда, 06 января 2021 12:45

Добавляем подпись для лампочки - Виджеты (компоненты) в Qt5.

Россия
Оцените материал
(0 голосов)

Сегодня мы будем расширять функционал нашего виджета. На этот раз мы добавим подпись под нашей лампочкой, для работы будет использован проект из предыдущей статьи.

Очищаем и оптимизируем код

Для начала добавим поля для размеров самой лампочки, для этого добавим новое поле класса виджета:

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());

Запустим:

2021-01-05_20-10-59.png

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

Давайте это исправим – в paintEvent(), после строки:

QPainter painter(this);

добавим 

    QFontMetrics metrics(painter.font());

    int heightOfText  = metrics.height();

    this->setFixedHeight(this->getLampSize()+heightOfText);

И немного опустим текст:

painter.drawText(QPoint(0,40),"Caption");

Запустим:

2021-01-05_20-13-24.png

Уже лучше, но надпись не помещается по ширине, давайте это исправим – добавим, под только что добавленными строчками:

    int widthOfText = metrics.horizontalAdvance("Caption");

    this->setFixedWidth(widthOfText);

 Запустим:

2021-01-05_20-16-57.png

Вроде неплохо, но если мы увеличим размер надписи, то получим следующее:

2021-01-05_20-17-52.png

Наша лампочка не выравнивается, относительно текста, давайте исправим и это:

    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());

}

Запустим:

2021-01-05_21-12-35.png

На этот раз всё отображается правильно.

Меняем текст подписи

До сих пор мы использовали фиксированную подпись, давайте добавим возможность задавать произвольный текст.

Добавим поле класса и сеттер/геттер для текста:

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");

Запустим:

2021-01-05_21-20-00.png

Кнопка без метки не отрисовывается! Почему? Все очень просто – при вычислении ширины виджета мы используем ширину текста, а если текста нет, или текст меньше размеров лампы, виджет не отображается или отрисовывается неправильно.

Давайте это исправим:

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());

}

Запустим:

2021-01-05_21-31-16.png

Здесь мы проверяем ширину текста и если она больше, чем размер лампы – вычисляем координаты, если меньше – отрисовываем как раньше, без надписи.

Заключение 

Сегодня мы добавили для лампочки подпись.

Добавили поле для хранения размера самой лампочки и методы для доступа к этим размерам.

Добавили подпись для лампочки, поле и методы для доступа к тексту подписи.

Реализовали механизм, автоматически изменяющий ширину виджета, если надпись шире, чем сама лампочка.

Добавили функционал позволяющий отрисовывать лампочку без текста.

В следующей статье мы доработаем подпись – добавим методы для изменения цвета, шрифта и размера шрифта надписи.

Исходный код проекта вы можете найти на Github.

Прочитано 103 раз Последнее изменение Среда, 13 января 2021 12:12