简体   繁体   English

在Qt中模糊对QWidget的影响

[英]Blur effect over a QWidget in Qt

Is there any way to blur a widget in Qt? 有没有办法模糊Qt中的小部件? For instance, supose I want to create a 'Loading...' dialog and blur the background (not active window). 例如,supose我想创建一个'Loading ...'对话框并模糊背景(非活动窗口)。

This answer is in a series of my overlay-related answers: first , second , third . 这个答案是我的一系列与叠加相关的答案: 第一第二第三

It requires some care if you wish for it to work on all platforms. 如果您希望它可以在所有平台上运行,则需要一些小心。 You can't apply effects directly to top-level windows. 您无法直接将效果应用于顶级窗口。 The hierarchy needs to look as follows: 层次结构需要如下所示:

ContainerWidget
     |
     +----------+
     |          |
**Target**   Overlay

You apply the effect to the Target widget (say, a QMainWindow ). 您将效果应用于Target小部件(例如, QMainWindow )。 The ContainerWidget is a helper class that keeps the children occupying the full size of the widget. ContainerWidget是一个帮助程序类,可以让子项占用窗口小部件的完整大小。 This obviates the need for an explicit zero-margin layout. 这消除了对显式零边距布局的需要。

The below works, even on a Mac. 以下工作,甚至在Mac上。 It wouldn't, had you foregone the ContainerWidget . 如果放弃了ContainerWidget ,它就不会。 This works portably on Qt 5 only, unfortunately. 不幸的是,这仅适用于Qt 5。 On Qt 4, your "cross platform" support excludes Mac :( It works OK on Windows using either Qt 4 (4.8.5) or Qt 5. 在Qt 4上,你的“跨平台”支持不包括Mac :(它在Windows上使用Qt 4(4.8.5)或Qt 5正常工作。

截图

// https://github.com/KubaO/stackoverflown/tree/master/questions/overlay-blur-19383427
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif

class OverlayWidget : public QWidget {
   void newParent() {
      if (!parent()) return;
      parent()->installEventFilter(this);
      raise();
   }
public:
   explicit OverlayWidget(QWidget *parent = {}) : QWidget(parent) {
      setAttribute(Qt::WA_NoSystemBackground);
      setAttribute(Qt::WA_TransparentForMouseEvents);
      newParent();
   }
protected:
   //! Catches resize and child events from the parent widget
   bool eventFilter(QObject *obj, QEvent *ev) override {
      if (obj == parent()) {
         if (ev->type() == QEvent::Resize)
            resize(static_cast<QResizeEvent*>(ev)->size());
         else if (ev->type() == QEvent::ChildAdded)
            raise();
      }
      return QWidget::eventFilter(obj, ev);
   }
   //! Tracks parent widget changes
   bool event(QEvent *ev) override {
      if (ev->type() == QEvent::ParentAboutToChange) {
         if (parent()) parent()->removeEventFilter(this);
      }
      else if (ev->type() == QEvent::ParentChange)
         newParent();
      return QWidget::event(ev);
   }
};

class ContainerWidget : public QWidget
{
public:
   explicit ContainerWidget(QWidget *parent = {}) : QWidget(parent) {}
   void setSize(QObject *obj) {
      if (obj->isWidgetType()) static_cast<QWidget*>(obj)->setGeometry(rect());
   }
protected:
   //! Resizes children to fill the extent of this widget
   bool event(QEvent *ev) override {
      if (ev->type() == QEvent::ChildAdded) {
         setSize(static_cast<QChildEvent*>(ev)->child());
      }
      return QWidget::event(ev);
   }
   //! Keeps the children appropriately sized
   void resizeEvent(QResizeEvent *) override {
      for(auto obj : children()) setSize(obj);
   }
};

class LoadingOverlay : public OverlayWidget
{
public:
   LoadingOverlay(QWidget *parent = {}) : OverlayWidget{parent} {
      setAttribute(Qt::WA_TranslucentBackground);
   }
protected:
   void paintEvent(QPaintEvent *) override {
      QPainter p{this};
      p.fillRect(rect(), {100, 100, 100, 128});
      p.setPen({200, 200, 255});
      p.setFont({"arial,helvetica", 48});
      p.drawText(rect(), "Loading...", Qt::AlignHCenter | Qt::AlignTop);
   }
};

namespace compat {
#if QT_VERSION >= QT_VERSION_CHECK(5,4,0)
using QT_PREPEND_NAMESPACE(QTimer);
#else
using Q_QTimer = QT_PREPEND_NAMESPACE(QTimer);
class QTimer : public Q_QTimer {
public:
   QTimer(QTimer *parent = nullptr) : Q_QTimer(parent) {}
   template <typename F> static void singleShot(int period, F &&fun) {
      struct Helper : public QObject {
         F fun;
         QBasicTimer timer;
         void timerEvent(QTimerEvent *event) override {
            if (event->timerId() != timer.timerId()) return;
            fun();
            deleteLater();
         }
         Helper(int period, F &&fun) : fun(std::forward<F>(fun)) {
            timer.start(period, this);
         }
      };
      new Helper(period, std::forward<F>(fun));
   }
};
#endif
}

int main(int argc, char *argv[])
{
   QApplication a{argc, argv};
   ContainerWidget base;
   QLabel label("Dewey, Cheatem and Howe, LLC.", &base);
   label.setFont({"times,times new roman", 32});
   label.setAlignment(Qt::AlignCenter);
   label.setGraphicsEffect(new QGraphicsBlurEffect);
   LoadingOverlay overlay(&base);
   base.show();
   compat::QTimer::singleShot(2000, [&]{
      overlay.hide();
      label.setGraphicsEffect({});
   });
   return a.exec();
}

请参阅QGraphicsBlurEffect ClassQWidget::setGraphicsEffect()

You can refer to this article if you want to apply blur effect on an image. 您可以参考文章,如果你想对图像应用模糊效果。 After you create your blurred image you can draw it in QWidget::paintEvent() function. 创建模糊图像后,您可以在QWidget::paintEvent()函数中绘制它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM