ПРИМЕЧАНИЕ: ниже редактируется более полный пример
Я хочу реализовать следующее в Qt (в частности, PyQt, но я считаю, что решение будет одинаковым как в Python, так и в C ++):
Я хочу, чтобы у виджета был внутренний виджет, который по умолчанию отключен, и при щелчке виджет будет включен, и нажатие мыши будет распространяться на него.Например, в следующем окне / виджете:
Если я нажму между c
и d
, я бы хотел QLineEdit
, чтобы стать включенным, сфокусируйтесь, и курсор будет между c
и d
.Я дошел до того, что снова включил QLineEdit
, но я не могу отправить ему событие back .
Пока это мой код:
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)
Это упрощенный пример, я также хочу обернуть другие виджеты таким образом, чтобы изменение внутренних виджетов было практически невозможно.
Проблема, насколько я могу судить, заключается в том, чтоотключенный дочерний виджет отклоняет событие мыши (поскольку оно отключено) и отказывается снова брать его (или любое другое событие) из родительского виджета.
Любая помощь будет принята с благодарностью.
РЕДАКТИРОВАТЬ: ниже приведен более ясный пример того, что я имею в виду:
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton
class ComplexInnerWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QVBoxLayout(self)
self.btn1 = QPushButton('button 1')
self.btn1.clicked.connect(self._btn1_click)
layout.addWidget(self.btn1)
self.btn2 = QPushButton('button 2')
self.btn2.clicked.connect(self._btn2_click)
layout.addWidget(self.btn2)
def _btn1_click(self, *a):
print('button 1')
def _btn2_click(self, *a):
print('button 2')
class MyWidget(QWidget):
def __init__(self, inner_widget: QWidget, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QVBoxLayout(self)
self.inner = inner_widget
self.inner.setEnabled(False)
layout.addWidget(self.inner)
if __name__ == '__main__':
from PyQt5.QtWidgets import QApplication
app = QApplication([])
inner = ComplexInnerWidget()
w = MyWidget(inner)
w.show()
res = app.exec_()
exit(res)
я хочу, чтобы пользователь мог нажать на отключенный внутренний виджет, тем самым включив его полностью (т. Е. Оба btn1 иbtn2 становится активным) и одновременно нажимает соответствующую кнопку.Мне нужно, чтобы это было сделано без изменения ComplexInnerWidget
(так как пользователь должен иметь возможность ввести любой виджет в качестве параметра MyWidget
)
РЕДАКТИРОВАТЬ 2: решение eyllanesc работает для предоставленного примера, но у меня естьизменил его на MyWidget
, чтобы иметь возможность поддерживать несколько виджетов и быть вложенным в другие виджеты:
from PyQt5 import QtCore, QtWidgets
class ComplexInnerWidget(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QVBoxLayout(self)
self.btn1 = QtWidgets.QPushButton('button 1')
self.btn1.clicked.connect(self._btn1_click)
layout.addWidget(self.btn1)
self.btn2 = QtWidgets.QPushButton('button 2')
self.btn2.clicked.connect(self._btn2_click)
layout.addWidget(self.btn2)
self.le = QtWidgets.QLineEdit('abcdef')
layout.addWidget(self.le)
def _btn1_click(self, *a):
print('button 1')
def _btn2_click(self, *a):
print('button 2')
class MyWidget(QtWidgets.QWidget):
class EnableMouseHelper(QtCore.QObject):
def __init__(self, *args, warden):
super().__init__(*args)
self.warden = warden
def eventFilter(self, obj, event):
if obj.isWidgetType() and event.type() == QtCore.QEvent.MouseButtonPress:
if self.warden in obj.window().findChildren(QtWidgets.QWidget) \
and self.warden.underMouse() and not self.warden.isEnabled():
self.warden.setEnabled(True)
obj.setFocus()
return super().eventFilter(obj, event)
def __init__(self, inner_widget: QtWidgets.QWidget, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QVBoxLayout(self)
self.inner = inner_widget
self.inner.setEnabled(False)
layout.addWidget(self.inner)
self.helper = self.EnableMouseHelper(warden=self.inner)
QtWidgets.QApplication.instance().installEventFilter(self.helper)
class OuterWidget(QtWidgets.QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(MyWidget(ComplexInnerWidget()))
layout.addWidget(MyWidget(ComplexInnerWidget()))
le = QtWidgets.QLineEdit('hi there')
le.setEnabled(False)
layout.addWidget(le)
le = QtWidgets.QLineEdit('hi there')
layout.addWidget(le)
if __name__ == '__main__':
from PyQt5.QtWidgets import QApplication
app = QApplication([])
w = OuterWidget()
w.show()
res = app.exec_()
exit(res)