简体   繁体   English

动态调整两个QLabel实现的大小

[英]Dynamically resizing two QLabel implementations

I'm trying to create a simple frame in Qt with a tick and some text. 我试图在Qt中创建一个带有刻度和一些文本的简单框架。 I made two new label implementations because I wanted the labels to dynamically fill all the available space but when I resize the window the sizes are off, as shown by the qDebug output, which represents the size of the image label: 我做了两个新的标签实现,因为我希望标签能够动态填充所有可用空间,但是当我调整窗口大小时,其大小已关闭,如qDebug输出所示,它代表图像标签的大小:

Resized:  244 ,  244 <-- Window first created
Resized:  305 ,  305 <-- Window maximized
Resized:  135 ,  135 <-- Window restored to original size

As you can see, when the window is restored to its original size the image is not. 如您所见,当窗口恢复到其原始大小时,图像不是。 The last size should be 244, 244. 最后的大小应为244、244。

The code which describes the behaviour of the two widgets is the following: 描述两个小部件行为的代码如下:

"widgets.h": “ widgets.h”:

    /*
 * This file includes many custom widgets.
 */

#ifndef APOCRYPHA_WIDGETS
#define APOCRYPHA_WIDGETS

#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <QPixmap>
#include <QResizeEvent>
#include <QPaintEvent>

class AutoTextLabel : public QLabel {

    Q_OBJECT

public:
    explicit AutoTextLabel(QWidget* parent);
    AutoTextLabel(QWidget* parent, QString text);

protected:
    void resizeEvent(QResizeEvent* event) override;

private:
    QTimer* resizeTimer;

private slots:
    void onResizeEnd();

};

class AutoImageLabel : public QLabel {

    Q_OBJECT

public:
    explicit AutoImageLabel(QWidget* parent);
    AutoImageLabel(QWidget* parent, const QPixmap& pixmap);
    void setFillOrientation(int orientation);
    QSize sizeHint() const override;

public slots:
    void setPixmap(const QPixmap &newPix);
    void resizeEvent(QResizeEvent* event) override;


protected:
//    void paintEvent(QPaintEvent* event) override;

private:
    int fillOrientation;

    int widthForHeight(int h) const;
    int heightForWidth(int w) const override;
    QPixmap scaledPixmap() const;

    QPixmap labelPixmap;

};

#endif //APOCRYPHA_WIDGETS

"widgets.cpp": “ widgets.cpp”:

/*
 * This file includes many custom widgets.
 */

#include "widgets.h"
#include <QPainter>
#include <QDebug>


AutoTextLabel::AutoTextLabel(QWidget *parent, QString text) : QLabel(text, parent){

    // Enable antialiasing
    QFont aaFont(font());
    aaFont.setStyleStrategy(QFont::PreferAntialias);
    setFont(aaFont);

    // This timer is used to fire a slot when a window is resized
    resizeTimer = new QTimer();
    resizeTimer->setSingleShot(true);
    connect(resizeTimer, SIGNAL(timeout()), SLOT(onResizeEnd()));

}

AutoTextLabel::AutoTextLabel(QWidget *parent) : AutoTextLabel(parent, "") {}

void AutoTextLabel::resizeEvent(QResizeEvent *event) {
    QWidget::resizeEvent(event);

    // Only fire when 25ms have passed since the last resize.
    resizeTimer->start(25);
}

void AutoTextLabel::onResizeEnd() {

    QFont updatedFont(font());

    // Resize Text
    if (!text().isEmpty()){

        int fontSize = 1;

        updatedFont.setPixelSize(fontSize);
        QRect boundingRectangle;

        // Update bounding rectangle
        if (wordWrap())
            boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
        else
            boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());

        while (boundingRectangle.height() <= contentsRect().height()) {
            fontSize++;
            updatedFont.setPixelSize(fontSize);

            // Update bounding rectangle
            if (wordWrap())
                boundingRectangle = QFontMetrics(updatedFont).boundingRect(contentsRect(), Qt::TextWordWrap, text());
            else
                boundingRectangle = QFontMetrics(updatedFont).boundingRect(text());

        }

        updatedFont.setPixelSize(fontSize - 1);
        setFont(updatedFont);

    }

}

/* Auto Image Label */

AutoImageLabel::AutoImageLabel(QWidget *parent, const QPixmap &pixmap) : QLabel(parent) {
    setMinimumSize(1, 1);
    setScaledContents(false);
    setPixmap(pixmap);
}

AutoImageLabel::AutoImageLabel(QWidget *parent) : QLabel(parent) {
    setScaledContents(false);
}

void AutoImageLabel::resizeEvent(QResizeEvent *event) {
    QWidget::resizeEvent(event);

    if(!labelPixmap.isNull())
        QLabel::setPixmap(scaledPixmap());
    qDebug() << "Resized: " << scaledPixmap().width() << ", " << scaledPixmap().height();

}

int AutoImageLabel::widthForHeight(int h) const {
    return labelPixmap.isNull() ? width() : (labelPixmap.width() * h) / labelPixmap.height();
}

int AutoImageLabel::heightForWidth(int w) const {
    return labelPixmap.isNull() ? height() : (labelPixmap.height() * w) / labelPixmap.width();
}

void AutoImageLabel::setFillOrientation(int orientation) {
    this->fillOrientation = orientation;
}

QSize AutoImageLabel::sizeHint() const {

    if (fillOrientation == Qt::Horizontal)
        return QSize(width(), heightForWidth(width()));
    else
        return QSize(widthForHeight(height()), height());
}

QPixmap AutoImageLabel::scaledPixmap() const {
    return labelPixmap.scaled(sizeHint(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
}

void AutoImageLabel::setPixmap(const QPixmap &newPix) {
    labelPixmap = newPix;
    QLabel::setPixmap(scaledPixmap());
}

"other_frames.h": “ other_frames.h”:

//
// Created by Riccardo on 18/09/2017.
//

#ifndef APOCRYPHA_OTHER_FRAMES_H
#define APOCRYPHA_OTHER_FRAMES_H

#include <QFrame>
#include <QLabel>
#include <QGridLayout>
#include <QWidget>
#include <QResizeEvent>
#include <QPixmap>
#include <QTimer>
#include "widgets.h"

class ConfirmationFrame : public QFrame {

    Q_OBJECT

public:
    explicit ConfirmationFrame(QWidget* parent);
    ConfirmationFrame(QWidget* parent, const QString& text);

private:

    QGridLayout* layout;

    AutoImageLabel* imageLabel;
    AutoTextLabel* textLabel;

};

#endif //APOCRYPHA_OTHER_FRAMES_H

"other_frames.cpp": “ other_frames.cpp”:

//
// Created by Riccardo on 18/09/2017.
//

#include "other_frames.h"
#include <QDebug>

ConfirmationFrame::ConfirmationFrame(QWidget* parent, const QString &text) : QFrame(parent) {

    textLabel = new AutoTextLabel(this, text);

    QPixmap pix(":/images/check-tick.png");
    imageLabel = new AutoImageLabel(this, pix);

    textLabel->setAlignment(Qt::AlignCenter);
    imageLabel->setAlignment(Qt::AlignCenter);

    textLabel->setWordWrap(true);

    // Green Background
    setStyleSheet("background-color: rgba(106, 242, 94, 1);");

    layout = new QGridLayout();
    layout->setSpacing(0);
    layout->setContentsMargins(32, 32, 32, 32);
    layout->setRowStretch(0, 1);
    layout->setRowStretch(1, 1);

    layout->addWidget(imageLabel, 0, 1);
    layout->addWidget(textLabel, 1, 1);

    setLayout(layout);

}

ConfirmationFrame::ConfirmationFrame(QWidget *parent) : ConfirmationFrame(parent, "") {
}

"window_main.h": “ window_main.h”:

#ifndef WINDOW_MAIN_H
#define WINDOW_MAIN_H

#include <QMainWindow>
#include <QMenuBar>
#include <QMenu>
#include <QGridLayout>
#include <QFrame>
#include <QScreen>

class MainWindow : public QMainWindow {

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);

    QFrame *mainFrame;

    void center(QScreen* screen);
    void autoSetSize(QScreen* screen);

private:
    void createMenu();

    // Components
    QGridLayout *mainLayout;
    QMenuBar *menuBar;
    QMenu *fileMenu;


};

#endif // WINDOW_MAIN

"window_main.cpp": “ window_main.cpp”:

#include "window_main.h"


MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
    mainFrame = new QFrame();
    mainLayout = new QGridLayout();

    mainLayout->setSpacing(0);
    mainLayout->setContentsMargins(0, 0, 0, 0);

    createMenu();

    mainFrame->setStyleSheet("background-color: red;");
    mainFrame->setLayout(mainLayout);
    setCentralWidget(mainFrame);

}

void MainWindow::createMenu(){
    menuBar = new QMenuBar;
    fileMenu = new QMenu(tr("&File"), this);
    menuBar->addMenu(fileMenu);
    setMenuBar(menuBar);
}

void MainWindow::center(QScreen *screen) {
    QSize size = screen->availableSize();
    int x = size.width() / 2 - width() / 2;
    int y = size.height() / 2 - height() / 2;
    move(x, y);
}

void MainWindow::autoSetSize(QScreen *screen) {
    QSize screenSize = screen->availableSize();
    // TODO Math.round
    setMinimumSize(QSize((int)(screenSize.width() / 1.25), (int)(screenSize.height() / 1.25)));
}

"main.cpp": “ main.cpp”:

#include <QApplication>
#include <iostream>
#include <QFile>
#include "quiz/choice.h"
#include "quiz/question.h"
#include "quiz/quizmaker.h"
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <src/user_interface/other_frames.h>
#include "user_interface/window_main.h"
#include <QScreen>
#include <QFontDatabase>

int main(int argc, char *argv[]) {

    QApplication a(argc, argv);

    // Set Application Parameters
    QCoreApplication::setOrganizationName("Riccardo Fagiolo");
    QCoreApplication::setOrganizationDomain("kopharex.me");
    QCoreApplication::setApplicationName("Apocrypha");

    // Set application font
    const int id = QFontDatabase::addApplicationFont(":/fonts/montserrat/Montserrat-Regular.otf");
    QString family = QFontDatabase::applicationFontFamilies(id).at(0);
    QFont font(family);
    font.setStyleStrategy(QFont::PreferAntialias);
    a.setFont(font);

    // App Settings
    QSettings settings;
    settings.setValue("data_dir", QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));

    // Create UI
    auto* window = new MainWindow();

    ConfirmationFrame* cframe = new ConfirmationFrame(window, "But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful. Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?");
    window->mainFrame->layout()->addWidget(cframe);

    window->autoSetSize(a.primaryScreen());
    //cframe->updateTextLabel();
    window->show();
    window->center(a.primaryScreen());

    // [...] - Nothing related to user interface.

    return a.exec();

}

Here is a screenshot of the current MainWindow and ConfirmationFrame to give you an idea of what i'm trying to accomplish: 这是当前MainWindow和ConfirmationFrame的屏幕截图,可让您大致了解我要完成的工作:

Window Screenshot 窗口截图

All comments regarding the code are welcome. 欢迎提供有关代码的所有注释。

Thanks for any help, 谢谢你的帮助,

Riccardo 里卡多

Hello I tried to fix the resizing issue with an hack. 您好,我尝试通过黑客解决调整大小的问题。 Before starting the timer to resize the text, just reduce its font to a 1 pixel font: 在启动计时器调整文本大小之前,只需将其字体减小为1像素字体即可:

void AutoTextLabel::resizeEvent(QResizeEvent *event) {
    QWidget::resizeEvent(event);

    // set a very small font, then start the timer
    QFont updatedFont(font());
    updatedFont.setPixelSize(1);
    setFont(updatedFont);
    // Only fire when 25ms have passed since the last resize.
    resizeTimer->start(25);
}

Can the effect be acceptable in your opinion? 您认为效果可以接受吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM