【问题标题】:Disabled QToolButtons inside QScrollArea prevent scrolling (PySide)QScrollArea 内禁用的 QToolButtons 防止滚动(PySide)
【发布时间】:2021-08-16 19:53:26
【问题描述】:

无论鼠标是否位于禁用的 QToolButton 上方,我都希望能够在 QScrollArea 内使用鼠标滚动。文档提到禁用的小部件不会将鼠标事件传播给父母,我发现我需要安装事件过滤器来克服我遇到的这个问题。这就是我设法做到的程度。我认为事件过滤器是在检测到车轮事件时安装的,但我不确定下一步应该是什么:

from PySide import QtGui
from PySide.QtCore import *
import sys

app = QtGui.QApplication(sys.argv)

wid = QtGui.QWidget()
wid.resize(200, 200)

scroll = QtGui.QScrollArea()
scroll.setWidget(wid)

layout = QtGui.QVBoxLayout()
wid.setLayout(layout)

class installEvent(QObject):
    def eventFilter(self, i_obj, i_event):

        if i_event.type() == QEvent.Wheel:
            print "QEvent: " + str(i_event.type())


buttonEnabled = QtGui.QToolButton()
layout.addWidget(buttonEnabled)


buttonDisabled = QtGui.QToolButton()
buttonDisabled.setEnabled(False)
layout.addWidget(buttonDisabled)

buttonDisabled.installEventFilter(installEvent(buttonDisabled))

scroll.show()

sys.exit(app.exec_())

【问题讨论】:

    标签: qt pyside


    【解决方案1】:

    一旦您捕获到正确的事件,您需要将该事件发布到父窗口小部件。我以前做过这样的:

    def eventFilter(self, obj, event):
        if obj and not obj.isEnabled() and event.type() == QEvent.Wheel:
            newEvent = QWheelEvent(obj.mapToParent(event.pos()), event.globalPos(),
                                   event.delta(), event.buttons(),
                                   event.modifiers(), event.orientation())
            QApplication.instance().postEvent(obj.parent(), newEvent)
            return True
    
        return QObject.eventFilter(self, obj, event)
    

    此事件过滤器仅在按钮被禁用且事件类型为QEvent.Wheel 时才起作用。否则它实现eventFilter的默认行为。

    if 语句中的登录首先将坐标映射到父窗口小部件,然后使用与原始事件相同的参数构造一个新的QWEheelEvent(坐标映射除外)。最后一部分是获取QApplication 的实例并使用postEvent 方法将事件发送到Qt 事件循环,Qt 将在其中将事件分发到适当的小部件(禁用按钮的父级)。

    【讨论】:

    • 谢谢,这就是我想要的。您的有用而深入的回答向我解释了更多的事情。
    【解决方案2】:

    我猜当涉及到 PySide 和解决此类问题时,面向对象的编程风格是合适的。如果将来 PySide 初学者偶然发现这个答案,这里有完整的例子来说明如何使它工作:

    from PySide import QtGui
    from PySide.QtCore import *
    import sys
    
    # http://zetcode.com/gui/pysidetutorial/firstprograms/
    
    class Example(QtGui.QWidget):
    
        def __init__(self):
            super(Example, self).__init__()
    
            self.initUI()
    
        def initUI(self):
    
            self.scroll = QtGui.QScrollArea()
            self.scroll.setWidget(self)
    
            self.layout = QtGui.QVBoxLayout()
            self.setLayout(self.layout)
    
            self.btn = QtGui.QToolButton()
            self.btn.move(50, 50)
            self.btn.setEnabled(False)
            self.btn.installEventFilter(self)
    
            self.layout.addWidget(self.btn)
            self.setGeometry(300, 300, 250, 150)   
            self.scroll.show()
    
        def eventFilter(self, obj, event):
            if obj and not obj.isEnabled() and event.type() == QEvent.Wheel:
                newEvent = QtGui.QWheelEvent(obj.mapToParent(event.pos()), event.globalPos(),
                                       event.delta(), event.buttons(),
                                       event.modifiers(), event.orientation())
                QtGui.QApplication.instance().postEvent(obj.parent(), newEvent)
                print "QEvent: " + str(event.type())
                return True
    
            return QObject.eventFilter(self, obj, event) 
    
    def main():
    
        app = QtGui.QApplication(sys.argv)
        ex = Example()
        sys.exit(app.exec_())
    
    
    if __name__ == '__main__':
        main()
    

    【讨论】:

      【解决方案3】:

      我的情况是这样的:

      • QScrollArea 小部件内的 QPushButton 很少
      • 当我在活动的按钮上滚动但在非活动的按钮上滚动时滚动有效。

      我在实现中所做的是:

      • 在我的所有按钮上安装了父类 (QMainWindow) 的 eventFilter,同时将它们添加到布局中
      • 在 QMainWindow 类中实现了对 eventFilter 的覆盖
      • 过滤的 QPushButtons 和 WheelEvents
      • 将 wheelEvent 转换为新的 WheelEvent 并将其发布到我的应用程序实例的主事件循环中。

      如果有人正在寻找 C++ 等效代码来防止上述行为(您可以根据需要调整代码):

      bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
      {
          if (obj->metaObject()->className() == QString("QPushButton") && ev->type() == QEvent::Wheel){
              QWheelEvent *wev = static_cast<QWheelEvent*>(ev);
              QPushButton *btn = static_cast<QPushButton*>(obj);
              if(btn->isEnabled() == false){
                  QWheelEvent newEvent = QWheelEvent(btn->mapToParent(wev->pos()), wev->globalPos(),
                                         wev->delta(), wev->buttons(),
                                         wev->modifiers(), wev->orientation());
                  qApp->sendEvent(obj->parent(), &newEvent);
                  return true;
              }
          }
          return QMainWindow::eventFilter(obj,ev);
      }
      

      【讨论】:

      • 在禁用按钮时可以使用button-&gt;setAttribute( Qt::WA_TransparentForMouseEvents, true);,在启用它们时可以使用button-&gt;setAttribute( Qt::WA_TransparentForMouseEvents, false);,使鼠标事件绕过禁用的小部件并传递给父级。
      猜你喜欢
      • 1970-01-01
      • 2020-01-07
      • 2011-08-14
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多