QScrollArea 中禁用的 QToolButtons 阻止滚动(PySide)
Disabled QToolButtons inside QScrollArea prevent scrolling (PySide)
我希望能够在 QScrollArea 中使用鼠标滚动,无论鼠标是否位于禁用的 QToolButton 上方。文档提到禁用的小部件不会将鼠标事件传播到 parents,我发现我需要安装事件过滤器来解决我遇到的这个问题。这是我设法做到的程度。我认为事件过滤器是在检测到车轮事件时安装的,但我不确定下一步应该做什么:
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_())
捕获到正确的事件后,您需要将事件 post 发送到父窗口小部件。我以前这样做过:
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 将在其中将事件分发到适当的小部件(禁用的父级)按钮)。
我猜想面向对象的编程风格在 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()
我的情况是这样的:
- QScrollArea 小部件中的 QPushButton 很少
- 当我在活动的按钮上滚动而不是非活动的按钮时,滚动有效。
我在实现中所做的是:
- 在我的所有按钮上安装父级 class (QMainWindow) 的事件过滤器,同时将它们添加到布局
- 在 QMainWindow 中实现了对 eventFilter 的覆盖 class
- 过滤 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);
}
我希望能够在 QScrollArea 中使用鼠标滚动,无论鼠标是否位于禁用的 QToolButton 上方。文档提到禁用的小部件不会将鼠标事件传播到 parents,我发现我需要安装事件过滤器来解决我遇到的这个问题。这是我设法做到的程度。我认为事件过滤器是在检测到车轮事件时安装的,但我不确定下一步应该做什么:
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_())
捕获到正确的事件后,您需要将事件 post 发送到父窗口小部件。我以前这样做过:
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 将在其中将事件分发到适当的小部件(禁用的父级)按钮)。
我猜想面向对象的编程风格在 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()
我的情况是这样的:
- QScrollArea 小部件中的 QPushButton 很少
- 当我在活动的按钮上滚动而不是非活动的按钮时,滚动有效。
我在实现中所做的是:
- 在我的所有按钮上安装父级 class (QMainWindow) 的事件过滤器,同时将它们添加到布局
- 在 QMainWindow 中实现了对 eventFilter 的覆盖 class
- 过滤 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);
}