QPainter 忽略 paintEvent 内部的裁剪
QPainter ignores clipping inside paintEvent
我正在尝试在 QPushButton
下方(按钮边界之外)每当它获得焦点时绘制文本。为此,我对 QPushButton
进行了子类化,并且我在 QPushButton
的重写 paintEvent
方法中使用 QPainter
drawText 方法绘制文本。在绘制之前,我设置 QPainter::setClipping(false)
以启用绘制侧边按钮边界的文本。但是不知何故 QPainter::setClipping(false)
不起作用,文本没有绘制到按钮边界之外。
painter的paint engine本身在底层实现了裁剪,widget painter默认是不裁剪的。换句话说:不可能关闭此剪辑。以下成立:
void Class::paintEvent(QPaintEvent *ev) {
Parent::paintEvent(ev);
QPainter p(this);
Q_ASSERT(!p.hasClipping());
// and now you do:
p.setClipping(false); // this is a no-op!
}
一个简单的解决方案是添加一个将文本绘制为按钮同级的小部件,并将其定位在按钮下方。该小部件可以是 QLabel
.
static const char kLabelSibling[] = "qq_labelSibling";
static const char kTrackedSibling[] = "qq_trackedSibling";
void setTextBelow(QWidget *widget, const QString &text) {
Q_ASSERT(widget->parent);
class Filter : QObject {
static QLabel *getLabel(QObject *sibling) {
return widget->property(kLabelSibling).value<QLabel*>();
}
static void updateLabel(QWidget *label) {
auto *sibling = label->property(kTrackedSibling).value<QWidget*>();
Q_ASSERT(sibling);
label->setParent(sibling->parent());
label->move(sibling->bottomLeft());
label->setVisible(sibling->hasFocus());
}
bool eventFilter(QObject *obj, QEvent *ev) override {
if (auto *label = getLabel(obj))
if (ev->type() == QEvent::Resize || ev->type() == QEvent::Move
|| ev->type() == QEvent::ParentChange || ev->type() == QEvent::FocusIn
|| ev->type() == QEvent::FocusOut)
updateLabel(label);
return false;
}
public:
using QObject::QObject;
};
auto *label = Filter::getLabel(widget);
if (!label) {
label = new QLabel(widget->parent());
label->setProperty(kTrackedSibling, QVariant::fromValue(widget));
widget->setProperty(kLabelSibling, QVariant::fromValue(label));
widget->installEventFilter(new Filter(widget));
QObject::connect(widget, &QObject::destroyed, label, [widget, label]{
widget->setProperty(kLabelSibling, {});
label->setProperty(kTrackedSibling, {});
label->deleteLater();
});
}
label->setText(text);
Filter::updateLabel(label);
}
(抱歉,以上内容未经测试,凭记忆编写)
我正在尝试在 QPushButton
下方(按钮边界之外)每当它获得焦点时绘制文本。为此,我对 QPushButton
进行了子类化,并且我在 QPushButton
的重写 paintEvent
方法中使用 QPainter
drawText 方法绘制文本。在绘制之前,我设置 QPainter::setClipping(false)
以启用绘制侧边按钮边界的文本。但是不知何故 QPainter::setClipping(false)
不起作用,文本没有绘制到按钮边界之外。
painter的paint engine本身在底层实现了裁剪,widget painter默认是不裁剪的。换句话说:不可能关闭此剪辑。以下成立:
void Class::paintEvent(QPaintEvent *ev) {
Parent::paintEvent(ev);
QPainter p(this);
Q_ASSERT(!p.hasClipping());
// and now you do:
p.setClipping(false); // this is a no-op!
}
一个简单的解决方案是添加一个将文本绘制为按钮同级的小部件,并将其定位在按钮下方。该小部件可以是 QLabel
.
static const char kLabelSibling[] = "qq_labelSibling";
static const char kTrackedSibling[] = "qq_trackedSibling";
void setTextBelow(QWidget *widget, const QString &text) {
Q_ASSERT(widget->parent);
class Filter : QObject {
static QLabel *getLabel(QObject *sibling) {
return widget->property(kLabelSibling).value<QLabel*>();
}
static void updateLabel(QWidget *label) {
auto *sibling = label->property(kTrackedSibling).value<QWidget*>();
Q_ASSERT(sibling);
label->setParent(sibling->parent());
label->move(sibling->bottomLeft());
label->setVisible(sibling->hasFocus());
}
bool eventFilter(QObject *obj, QEvent *ev) override {
if (auto *label = getLabel(obj))
if (ev->type() == QEvent::Resize || ev->type() == QEvent::Move
|| ev->type() == QEvent::ParentChange || ev->type() == QEvent::FocusIn
|| ev->type() == QEvent::FocusOut)
updateLabel(label);
return false;
}
public:
using QObject::QObject;
};
auto *label = Filter::getLabel(widget);
if (!label) {
label = new QLabel(widget->parent());
label->setProperty(kTrackedSibling, QVariant::fromValue(widget));
widget->setProperty(kLabelSibling, QVariant::fromValue(label));
widget->installEventFilter(new Filter(widget));
QObject::connect(widget, &QObject::destroyed, label, [widget, label]{
widget->setProperty(kLabelSibling, {});
label->setProperty(kTrackedSibling, {});
label->deleteLater();
});
}
label->setText(text);
Filter::updateLabel(label);
}
(抱歉,以上内容未经测试,凭记忆编写)