Повторно отправить событие недавно включенному дочернему виджету
Я хочу реализовать следующее в Qt (в частности, PyQt, но я верю, что решение будет одинаковым как в Python, так и в C++):
Я хочу, чтобы у виджета был внутренний виджет, который по умолчанию отключен, и при щелчке виджет будет включен, и нажатие мыши будет распространяться на него. Например, в следующем окне / виджете:
Если я нажму между c
а также d
Я бы хотел QLineEdit
чтобы включить его, сфокусируйтесь и курсор находится между c
а также d
, Я добрался до повторного включения QLineEdit
но я не могу отправить это событие обратно.
Это мой код до сих пор:
from PyQt5.QtWidgets import QWidget, QLineEdit, QVBoxLayout, QPushButton, QApplication
class MyWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QVBoxLayout(self)
self.edit = QLineEdit('abcdef')
self.edit.setEnabled(False)
layout.addWidget(self.edit)
self.disable_btn = QPushButton('disable edit')
self.disable_btn.clicked.connect(self._disable_edit)
layout.addWidget(self.disable_btn)
def _disable_edit(self, *a):
self.edit.setEnabled(False)
def mousePressEvent(self, a0):
if not self.edit.isEnabled() and self.edit.underMouse():
self.edit.setEnabled(True)
QApplication.instance().sendEvent(self.edit, a0) # <-- this doesn't seem to work
super().mousePressEvent(a0)
if __name__ == '__main__':
from PyQt5.QtWidgets import QApplication
app = QApplication([])
w = MyWidget()
w.show()
res = app.exec_()
exit(res)
Это упрощенный пример, я также хочу обернуть другие виджеты таким образом, чтобы изменение внутренних виджетов практически невозможно.
Насколько я могу судить, проблема в том, что отключенный дочерний виджет отклоняет событие мыши (так как оно отключено) и отказывается снова брать его (или любое другое событие) из родительского виджета.
Любая помощь будет принята с благодарностью.
2 ответа
Вы не можете отправить объект события, так как Qt удалит его, когда его использует виджет, и вам нужно создать другое событие с теми же данными. Я создал класс, который позволяет вам регистрировать виджеты, чтобы дать вам это свойство без необходимости перезаписывать класс.
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
class EnableMouseHelper(QtCore.QObject):
def __init__(self, parent=None):
super(EnableMouseHelper, self).__init__(parent)
self._widgets = []
def addWidget(self, widget):
if isinstance(widget, QtWidgets.QWidget):
self._widgets.append(widget)
widget.installEventFilter(self)
return True
return False
def removeWidget(self, widget):
if widget is self._widgets:
widget.removeEventFilter(self)
self._widgets.remove(widget)
def eventFilter(self, obj, event):
if obj in self._widgets and event.type() == QtCore.QEvent.MouseButtonPress:
if not obj.isEnabled():
new_event = QtGui.QMouseEvent(
event.type(),
event.localPos(),
event.windowPos(),
event.screenPos(),
event.button(),
event.buttons(),
event.modifiers(),
event.source()
)
obj.setEnabled(True)
QtCore.QCoreApplication.postEvent(obj, new_event)
obj.setFocus()
return super(EnableMouseHelper, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
helper = EnableMouseHelper()
le = QtWidgets.QLineEdit(
text='abcdef',
enabled=False
)
btn = QtWidgets.QPushButton(
text='disable edit',
clicked=partial(le.setEnabled, False)
)
helper.addWidget(le)
w = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(w)
lay.addWidget(le)
lay.addWidget(btn)
w.show()
sys.exit(app.exec_())
Попытайся:
from PyQt5.QtWidgets import QWidget, QLineEdit, QVBoxLayout, QPushButton, QApplication
class LineEdit(QLineEdit): # +++
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setText('abcdef')
self.setStyleSheet('color: blue; font-size: 32px')
def mousePressEvent(self, event):
super(LineEdit, self).mousePressEvent(event)
self.cursor = self.cursorPosition()
def mouseReleaseEvent(self, event):
self.setFocus()
self.setCursorPosition(self.cursor)
class MyWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QVBoxLayout(self)
# self.edit = QLineEdit('abcdef')
self.edit = LineEdit() # +++
self.edit.setEnabled(False)
layout.addWidget(self.edit)
self.disable_btn = QPushButton('disable edit')
self.disable_btn.clicked.connect(self._disable_edit)
layout.addWidget(self.disable_btn)
def _disable_edit(self, *a):
self.edit.setEnabled(False)
def mousePressEvent(self, a0):
if not self.edit.isEnabled() and self.edit.underMouse():
self.edit.setEnabled(True)
QApplication.instance().sendEvent(self.edit, a0) # <-- this does seem to work
super().mousePressEvent(a0)
if __name__ == '__main__':
from PyQt5.QtWidgets import QApplication
app = QApplication([])
w = MyWidget()
w.show()
res = app.exec_()
exit(res)