如何检测 qt 标签(或任何小部件)是否具有所需的所有 space?
How to detect if a qt label (or any widget) has all the space it would need?
我的小部件在网格布局中有一个长标签,没有任何额外的代码行,禁止缩小 window。在 this post 中,我看到设置 label1.setMiniumSize(1, 1)
可以再次缩小 window。但是,如果缩小 windows 会减少文本的显示,我想在标签中显示文本的缩写形式。
这是一个例子:
-
起点:label1.setText("This is a long long long long long long long long label")
显示“这是一个长长的长长长长标签”,并抑制window的收缩。
添加label1.setMinimumSize(1, 1)
后window可以缩小显示“This is a long lo”
我想要显示“This is ... ong label”或“This is a long ... long label”,以适应标签的实际可用尺寸。
我们能否捕捉到布局管理器想要赋予标签的大小的信息?计算对应的字符数,将文本缩写,并设置新的文本?
您可以使用 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()
中。
使用省略号Class。
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);
}
每当您想删除文本时,调用此函数和事件。
有多种方法可以解决这个问题。创建自定义小部件就是其中之一。
所以,我已经根据您的规格修改了 Elided Label Example
:
- 仅支持one-line文本
- 它允许您通过
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();
}
这是@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)
我的小部件在网格布局中有一个长标签,没有任何额外的代码行,禁止缩小 window。在 this post 中,我看到设置 label1.setMiniumSize(1, 1)
可以再次缩小 window。但是,如果缩小 windows 会减少文本的显示,我想在标签中显示文本的缩写形式。
这是一个例子:
-
起点:
label1.setText("This is a long long long long long long long long label")
显示“这是一个长长的长长长长标签”,并抑制window的收缩。 添加
label1.setMinimumSize(1, 1)
后window可以缩小显示“This is a long lo”我想要显示“This is ... ong label”或“This is a long ... long label”,以适应标签的实际可用尺寸。
我们能否捕捉到布局管理器想要赋予标签的大小的信息?计算对应的字符数,将文本缩写,并设置新的文本?
您可以使用 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()
中。
使用省略号Class。
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);
}
每当您想删除文本时,调用此函数和事件。
有多种方法可以解决这个问题。创建自定义小部件就是其中之一。
所以,我已经根据您的规格修改了 Elided Label Example
:
- 仅支持one-line文本
- 它允许您通过
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();
}
这是@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)