I have a QTextBrowser and I want to select a part of the text inside, I need the position of the start and the end of the selection. I want to do that with mousePressEvent and mouseReleaseEvent. Here is my code,
class MainWindow(QMainWindow, TeamInsight.Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
def set_text(self):
self.textBrowser.setText('test strings are here')
textBrowser is inside a MainWindow. How do I implement mousePressEvent and mouseReleaseEvent for text in textBrowser
If you want to track events and you can not overwrite the class, the solution is to install an event filter, in your case, just the MouseButtonRelease event, we must filter the viewport() of the QTextBrowser:
import sys
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import QMainWindow, QApplication
import TeamInsight
class MainWindow(QMainWindow, TeamInsight.Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.browserInput.viewport().installEventFilter(self)
self.browserInput.setText("some text")
def eventFilter(self, obj, event):
if obj is self.browserInput.viewport():
if event.type() == QEvent.MouseButtonRelease:
if self.browserInput.textCursor().hasSelection():
start = self.browserInput.textCursor().selectionStart()
end = self.browserInput.textCursor().selectionEnd()
print(start, end)
elif event.type() == QEvent.MouseButtonPress:
print("event mousePressEvent")
return QMainWindow.eventFilter(self, obj, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Related
Don't know exactly how to give the parameters of QMouseEvent class. Should I create new class to implement a QMouseEvent into my QTextEdit?
class Test(QMainWindow):
def __init__(self):
super().__init__()
self.txt = QTextEdit(self)
self.txt.setMouseTracking(True)
self.txt.mouseReleaseEvent(QMouseEvent())
class Test2(QTextEdit):
def __init__(self):
super().__init__()
def mouseReleaseEvent(self, e):
print("text edit is clicked")
ui = Test()
ui.show()
Since many times it is asked how to detect the events that affect a widget then in this answer I will detail the solution and it will be used as a canonical answer for future questions.
To detect an event from a widget there are several solutions:
- Override a method
If the widget has a method that handles that event then an option is to override that method and associate it with a signal so that other objects can be notified.
In the particular case of the mouse release event, this is handled by the mouseReleaseEvent method.
from PyQt5 import QtCore, QtWidgets
class TextEdit(QtWidgets.QTextEdit):
released = QtCore.pyqtSignal()
def mouseReleaseEvent(self, event):
super().mouseReleaseEvent(event)
self.released.emit()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.textedit = TextEdit()
self.textedit.released.connect(self.handle_released)
self.setCentralWidget(self.textedit)
#QtCore.pyqtSlot()
def handle_released(self):
print("released")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
- Use an event filter
Qt allows you to monitor the events using an event filter, so you can take advantage of this feature to emit a signal in a similar way to the previous solution.
In the case of classes that inherit from QAbstractScrollArea, the mouse methods are transmitted to the viewport, so that object must be monitored.
from PyQt5 import QtCore, QtWidgets
class ReleaseFilter(QtCore.QObject):
released = QtCore.pyqtSignal()
def __init__(self, widget):
super().__init__(widget)
self._widget = widget
self.widget.installEventFilter(self)
#property
def widget(self):
return self._widget
def eventFilter(self, obj, event):
if obj is self.widget and event.type() == QtCore.QEvent.MouseButtonRelease:
self.released.emit()
return super().eventFilter(obj, event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.textedit = QtWidgets.QTextEdit()
rf = ReleaseFilter(self.textedit.viewport())
rf.released.connect(self.handle_released)
self.setCentralWidget(self.textedit)
#QtCore.pyqtSlot()
def handle_released(self):
print("released")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Hello I have a QWidget and If I click on it, I want to get the object (the QWidget Element I clicked on) is there anyway to do that?
I already found some code but I only get the MouseClickEvent from
self.widget_34.mouseReleaseEvent = lambda event: self.myfunction(event)
Although the solution offered by #Cin is interesting, it has a serious problem: it cancels the mousePressEvent of the widget, so the widget loses the behavior it could have when the widget is pressed, for example the button no longer emits the clicked signal, other widget also They will have the same problem.
A less intrusive solution is to use eventFilter:
import sys
import weakref
from PyQt5 import QtCore, QtWidgets
class ClickListener(QtCore.QObject):
clicked = QtCore.pyqtSignal(QtWidgets.QWidget)
def addWidget(self, widget, other_widget=None):
if not hasattr(self, "_widgets"):
self._widgets = {}
widget.installEventFilter(self)
self._widgets[widget] = widget if other_widget is None else other_widget
weakref.ref(widget, self.removeWidget)
def eventFilter(self, obj, event):
if (
obj in self._widgets
and event.type() == QtCore.QEvent.MouseButtonPress
):
self.clicked.emit(self._widgets[obj])
return super(ClickListener, self).eventFilter(obj, event)
def removeWidget(self, widget):
if hasattr(self, "_widgets"):
if widget in self._widgets:
del self._widgets[widget]
class App(QtWidgets.QWidget):
def __init__(self):
super().__init__()
button = QtWidgets.QPushButton("Press Me")
label = QtWidgets.QLabel("Stack Overflow")
spinBox = QtWidgets.QSpinBox()
te = QtWidgets.QTextEdit()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button)
lay.addWidget(label)
lay.addWidget(spinBox)
lay.addWidget(te)
listener = ClickListener(self)
listener.clicked.connect(self.onClicked)
listener.addWidget(button)
listener.addWidget(label)
listener.addWidget(spinBox.lineEdit(), spinBox)
listener.addWidget(te.viewport(), te)
def onClicked(self, obj):
print("Clicked, from", obj)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
I am not sure this will be a proper solution or not but I think, you can use the partial method of functools module. A collable object can be treated as a function for the purposes of this module. Here you can see my example,
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel
import functools
class App(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(200,200,200,200)
self.button = QPushButton('Button', self)
self.button.move(50,50)
self.label = QLabel(self)
self.label.setText("Label")
self.label.move(100,100)
self.items = [self.button, self.label]
for i in self.items:
i.mousePressEvent = functools.partial(self.getClickedItem, source_object=i)
self.show()
def getClickedItem(self, event, source_object=None):
print("Clicked, from", source_object)
#item text
#print(source_object.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
How can I get the value returned from mousePressEvent of a widget and apply it to another widget?
Here's the widget with the mousePressEvent:
class Text(QTextEdit):
...
def mousePressEvent(self, event):
if event.button()==Qt.LeftButton:
return "test"
Now I want to use the string returned from the event and apply it to another widget:
class OtherWidget(QWidget):
...
self.label=QLabel()
self.label.setText(???) # <=== How to put the string here?
...
How can I do that? I have tried the following but it does not work.
self.label.setText(Text().mousePressEvent())
The events do not return anything for what you point out is impossible, Qt to send information asynchronously uses the signals, in the next part I show an example:
from PyQt5 import QtCore, QtWidgets
class Text(QtWidgets.QTextEdit):
mousePressSignal = QtCore.pyqtSignal(str)
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
text = "test: {}-{}".format(event.pos().x(), event.pos().y())
self.mousePressSignal.emit(text)
class OtherWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(OtherWidget, self).__init__(parent)
self.label = QtWidgets.QLabel()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
#QtCore.pyqtSlot(str)
def setText(self, text):
self.label.setText(text)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
t = Text()
o = OtherWidget()
o.resize(640, 480)
t.mousePressSignal.connect(o.setText)
t.show()
o.show()
sys.exit(app.exec_())
class widget(QWidget):
...
self.edit=QTextEdit()
def mousePressEvent(self, event):
if event.button()==Qt.LeftButton:
print('test')
self.edit.mousePressEvent(event)
I have tried that but it does not work. It works for the parent widget. Is there anyway I can do it without subclassing the QTextEdit?
In this case you must use an eventFilter in addition to the classes that inherit from QAbstractScrollArea as QTextEdit you must use the viewport():
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.edit = QtWidgets.QTextEdit()
btn = QtWidgets.QPushButton()
le = QtWidgets.QLineEdit()
lay = QtWidgets.QVBoxLayout(self)
for w in (self.edit, btn, le):
lay.addWidget(w)
self.edit.viewport().installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self.edit.viewport() and event.type() == QtCore.QEvent.MouseButtonPress:
if event.button() == QtCore.Qt.LeftButton:
print('test')
return super(Widget, self).eventFilter(obj, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
I'm trying to catch a closeEvent for several dockWidgets that get added dynamically to a QMainWindow. It is unclear to me how I can figure out which widget has been closed.. Here's an simplified example:
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.leftDockWidget = QtGui.QDockWidget('pick tool', self)
self.leftDockWidget.setWidget( QtGui.QLabel('a dock widget') )
self.addDockWidget( QtCore.Qt.LeftDockWidgetArea, self.leftDockWidget )
self.leftDockWidget.closeEvent = self.dockWidgetCloseEvent
self.show()
def dockWidgetCloseEvent(self, event):
print event
# how to get sender widget ?
event.sender() doesn't seem to exist..
any ideas ?
thanks
One way to achieve what you want would be to use an event filter:
from PyQt4 import QtGui, QtCore
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.leftDockWidget = QtGui.QDockWidget('pick tool', self)
self.leftDockWidget.setWidget(QtGui.QLabel('a dock widget'))
self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.leftDockWidget)
self.leftDockWidget.installEventFilter(self)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.Close and
isinstance(source, QtGui.QDockWidget)):
print source.windowTitle()
return super(Example, self).eventFilter(source, event)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Example()
window.show()
sys.exit(app.exec_())
def dockWidgetCloseEvent(self, event):
self.sender()