Qt QPainter忽略paintEvent内部的剪裁

Qt QPainter忽略paintEvent内部的剪裁,qt,qwidget,clip,qpainter,qt4.8,Qt,Qwidget,Clip,Qpainter,Qt4.8,我试图在一个QPushButton(按钮边界之外)下绘制一个文本,只要它聚焦。为此,我对QPushButton进行了子类化,并使用QPainterdrawText方法在QPushButton中重写paintEvent方法绘制文本。在绘制之前,我正在设置QPainter::setClipping(false)以启用文本绘制侧边按钮的边界。但是不知何故,qPaint::setClipping(false)不起作用,并且文本没有在按钮边界之外绘制。画师的绘制引擎本身在较低的级别上实现剪裁,而小部件画师

我试图在一个
QPushButton
(按钮边界之外)下绘制一个文本,只要它聚焦。为此,我对
QPushButton
进行了子类化,并使用
QPainter
drawText方法在
QPushButton
中重写
paintEvent
方法绘制文本。在绘制之前,我正在设置
QPainter::setClipping(false)
以启用文本绘制侧边按钮的边界。但是不知何故,
qPaint::setClipping(false)
不起作用,并且文本没有在按钮边界之外绘制。

画师的绘制引擎本身在较低的级别上实现剪裁,而小部件画师默认情况下没有剪裁。换句话说:不可能关闭此剪辑。以下观点认为:

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);
}
static const char kLabelSibling[]=“qq\u标签”;
静态常量字符ktracketsibling[]=“qq\u trackedshibling”;
void settextlower(QWidget*widget、const QString和text){
Q_断言(小部件->父级);
类筛选器:QObject{
静态QLabel*getLabel(QObject*同级){
返回小部件->属性(kLabelSibling).value();
}
静态void updateLabel(QWidget*标签){
auto*sibling=label->property(ktracketsibling.value();
Q_断言(兄弟);
标签->设置父项(同级->父项());
标签->移动(同级->左下角());
标签->设置可见(同级->hasFocus());
}
布尔事件过滤器(QObject*obj、QEvent*ev)覆盖{
if(auto*label=getLabel(obj))
如果(ev->type()==QEvent::Resize | ev->type()==QEvent::Move
||ev->type()==QEvent::ParentChange | ev->type()==QEvent::FocusIn
||ev->type()==QEvent::FocusOut)
更新标签(标签);
返回false;
}
公众:
使用QObject::QObject;
};
auto*label=Filter::getLabel(小部件);
如果(!标签){
label=newqlabel(小部件->父项());
标签->设置属性(ktracketsibling,QVariant::fromValue(小部件));
widget->setProperty(kLabelSibling,QVariant::fromValue(标签));
小部件->安装事件过滤器(新过滤器(小部件));
QObject::connect(小部件,&QObject::已销毁,标签,[小部件,标签]{
widget->setProperty(kLabelSibling,{});
标签->设置属性(ktracketsibling,{});
label->deleteLater();
});
}
标签->设置文本(文本);
过滤器::updateLabel(标签);
}

(抱歉,以上内容未经测试,是从内存中写入的)

谢谢。是的,我尝试了相同的方法,但没有从外部添加事件过滤器。我已经对QPushButton进行了子类化,并且我正在更改changeEvent方法中标签的位置,用于移动、调整大小、父项更改、显示和隐藏事件。但问题是,每当视图首次显示时,有时标签未显示或标签位置未正确更新。但除此之外,它工作得很好。您知道为什么会发生这种情况吗?子类化应该是最后的手段,因为它将您的代码与控件紧密结合。事件过滤器方法适用于任何聚焦控件。没有显示代码,我不能告诉你你做错了什么,对不起。