I am using QTextBrowser for printing data but want to check which line is clicked and get its string. I looked at other resources and was able to make this, but its not printing the line.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class TextBrowser(QtWidgets.QTextBrowser):
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.MouseButtonPress:
tc = self.cursorForPosition(event.pos())
print("text = ", tc.block().text())
return super().eventFilter(source, event)
def setupUi(self, MainWindow):
MainWindow.resize(104, 105)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName(u"gridLayout_8")
self.code_textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
self.gridLayout.addWidget(self.code_textBrowser, 1, 0, 1, 1)
self.code_textBrowser.viewport().installEventFilter(self)
self.code_textBrowser.append("ab\ncde\nfghi\njklmn\nopqrstu")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
MainWindow.setMenuBar(self.menubar)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = TextBrowser()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
One of the reasons why I do not recommend modifying the code generated by .ui is that it causes confusion so for my possible solution you must restore that file (run pyuic again) and call the generated file as gui.py.
The problem is that the cursorForPosition returns the cursor associated with "TextBrowser" (in your case "ui") and not with "code_textBrowser", that a class inherits from class T does not imply that all attributes are of the same class T they will be the same.
The solution is to implement the logic in another class that inherits from a QObject like QMainWindow and implement the logic using code_textBrowser.
import sys
from PyQt5.QtCore import QEvent
from PyQt5.QtWidgets import QApplication, QMainWindow
from gui import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.code_textBrowser.viewport().installEventFilter(self)
def eventFilter(self, obj, event):
if (
obj is self.ui.code_textBrowser.viewport()
and event.type() == QEvent.MouseButtonPress
):
tc = self.ui.code_textBrowser.cursorForPosition(event.pos())
print("text = ", tc.block().text())
return super().eventFilter(obj, event)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Related
I'm trying to install a keyPressEvent on a QPlainTextEdit widget such that when type, i type normally and when I hit enter, it will add text to the QPlainTextEdit. I have to files, QtDes.py created by Qt Designer and another file, QtTextEvent.py. These are my files:
QtDes.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'QtDes.ui'
#
# Created by: PyQt5 UI code generator 5.13.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtGui, QtWidgets, QtCore
class Ui_MainWindow(object):
def __init__(self, *args, **kwargs):
super(Ui_MainWindow, self).__init__(*args, **kwargs)
self.exactAns = ""
self.approxAns = 0
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 569)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.plainTextEdit = QtWidgets.QPlainTextEdit(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Courier New")
self.plainTextEdit.setFont(font)
self.plainTextEdit.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.plainTextEdit.setTabChangesFocus(False)
self.plainTextEdit.setLineWrapMode(QtWidgets.QPlainTextEdit.NoWrap)
self.plainTextEdit.setOverwriteMode(False)
self.plainTextEdit.setTabStopWidth(40)
self.plainTextEdit.setTabStopDistance(40.0)
self.plainTextEdit.setObjectName("plainTextEdit")
self.plainTextEdit.appendPlainText("First Line: ")
self.plainTextEdit.keyPressEvent = self.keyPressEvent
self.gridLayout.addWidget(self.plainTextEdit, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
and QtTextEvent.py:
from PyQt5 import QtCore, QtGui, QtWidgets
from QtDes import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Return or event.key() == QtCore.Qt.Key_Enter:
print("Enter pressed")
self.plainTextEdit.appendPlainText("New Line: ")
else:
super(MainWindow, self).keyPressEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Pressing enter does what it should do, but pressing other buttons doesn't work. I took the answer from this question and this question. Is there something wrong with my implementation and how could I fix it?
Explanation:
The keyPressEvent method implements the task of adding text to the QPlaintTextEdit when you press a key but you are assigning it another keyPressEvent (from the QMainWindow) that does not implement this logic, that is, it does not add the text. So it is not correct to assign one method to another since you delete the behavior that the widgets have by default.
Solution:
In your case it is only necessary to listen to the keyboard and if you press enter or return then add a text, then to listen to an event you only need an event filter.
To do this you must delete self.plainTextEdit.keyPressEvent = self.keyPressEvent in the QtDes.py file. Also implement the event filter in QtTextEvent.py file:
from PyQt5 import QtCore, QtGui, QtWidgets
from QtDes import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
self.plainTextEdit.installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self.plainTextEdit and event.type() == QtCore.QEvent.KeyPress:
if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
print("Enter pressed")
self.plainTextEdit.appendPlainText("New Line: ")
return True
return super(MainWindow, self).eventFilter(obj, event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Another possible solution is to inherit from QPlainTextEdit and override the keyPressEvent method.
plaintextedit.py
class PlainTextEdit(QtWidgets.QPlainTextEdit):
def keyPressEvent(self, event):
if event.key() in (QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter):
print("Enter pressed")
self.appendPlainText("New Line: ")
return
super(PlainTextEdit, self).keyPressEvent(event)
Then you change to:
QtDes.py
from plaintextedit import PlainTextEdit
# ...
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
# ...
self.plainTextEdit = PlainTextEdit(self.centralwidget)
# ...
(you could also promote it as I indicated in this answer)
You cannot "install a keyPressEvent", and even if you could, it wouldn't work with your approach.
By doing this:
self.plainTextEdit.keyPressEvent = self.keyPressEvent
you are practically doing something like this:
mainWindowInstance.plainTextEdit.keyPress = mainWindowInstance.keyPressEvent
The result is that the event will not be received by the plainTextEdit, but the main window, and since events are always sent back to the parent if not processed, nothing else will happen.
A theoretical solution would be to call the base class implementation against the QPlainTextEdit widget instead:
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Return or event.key() == QtCore.Qt.Key_Enter:
print("Enter pressed")
self.plainTextEdit.appendPlainText("New Line: ")
else:
QtWidgets.QPlainTextEdit.keyPressEvent(self.plainTextEdit, event)
Note that I didn't call self.plainTextEdit.keyPressEvent(event), as it would cause a recursion.
This idea is not good anyway, because in this way you're overwriting the QMainWindow keyPressEvent too (which could be a problem if you need it, but that's not the point).
There are two possible (and more "elegant") solutions:
1. Subclass QPlainTextEdit and promote it in Designer
This method allows you to create your UI in designer and set basic parameters for a custom widget that you can extend with your own code; see this answer for an explanation about the procedure.
With this you can just do something like this:
class MyTextEdit(QtWidget.QPlainTextEdit):
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Return or event.key() == QtCore.Qt.Key_Enter:
print("Enter pressed")
self.appendPlainText("New Line: ")
else:
super().keyPressEvent(event)
The extra advantage is that, in this way, the code is also more cleaner and easier to implement.
2. Install an event filter on the widget
An event filter is able to "intercept" any event a widget receives, and possibly react to it. In your case it could be something like this:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.plainTextEdit.installEventFilter(self)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.KeyPress and
event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return)):
# ensure that the widget receives the key event
super().eventFilter(source, event)
print("Enter pressed")
self.plainTextEdit.appendPlainText("New Line: ")
# the event is accepted and not sent to its ancestors
return True
return super().eventFilter(source, event)
I am trying to figure out how I can create a drop down list (currently using QComoboBox), with a few items, and when I hover my mouse/click on one of the options, it shows a sub list, containing a few more options.
I tried to search online but couldn't find anything that I could use.
Here an example of what I want to achieve (sorry for terrible quality, but I think it makes it clear what my goal is..)
Does any one have an idea of how to make a sub list inside a list?
Edit
After trying #eyllanesc suggestion I still having a problem:
I am using two files: one file that contains all the objects like buttons and such, and the other one that contains some functions and basically makes the GUI functional.
I defined this on my first file
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(751, 650)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.menuBtn=QtWidgets.QPushButton(self.centralwidget)
self.menuBtn.setGeometry(QtCore.QRect(100, 220, 100, 100))
self.productMenu=QtWidgets.QMenu(self.centralwidget)
self.menu1=self.productMenu.addMenu("options")
self.menu1.addAction("option 1")
self.menu2=self.productMenu.addMenu("option 2")
self.menu2.addAction("option 2a")
self.menu2.addAction("option 2b")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Test"))
self.menuBtn.setText(_translate("MainWindow", "Menu"))
And on the second file (the functional) I wrote this:
from PyQt5 import QtWidgets, QtCore, QtGui
from stackTest import Ui_MainWindow
import sys
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super(ApplicationWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.productMenu.triggered.connect(lambda action: self.ui.menuBtn.setText(action.text("Hello!")))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = ApplicationWindow()
application.show()
sys.exit(app.exec_())
When I run the code, I can see the button, but when I click it nothing happens.
How can I make it run so when I push the button I'll get the menu.
One possible solution is to use a button (QPushButton, QToolButton, etc.) and establish a QMenu as I show below:
import sys
from PyQt5 import QtCore, QtWidgets
def create_menu(d, menu):
if isinstance(d, list):
for e in d:
create_menu(e, menu)
elif isinstance(d, dict):
for k, v in d.items():
sub_menu = QtWidgets.QMenu(k, menu)
menu.addMenu(sub_menu)
create_menu(v, sub_menu)
else:
action = menu.addAction(d)
action.setIconVisibleInMenu(False)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
d = ["1", "2", "3", {"4": ["5", "6", {"7": ["8", "9"]}]}, {"10": "11"}]
menu = QtWidgets.QMenu(self)
create_menu(d, menu)
button = QtWidgets.QPushButton()
button.setMenu(menu)
menu.triggered.connect(lambda action: button.setText(action.text()))
lay = QtWidgets.QHBoxLayout(self)
lay.addWidget(button)
lay.addStretch()
self.resize(640, 480)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
The code provided by the OP must add the QMenu to the QPushButton:
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
from stackTest import Ui_MainWindow
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super(ApplicationWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.menuBtn.setMenu(self.ui.productMenu)
self.ui.productMenu.triggered.connect(
lambda action: self.ui.menuBtn.setText(action.text())
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
application = ApplicationWindow()
application.show()
sys.exit(app.exec_())
I am using the given code, I want the user to enter text in the QLineEdit widget, press the Copy! button and see the inputted text replace the 'N/A' label. My questions is: following this procedure, how can I clear the text inputted in the QLineEdit widget with a simple mouse click?
From what I read (this, this and this) it seems like I need to reimplement focusInEvent() in a new class extending QLineEdit. My problem is that the code for my GUI has been imported from Qt Designer using pyuic5 and the examples cited above don't seem to take this in consideration.
Here is my code:
from PyQt5.QtWidgets import *
import sys
import QLineEdit_test
class MainWindow(QMainWindow, QLineEdit_test.Ui_QLineEdit_test):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.copy_button.clicked.connect(self.copy_and_print)
def copy_and_print(self):
self.label.setText(self.lineEdit.text())
def main():
app = QApplication(sys.argv)
form = MainWindow()
form.show()
app.exec_()
if __name__ == "__main__":
main()
Here is my converted .ui file:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_QLineEdit_test(object):
def setupUi(self, QLineEdit_test):
QLineEdit_test.setObjectName("QLineEdit_test")
QLineEdit_test.resize(300, 200)
QLineEdit_test.setMaximumSize(QtCore.QSize(300, 200))
self.centralwidget = QtWidgets.QWidget(QLineEdit_test)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout_2.setObjectName("gridLayout_2")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setMaximumSize(QtCore.QSize(120, 16777215))
self.lineEdit.setObjectName("lineEdit")
self.gridLayout.addWidget(self.lineEdit, 0, 0, 1, 1)
self.copy_button = QtWidgets.QPushButton(self.centralwidget)
self.copy_button.setObjectName("copy_button")
self.gridLayout.addWidget(self.copy_button, 1, 0, 1, 1)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setMaximumSize(QtCore.QSize(200, 20))
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 2, 0, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
QLineEdit_test.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(QLineEdit_test)
self.menubar.setGeometry(QtCore.QRect(0, 0, 300, 22))
self.menubar.setObjectName("menubar")
QLineEdit_test.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(QLineEdit_test)
self.statusbar.setObjectName("statusbar")
QLineEdit_test.setStatusBar(self.statusbar)
self.retranslateUi(QLineEdit_test)
QtCore.QMetaObject.connectSlotsByName(QLineEdit_test)
def retranslateUi(self, QLineEdit_test):
_translate = QtCore.QCoreApplication.translate
QLineEdit_test.setWindowTitle(_translate("QLineEdit_test", "MainWindow"))
self.copy_button.setText(_translate("QLineEdit_test", "Copy!"))
self.copy_button.setShortcut(_translate("QLineEdit_test", "Return"))
self.label.setText(_translate("QLineEdit_test", "N/A"))
The solution is to promote QtDesigner use our custom QLineEdit where we implement the signal clicked with the help of mousePressEvent, this class will be called ClickableLineEdit and the file will be called ClickableLineEdit.py.
ClickableLineEdit.py
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QLineEdit
class ClickableLineEdit(QLineEdit):
clicked = pyqtSignal()
def mousePressEvent(self, event):
self.clicked.emit()
QLineEdit.mousePressEvent(self, event)
To promote it, the following structure will be considered:
.
├── ClickableLineEdit.py
├── main.py
├── your.ui
└── QLineEdit_test.py
Open the design with Qt Designer and right click on the QLineEdit and select Promote to ...:
A menu will open and place the following
then press and Promote. Then we generate the code again.
Then we connect the signal to clear:
class MainWindow(QMainWindow, QLineEdit_test.Ui_QLineEdit_test):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.copy_button.clicked.connect(self.copy_and_print)
self.lineEdit.clicked.connect(self.lineEdit.clear)
def copy_and_print(self):
self.label.setText(self.lineEdit.text())
Update:
PySide2:
from PySide2 import QtCore, QtWidgets
class ClickableLineEdit(QtWidgets.QLineEdit):
clicked = QtCore.Signal()
def mousePressEvent(self, event):
super(ClickableLineEdit, self).mousePressEvent(event)
self.clicked.emit()
class App(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.lineedit = ClickableLineEdit()
self.lineedit.clicked.connect(self.lineedit.clear)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.lineedit)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())
def __init__(self, *args, **kwargs):
QWidget.__init__(self, *args, **kwargs)
layout = QGridLayout()
self.setLayout(layout)
self.lineedit = QLineEdit()
self.lineedit.returnPressed.connect(self.press)
layout.addWidget(self.lineedit, 0, 0)
def press(self):
print("Hi World")
self.lineedit.clear()
If someone is still looking for a way to do this, but you only want the Line edit to be cleared when it first clicked and not every time it is clicked, you can do so without using variables like this :
def init_UI(self):
self.text_input = QLineEdit('Type your name')
self.text_input.mousePressEvent = self._mousePressEvent
def _mousePressEvent(self, event):
self.text_input.clear()
self.text_input.mousePressEvent = None
This way the _mousePressEvent gets called only once
I have an optional solution in one line:
self.lineEdit.mouseReleaseEvent = self.copy_and_print
Make sure you are receiving two parameters in your function (self,event)
I hope I helped you
Full post: https://wiki.python.org/moin/PyQt/Making%20non-clickable%20widgets%20clickable
Use mousePressEvent of QLineEdit to detect mouse click. To clear the text use clear() method or setText() method of QLineEdit.
#called when ever mouse is pressed
def mousePressed(self, event):
print('mouse pressed')
self.lineEdit=QLineEdit("Awesome day")#from PyQt5.QtWidget import QLineEdit
self.lineEdit.mousePressEvent = self.mousePressed
Example program :
import sys
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QApplication, QLineEdit
class ButtonPanel(QWidget):
def __init__(self, heading):
self.initUI(heading)
def initUI(self, heading):
super().__init__()
self.layout = QHBoxLayout()
self.lineEdit = QLineEdit(heading)
#self.lineEdit.setReadOnly(True)
self.lineEdit.returnPressed.connect(self.returnPressed)
self.lineEdit.mousePressEvent = self.mousePressed
self.delete = QPushButton("D")
self.layout.addWidget(self.lineEdit)
self.layout.addWidget(self.delete)
self.setLayout(self.layout)
self.show()
#called when mouse is clicked
def mousePressed(self, event):
self.lineEdit.clear() #text is cleared
//self.lineEdit.setText("") #this way we can also clear the text
print('mouse pressed')
//called when return key is pressed
def returnPressed(self):
print('return pressed')
if __name__ == "__main__":
app = QApplication(sys.argv)
b = ButtonPanel("Awesome")
sys.exit(app.exec())
Output :
Good evening everyone!
I`m just starting using pyQt5 and Qt Designer in Python so met some troubles while coding the example below. No matter about buttons and so on inside the App, the question is about using keyPressEvent i.e. for terminating App by Esc button.
There are 2 files: one generated by designer, second one - where the keyPressEvent is.
Form is opening, but nothing happened to it pressing Esc butt.
Looking forward for your hepl! Thanks.
ui_main.py
from PyQt5 import QtCore, QtWidgets
from PyQt5 import QtQuickWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(MainWindow)
self.gridLayout.setObjectName("gridLayout")
self.bigWindow = QtQuickWidgets.QQuickWidget(MainWindow)
self.bigWindow.setResizeMode(QtQuickWidgets.QQuickWidget.SizeRootObjectToView)
self.bigWindow.setObjectName("bigWindow")
self.gridLayout.addWidget(self.bigWindow, 0, 0, 1, 1)
self.dateTimeEdit = QtWidgets.QDateTimeEdit(MainWindow)
self.dateTimeEdit.setObjectName("dateTimeEdit")
self.gridLayout.addWidget(self.dateTimeEdit, 1, 0, 1, 1)
self.progressBar = QtWidgets.QProgressBar(MainWindow)
self.progressBar.setProperty("value", 24)
self.progressBar.setObjectName("progressBar")
self.gridLayout.addWidget(self.progressBar, 2, 0, 1, 1)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Dialog"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QDialog()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
py_main.py
import sys
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5.QtCore import Qt
from ui_main import Ui_MainWindow
class MyMainWindow(QDialog, Ui_MainWindow):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.show()
self.setupUi(self)
def keyPressEvent(self, event):
if event.key() == Qt.Key_Escape:
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyMainWindow()
sys.exit(app.exec_())
You must use the eventFilter method, in the constructor:
qApp.installEventFilter(self)
Then we override the method:
def eventFilter(self, obj, event):
if event.type() == QEvent.KeyPress:
if event.key() == Qt.Key_Escape:
self.close()
return super(MyMainWindow, self).eventFilter(obj, event)
Complete code:
import sys
from PyQt5.QtWidgets import QDialog, QApplication, qApp
from PyQt5.QtCore import Qt, QEvent
from ui_main import Ui_MainWindow
class MyMainWindow(QDialog, Ui_MainWindow):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
qApp.installEventFilter(self)
self.setupUi(self)
self.show()
def eventFilter(self, obj, event):
if event.type() == QEvent.KeyPress:
if event.key() == Qt.Key_Escape:
self.close()
return super(MyMainWindow, self).eventFilter(obj, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyMainWindow()
sys.exit(app.exec_())
I am using a PyQt4.QMainWindow as my application interface, and I want to get the x and y coordinates of the mouse inside of a QWidget and set them continuously in 2 textBrowsers in the MainWindow.
The documentation for QWidget is here.
and the documentation for QMouseEvent is here.
Here is the code
from PyQt4 import QtGui
from PyQt4.QtGui import QApplication
import sys
class Ui_MainWindow(object):
def setupUI(self, MainWindow):
self.textBrowser_1 = QtGui.QTextBrowser(self.tab)
self.textBrowser_2 = QtGui.QTextBrowser(self.tab)
self.widget_1 = QtGui.QWidget(self.tab)
self.widget_1.setMouseTracking(True)
class MyMainScreen(QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow() # This is from a python export from QtDesigner
# There is a QWidget inside that is self.ui.widget_1
# and 2 textBrowsers, textBrowser_1 and textBrowser_2
# I want to populate these 2 textBrowsers with the current x,y
# coordinates.
if __name__ == "__main__":
app = QApplication(sys.argv)
mainscreen = MyMainScreen()
mainscreen.show()
app.exec_()
When you apply setMouseTracking it only applies to that widget, and not to your children, so you must manually, in the next solution:
def setMouseTracking(self, flag):
def recursive_set(parent):
for child in parent.findChildren(QtCore.QWidget):
child.setMouseTracking(flag)
recursive_set(child)
QtGui.QWidget.setMouseTracking(self, flag)
recursive_set(self)
complete code:
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4.QtGui import QApplication, QMainWindow
import sys
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.resize(800, 132)
self.centralwidget = QtGui.QWidget(MainWindow)
self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
self.textBrowser_1 = QtGui.QTextBrowser(self.centralwidget)
self.horizontalLayout.addWidget(self.textBrowser_1)
self.textBrowser_2 = QtGui.QTextBrowser(self.centralwidget)
self.horizontalLayout.addWidget(self.textBrowser_2)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
MainWindow.setStatusBar(self.statusbar)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
class MyMainScreen(QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow() # This is from a python export from QtDesigner
self.ui.setupUi(self)
self.setMouseTracking(True)
self.ui.textBrowser_1.setMouseTracking(True)
self.ui.textBrowser_2.setMouseTracking(True)
self.ui.menubar.setMouseTracking(True)
self.ui.statusbar.setMouseTracking(True)
def setMouseTracking(self, flag):
def recursive_set(parent):
for child in parent.findChildren(QtCore.QWidget):
child.setMouseTracking(flag)
recursive_set(child)
QtGui.QWidget.setMouseTracking(self, flag)
recursive_set(self)
def mouseMoveEvent(self, event):
pos = event.pos()
self.ui.textBrowser_1.append(str(pos.x()))
self.ui.textBrowser_2.append(str(pos.y()))
QtGui.QMainWindow.mouseMoveEvent(self, event)
if __name__ == "__main__":
app = QApplication(sys.argv)
mainscreen = MyMainScreen()
mainscreen.show()
app.exec_()
This is my output: