如何检测 qt 标签(或任何小部件)是不是具有所需的所有空间?
Posted
技术标签:
【中文标题】如何检测 qt 标签(或任何小部件)是不是具有所需的所有空间?【英文标题】:How to detect if a qt label (or any widget) has all the space it would need?如何检测 qt 标签(或任何小部件)是否具有所需的所有空间? 【发布时间】:2021-01-05 10:58:12 【问题描述】:我的小部件在网格布局中有一个长标签,没有任何额外的代码行,它禁止缩小窗口。在this post 我看到设置label1.setMiniumSize(1, 1)
可以再次缩小窗口。但是,如果缩小窗口会切断文本的显示,我想在标签中显示文本的缩写形式。
这是一个例子:
起点:label1.setText("This is a long long long long long long long long label")
显示“This is a long long long long long long long long long long label”并禁止缩小窗口。
添加label1.setMinimumSize(1, 1)
后窗口可以缩小并显示“This is a long lo”
我希望显示“这是……长标签”或“这是一个长……长标签”,以适应标签的实际可用尺寸。
我们能否获取布局管理器希望为标签提供多大尺寸的信息?计算对应的字符数,将文本缩写,并设置新文本?
【问题讨论】:
看看Elided Label Example。 好的,我通读了,但对我来说似乎很复杂......也许我会尝试使用省略的 Qlabel(因为我的只有一行),(即使我更喜欢中间的点)。谢谢你的帮助。我什至不知道英文单词'to elide'...... 关于我什至不知道英文单词'to elide',现在只需要知道正确的关键字来查找信息。 :) 所以,不客气!至于复杂性,它是复杂的,但是你可能会学习这个类,把它放在你的项目中,然后照原样使用它。 我也会尝试让它按你想要的方式工作,敬请期待。 【参考方案1】:您可以使用QFontMetricsF
获取绘制文本所需的QLabel
的大小。相反,您可以覆盖QLabel
的resizeEvent()
以在每次更改大小时获取标签的当前大小,并使您的文本适应它。
QFontMetricsF FM(ui->label->font());
QRectF rect = FM.boundingRect("A Long Long Long Long Text");
double rectWidth = rect.width();
if (rectWidth > ui->label->width())
// Change text and recalculate in a loop if it fits
执行此操作的最佳位置是标签或父小部件的resizeEvent()
。
【讨论】:
谢谢,这看起来比 Elided Label 示例要简单得多。我会尝试将其翻译成 Pyhton 并进行测试。 是的,它工作正常。非常感谢。我会将pyhton版本放在下面的答案中【参考方案2】:使用 Elide 类。
static void SetTextToLabel(QLabel *label, QString text)
QFontMetrics metrix(label->font());
int width = label->width() - 2;
QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
label->setText(clippedText);
只要您想省略文本,就可以通过事件调用此函数。
【讨论】:
也感谢您的回答。由于它更短,对我来说比@Chaitanya 更难理解,但它给了我信息,你可以选择 eldide 模式为ElideMiddle
。我认为最终这将是一个接近理想的快速解决方案,而无需处理缩短文本的细节。【参考方案3】:
有不同的方法来解决这个问题。创建自定义小部件就是其中之一。
所以,我根据您的要求修改了Elided Label Example
:
-
仅支持单行文字
它可以让你通过
ElidedLabel::setElideMode
设置省略模式
这里是文件:
ElidedLabel.h
#ifndef ELIDEDLABEL_H
#define ELIDEDLABEL_H
#include <QFrame>
class ElidedLabelPrivate;
class ElidedLabel : public QFrame
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
Q_PROPERTY(QFlags<Qt::AlignmentFlag> alignment READ alignment
WRITE setAlignment NOTIFY alignmentChanged)
Q_PROPERTY(Qt::TextElideMode elideMode READ elideMode WRITE setElideMode
NOTIFY elideModeChanged)
public:
explicit ElidedLabel(QWidget *parent = nullptr);
explicit ElidedLabel(const QString &text, QWidget *parent = nullptr);
~ElidedLabel();
QString text() const;
void setText(const QString &str);
QFlags<Qt::AlignmentFlag> alignment() const;
void setAlignment(QFlags<Qt::AlignmentFlag> flags);
Qt::TextElideMode elideMode() const;
void setElideMode(Qt::TextElideMode mode);
protected:
void paintEvent(QPaintEvent *event) override;
private:
ElidedLabelPrivate *m_ptr;
signals:
void textChanged();
void alignmentChanged();
void elideModeChanged();
;
#endif // ELIDEDLABEL_H
ElidedLabel_p.h
#ifndef ELIDEDLABEL_P_H
#define ELIDEDLABEL_P_H
#include <Qt>
#include <QString>
class ElidedLabel;
class ElidedLabelPrivate
Q_DISABLE_COPY(ElidedLabelPrivate)
explicit ElidedLabelPrivate();
QString text;
QFlags<Qt::AlignmentFlag> alignment;
Qt::TextElideMode elideMode;
friend class ElidedLabel;
;
#endif // ELIDEDLABEL_P_H
ElidedLabel.cpp
#include "ElidedLabel.h"
#include "ElidedLabel_p.h"
#include <QPaintEvent>
#include <QPainter>
ElidedLabel::ElidedLabel(QWidget *parent) :
QFrame(parent),
m_ptr(new ElidedLabelPrivate)
ElidedLabel::ElidedLabel(const QString &text, QWidget *parent) :
ElidedLabel(parent)
m_ptr->text = text;
ElidedLabel::~ElidedLabel()
delete m_ptr;
QString ElidedLabel::text() const
return m_ptr->text;
void ElidedLabel::setText(const QString &str)
m_ptr->text = str;
update();
emit textChanged();
QFlags<Qt::AlignmentFlag> ElidedLabel::alignment() const
return m_ptr->alignment;
void ElidedLabel::setAlignment(QFlags<Qt::AlignmentFlag> flags)
m_ptr->alignment = flags;
update();
emit alignmentChanged();
Qt::TextElideMode ElidedLabel::elideMode() const
return m_ptr->elideMode;
void ElidedLabel::setElideMode(Qt::TextElideMode mode)
m_ptr->elideMode = mode;
update();
emit elideModeChanged();
void ElidedLabel::paintEvent(QPaintEvent *event)
QFrame::paintEvent(event);
QPainter painter(this);
painter.setPen(QPalette().windowText().color());
painter.setClipRect(event->rect());
painter.setFont(font());
painter.drawText(contentsRect(), m_ptr->alignment | Qt::TextSingleLine,
painter.fontMetrics().elidedText(m_ptr->text,
m_ptr->elideMode,
contentsRect().width(),
1));
ElidedLabelPrivate::ElidedLabelPrivate() :
alignment(Qt::AlignLeft | Qt::AlignVCenter),
elideMode(Qt::ElideRight)
我知道,这代码太多了,而且可能看起来很吓人。然而它的使用并不难。只需将给定的文件添加到您的项目中,然后像使用任何其他小部件一样使用它。
这是一个例子main.cpp
:
#include "ElidedLabel.h"
#include <QApplication>
int main(int argc, char *argv[])
QApplication a(argc, argv);
QFont f = QGuiApplication::font();
f.setPointSize(11);
QGuiApplication::setFont(f);
ElidedLabel label;
label.setText(QObject::tr("Hello Elided World! We have a very very very"
" long one-line text here."));
label.setContentsMargins(10, 10, 10, 10);
label.setElideMode(Qt::ElideMiddle);
label.show();
label.resize(200, 100);
return a.exec();
【讨论】:
【参考方案4】:这是@Chaitanyas 答案的 Python3 版本。
from PyQt5.QtCore import QRectF
from PyQt5.QtGui import QFontMetricsF
class PathLabel(QLabel):
def resizeEvent(self, *args, **kwargs):
font_m = QFontMetricsF(self.font())
text_rect = QRectF(font_m.boundingRect(self.text()))
if text_rect.width() > self.width(): # use shorter text
# just for test: remove ten characters
self.setText(self.text()[:-10])
else: # possibly use longer text
# check if a longer version would fit
pass
稍后在主窗口中:
self.LbFolderName = PathLabel()
这是我现在终于使用的:
class PathLabel(QLabel):
"""Use setLongText instead of setText for a usual label"""
def __init__(self, parent=None):
super(PathLabel, self).__init__(parent)
self.long_text = ""
def make_short_text(self):
# print("make_short_text called")
"""works fine but is not perfect for fnames as the middle is hidden.
-> better hide the middle of the path but not long filenames"""
font_m = QFontMetricsF(self.font()) # F or not ?
avail_width = self.width() - 3 # - 3 px for a little space at the end
short_text = font_m.elidedText(self.long_text, Qt.ElideMiddle, avail_width)
return short_text
def setLongText(self, text_in):
# print("setLongText called")
"""Use this instead of setText for a usual label"""
self.long_text = text_in
self.setToolTip(text_in) # tooltip shows the full text
short_text = self.make_short_text()
self.setText(short_text)
def resizeEvent(self, *args, **kwargs):
#print("resizeEvent called")
short_text = self.make_short_text()
self.setText(short_text)
创建标签后,
lb_folder = PathLabel("File not yet defined")
我打电话
lb_folder.setLongText(full_path_to_file)
【讨论】:
裁剪直到文本适合while text_rect.width() > self.width(): # crop one by one until it fits self.setText(self.text()[:-1]) text_rect = QRectF(font_m.boundingRect(self.text()))
以上是关于如何检测 qt 标签(或任何小部件)是不是具有所需的所有空间?的主要内容,如果未能解决你的问题,请参考以下文章