QPainter игнорирует отсечение внутри paintEvent - PullRequest
0 голосов
/ 14 декабря 2018

Я пытаюсь нарисовать текст ниже QPushButton (вне границ кнопки) всякий раз, когда он фокусируется.Для этого у меня есть подкласс QPushButton, и я рисую текст, используя QPainter метод drawText внутри переопределенного paintEvent метода QPushButton.Перед рисованием я устанавливаю QPainter::setClipping(false), чтобы включить вывод текста за пределы боковой кнопки.Но почему-то QPainter::setClipping(false) не работает, и текст не отображается за пределами кнопки.

1 Ответ

0 голосов
/ 14 декабря 2018

Сам движок рисования реализует обрезку на более низком уровне, и по умолчанию рисователь виджетов не обрезает.Другими словами: невозможно отключить это ограничение.Справедливо следующее:

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);
}

(извините, вышеизложенное не проверено и записано из памяти)

...