当鼠标不在QTextEdit上时转动鼠标滚轮,滚动条不会移动,但我仍然想通过鼠标滚轮移动滚动条,那么我该如何实现这个功能呢? 我知道像 Microsoft Word 这样的软件有这个功能。
我像下面这样实现了这个功能,但是当你通过鼠标滚轮将滚动条移动到顶部或底部时,会出现错误:调用Python对象时超出最大递归深度。 任何人都可以帮忙吗? 我的代码在这里http://codepad.org/1rq06qTk:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class BoxLayout(QWidget):
def __init__(self, parent=None):
super(BoxLayout, self).__init__(parent)
self.resize(100, 300)
ok = QPushButton("OK")
cancel = QPushButton("Cancel")
self.textEdit = QTextEdit("This function returns true if the contents "
"of the MIME data object, specified by source, "
"can be decoded and inserted into the document. "
"It is called for example when during a drag "
"operation the mouse enters this widget and it "
"is necessary to determine whether it is possible "
"to accept the drag and drop operation.")
vbox = QVBoxLayout()
vbox.addWidget(self.textEdit)
vbox.addWidget(ok)
vbox.addWidget(cancel)
self.setLayout(vbox)
# self.textEdit.installEventFilter(self)
# def eventFilter(self, obj, event):
# if obj == self.textEdit:
# if event.type() == QEvent.Wheel:
# self.textEdit.wheelEvent(event)
# return True
# else:
# return False
# else:
# return QMainWindow.eventFilter(self, obj, event)
def wheelEvent(self, event):
self.textEdit.wheelEvent(event)
app = QApplication(sys.argv)
qb = BoxLayout()
qb.show()
sys.exit(app.exec_())
您可以通过在任何将鼠标滚轮事件转发到 QTextEdit 的小部件上安装事件过滤器来做到这一点:
不幸的是,我只能给你 C++ 代码,但它应该给你一个总体思路。 另外,我正在使用 Qt 4.6.1。我在 Qt 4.8 及更高版本中检测到新的“滚动”事件类型,您在使用它时可能需要更改代码。
[编辑:]
对于 TextEdit 滚动,事件处理由于某种原因与标准方式不同: 将滚轮事件发送到文本编辑器不会对其进行处理。 相反,某种私有事件过滤器通过
wheelEvent
调用 QAbstractScrollArea::viewportEvent
,不幸的是,它受到了保护。
长话短说,我们可以通过子类化 QTextEdit 来伪造 Wheel 事件:
#include "MyTextEdit.h"
MyTextEdit::MyTextEdit( QWidget* parent ) :
QTextEdit( parent )
{
}
void MyTextEdit::forwardViewportEvent( QEvent* event )
{
viewportEvent( event );
}
当使用它而不是默认的 QTextEdits 时,您可以创建一个事件转发器,如下所示:
#ifndef WHEELEVENTFORWARDER_H
#define WHEELEVENTFORWARDER_H
#include <QtCore/QObject>
class MyTextEdit;
class WheelEventForwarder : public QObject
{
Q_OBJECT
public:
explicit WheelEventForwarder( MyTextEdit* target );
~WheelEventForwarder();
bool eventFilter( QObject* obj, QEvent* event );
private:
MyTextEdit* _target;
};
#endif // WHEELEVENTFORWARDER_H
WheelEventForwarder.cpp
#include "WheelEventForwarder.h"
#include "MyTextEdit.h"
#include <QtCore/QEvent>
#include <QtGui/QApplication>
WheelEventForwarder::WheelEventForwarder( MyTextEdit* target ) :
QObject(),
_target( target )
{
}
WheelEventForwarder::~WheelEventForwarder()
{
_target = NULL;
}
bool WheelEventForwarder::eventFilter( QObject* obj, QEvent* event )
{
Q_UNUSED( obj );
static bool recursionProtection = false;
if( recursionProtection ) return false;
if( !_target ) return false;
if( event->type() == QEvent::Wheel )
{
recursionProtection = true;
_target->forwardViewportEvent( event );
recursionProtection = false;
}
// do not filter the event
return false;
}
然后你可以像这样安装事件过滤器:
MainWindow.cpp(或任何更合适的地方):
_wheelEventForwarder = new WheelEventForwarder( ui->textEdit );
ui->centralwidget->installEventFilter( _wheelEventForwarder );
有关更多信息,请参阅 QObject::installEventFilter 的文档。
您也可以采用这种方法:
在需要时调用 QTextEdit.scroll(int,int) 函数来滚动 qtextedit。 意味着你可以从你的小部件的 mouseScrollEvent 中调用这个函数
@TimMeyer 的解决方案效果很好。至少对于 C++ 来说是这样。
我去掉了“递归”防护。对于Qt/v5.12,则没有必要。
这是上面 Tim Meyer 的 C++ 代码在 Python 中的实现。这个问题在 Qt 5.15 中仍然相关,尽管它是一个老问题。
此代码保留了递归检测,对于最新版本的 Qt5 可能不再需要。 (我用5.15.8测试过,没有它也能正常工作。)
创建自定义事件过滤器类,类似于 Tom 的:
class WheelEventFilter(QObject):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
self._parent = parent
self._locked = False
return
def eventFilter(self, object: QObject, event: QEvent) -> bool:
"""Filter events of type QWheelEvent and forward them to the
parent widget's wheelEvent handler.
"""
if self._locked:
return False
if isinstance(event, QWheelEvent):
self._locked = True
self._parent.wheelEvent(event)
self._locked = False
return False
然后,在
QTextEdit
子类的初始化中安装过滤器:
class TextEditor(QTextEdit):
def __init__(self, parent: QWidget) -> None:
super().__init__(parent=parent)
self.installEventFilter(WheelEventFilter(self))
return
这似乎效果很好。