Воскресенье, 10.01.2021 09:54

Перенос слов на новую строку в подписи - Виджеты в Qt. Часть 7

Перенос слов на новую строку в подписи - Виджеты в Qt. Часть 7

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

Мы будем использовать проект из предыдущей статьи.

Очистка проекта

Сперва очистим проект от лишнего кода и внесем некоторые изменения:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QVBoxLayout *vlay = new QVBoxLayout();

    QHBoxLayout *hlay1 = new QHBoxLayout();

    QLampWidget *lamp1 = new QLampWidget("#557d00","#F00",QLampWidget::on, 32, "2");
    lamp1->setCaption("Left Right Top Bottom");
    lamp1->setCaptionAlign(Qt::TextWordWrap);
    hlay1->addWidget(lamp1);


    QLampWidget *lamp2 = new QLampWidget("#557d00","#F00",QLampWidget::on, 64, "2");
    lamp2->setCaption("Left Right Top Bottom");
    lamp2->setCaptionAlign(Qt::TextWordWrap);
    hlay1->addWidget(lamp2);

    hlay1->addStretch(1);
    vlay->addItem(hlay1);

    QHBoxLayout *hlay3 = new QHBoxLayout();

    QLampWidget *lamp3 = new QLampWidget("#557d00","#F00",QLampWidget::on, 96, "2");
    lamp3->setCaption("Left Right Top Bottom");
    lamp3->setCaptionAlign(Qt::TextWordWrap);
    hlay3->addWidget(lamp3);

    hlay3->addStretch(1);
    vlay->addItem(hlay3);

    QHBoxLayout *hlay4 = new QHBoxLayout();

    QLampWidget *lamp4 = new QLampWidget("#557d00","#F00",QLampWidget::on, 128, "2");
    lamp4->setCaption("Left Right Top Bottom");
    lamp4->setCaptionAlign(Qt::TextWordWrap);
    hlay4->addWidget(lamp4);


    hlay4->addStretch(1);
    vlay->addItem(hlay4);

    vlay->addStretch(1);

    ui->centralwidget->setLayout(vlay);
}

В методе paintEvent() уберем все умножения на *2

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

    painter.setFont(this->captionFont);

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


    QRect r;

    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.setBrush(QBrush(QColor(157,255,252,127)));
    QPen pen;
    pen.setStyle(Qt::DashLine);
    painter.setPen(pen);
    QRect border = QRect(0,this->getLampSize(),
                         this->getLampSize(), heightOfText);
    painter.drawRect(border);

    painter.setPen(QPen(QColor(this->captionColor), 1));
    painter.drawText(0,this->getLampSize(),
                     this->getLampSize(), heightOfText,
                     this->getCaptionAlign(),
                     this->getCaption(),
                     new QRect(0,this->getLampSize(),this->getLampSize(), heightOfText));
}

Запустим:

Изображение удалено.

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

Перенос по словам

У класса QFontMetrics есть метод

QRect QFontMetrics::boundingRect(const QRect &rect, int flags, const QString &text, int tabStops = 0, int *tabArray = nullptr) const

Который возвращает размеры прямоугольника - QRect, в котором поместиться текст - text, нарисованный в прямоугольнике rect, с флагами flag. Параметр tabStops в данном случае, всегда будет равен 0, а tabArray равен nullptr, поэтому мы их не указываем.

Особенность метода состоит в том, что если мы используем флаг Qt::TextWordWrap, то возвращаемый прямоугольник будет автоматически расширен по высоте на нужное количество строк, а это нам и нужно!

Внесем изменения в метод

После

    QFontMetrics metrics(painter.font());

Добавим

    QRect bRect = metrics.boundingRect(QRect(0,0,this->getLampSize(),32),this->getCaptionAlign(),this->getCaption());;

 Изменим строки

int heightOfText  = bRect.height();

и

int widthOfText = bRect.width();

Заменим код

    if (widthOfText > this->getLampSize())
    {
        this->setFixedWidth(widthOfText);
        xPos = widthOfText / 2 - (this->getLampSize()-8) / 2;
    }
    else
    {
        xPos = 4;
        this->setFixedWidth(this->getLampSize());
    }

на

      if (widthOfText > this->getLampSize())
    {
        this->setFixedWidth(bRect.width());
    }
    else
    {
        this->setFixedWidth(this->getLampSize());
    }

Запустим:

Изображение удалено.

На этот раз всё работает как надо. 

Использование Qt::TextWordWrap

Вы можете использовать Qt::TextWordWrap совместно с флагами выравнивания, например у вас может получиться следующее:

    QLampWidget *lamp1 = new QLampWidget("#557d00","#F00",QLampWidget::on, 32, "2");
    lamp1->setCaption("Left Right Top Bottom");
    lamp1->setCaptionAlign(Qt::TextWordWrap | Qt::AlignHCenter | Qt::AlignVCenter);
    hlay1->addWidget(lamp1);

    QLampWidget *lamp2 = new QLampWidget("#557d00","#F00",QLampWidget::on, 64, "2");
    lamp2->setCaption("Left Right Top Bottom");
    lamp2->setCaptionAlign(Qt::TextWordWrap | Qt::AlignRight);
    hlay1->addWidget(lamp2);

    hlay1->addStretch(1);
    vlay->addItem(hlay1);

    QHBoxLayout *hlay3 = new QHBoxLayout();

    QLampWidget *lamp3 = new QLampWidget("#557d00","#F00",QLampWidget::on, 96, "2");
    lamp3->setCaption("Left Right Top Bottom");
    lamp3->setCaptionAlign(Qt::TextWordWrap | Qt::AlignRight);
    hlay3->addWidget(lamp3);

    hlay3->addStretch(1);
    vlay->addItem(hlay3);

    QHBoxLayout *hlay4 = new QHBoxLayout();

    QLampWidget *lamp4 = new QLampWidget("#557d00","#F00",QLampWidget::on, 128, "2");
    lamp4->setCaption("Left Right Top Bottom");
    lamp4->setCaptionAlign(Qt::TextWordWrap | Qt::AlignCenter);
    hlay4->addWidget(lamp4);

Запустим:

Изображение удалено.

Заключение

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

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

Категория Виджеты

Добавить комментарий

Простой текст

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Строки и абзацы переносятся автоматически.
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.
Просмотров: 248