How to make a loop and AutoClosed messagebox in PyQt5? - python

How to make a loop and AutoClosed messagebox in PyQt5?
Here is a kind of messagebox that can auto close after 3sec.
I want to show the message by using it in a loop.
How can i do it?
PS:the code is not writen by me
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, Qt
import time
class Ui_Message(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(538, 91)
self.frame = QtWidgets.QFrame(Form)
self.frame.setGeometry(QtCore.QRect(0, 0, 541, 111))
# self.frame.setStyleSheet("background-image: url(:/img/messageback.png);")
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.label = QtWidgets.QLabel(self.frame)
self.label.setGeometry(QtCore.QRect(0, 0, 531, 91))
font = QtGui.QFont()
font.setPointSize(31)
font.setBold(False)
font.setWeight(50)
self.label.setFont(font)
self.label.setStyleSheet("background-color: transparent;\n"
"fontsize: 30px;")
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "显示信息"))
# import img_rc
# Define a removable borderless 3S prompt message interface
class MessageWindow(Qt.QMainWindow):
def __init__(self, parent=None):
Qt.QWidget.__init__(self, parent)
self.ui = Ui_Message()
self.ui.setupUi(self)
self.setWindowFlags(Qt.Qt.FramelessWindowHint)
QtCore.QTimer().singleShot(3000, self.close)
self.show()
def mousePressEvent(self, event):
# Define mouse click events
if event.button() == QtCore.Qt.LeftButton:
self.dragPosition = event.globalPos() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event):
# Define mouse movement events
if event.buttons() == QtCore.Qt.LeftButton:
self.move(event.globalPos() - self.dragPosition)
event.accept()
def setMessage(self, message):
self.ui.label.setText(message)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
login = MessageWindow()
#----how can i maike a loop messagebox?------
for i in range(0,5):
login.setMessage("Number"+str(i))
time.sleep(3)
sys.exit(app.exec())
I know maybe i can't use time.sleep in PyQt5,however i had search for anything but not get the answer.

In Qt if you want to do a periodic task then you must use a QTimer, and forget about synchronous logic since you must work through events.
In this case a possible solution is to use a queue that stores the information and in each shot of the timer an element is obtained.
from collections import deque
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
login = MessageWindow()
values = range(0, 5)
q = deque(values)
def on_timeout():
print(q)
if q:
i = q.popleft()
Qt.QTimer.singleShot(3000, on_timeout)
login.setMessage("Number" + str(i))
on_timeout()
sys.exit(app.exec())
Notes:
Your class must not inherit from QMainWindow but from QWidget.
You must eliminate the timer that closes the window, otherwise you will not see the text change since the time is very short.

Related

When two widget animation commands run at start only one gets animated

I am trying hide two list widgets upon start by animating the maximum width to zero, then two buttons to toggle each widget to appear and disappear, this works fine, but not at start, only one of the two widget gets animated, the other just stays on, but the same command works fine when signaled by the push buttons.
Please suggest if there is any better approach to achieve the same effect or the reason behind it.
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtCore import QPropertyAnimation
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(640, 480)
self.horizontalLayout = QtWidgets.QHBoxLayout(Form)
self.horizontalLayout.setObjectName("horizontalLayout")
self.frame = QtWidgets.QFrame(Form)
self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
self.frame.setObjectName("frame")
self.verticalLayout = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton = QtWidgets.QPushButton(self.frame)
self.pushButton.setObjectName("pushButton")
self.verticalLayout.addWidget(self.pushButton)
self.pushButton_2 = QtWidgets.QPushButton(self.frame)
self.pushButton_2.setObjectName("pushButton_2")
self.verticalLayout.addWidget(self.pushButton_2)
self.pushButton_3 = QtWidgets.QPushButton(self.frame)
self.pushButton_3.setObjectName("pushButton_3")
self.verticalLayout.addWidget(self.pushButton_3)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding)
self.verticalLayout.addItem(spacerItem)
self.horizontalLayout.addWidget(self.frame)
self.listWidget = QtWidgets.QListWidget(Form)
self.listWidget.setObjectName("listWidget")
self.horizontalLayout.addWidget(self.listWidget)
self.listWidget_2 = QtWidgets.QListWidget(Form)
self.listWidget_2.setObjectName("listWidget_2")
self.horizontalLayout.addWidget(self.listWidget_2)
self.listWidget_3 = QtWidgets.QListWidget(Form)
self.listWidget_3.setObjectName("listWidget_3")
self.horizontalLayout.addWidget(self.listWidget_3)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
# Trying to Hide both widgets upon start, but one gets hidden
self.animate_listwidget2()
self.animate_listwidget3()
self.pushButton_2.clicked.connect(self.animate_listwidget2)
self.pushButton_3.clicked.connect(self.animate_listwidget3)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "PushButton"))
self.pushButton_2.setText(_translate("Form", "toggle lw2"))
self.pushButton_3.setText(_translate("Form", "toggle lw3"))
def animate_listwidget2(self):
width = self.listWidget_2.width()
if width != 0:
width1 = 0
else:
width1 = 350
self.animation = QPropertyAnimation(self.listWidget_2, b'maximumWidth')
self.animation.setDuration(800)
self.animation.setStartValue(width)
self.animation.setEndValue(width1)
self.animation.setEasingCurve(QtCore.QEasingCurve.Type.Linear)
self.animation.start()
def animate_listwidget3(self):
width = self.listWidget_3.width()
if width != 0:
width1 = 0
else:
width1 = 350
self.animation = QPropertyAnimation(self.listWidget_3, b'maximumWidth')
self.animation.setDuration(800)
self.animation.setStartValue(width)
self.animation.setEndValue(width1)
self.animation.setEasingCurve(QtCore.QEasingCurve.Type.Linear)
self.animation.start()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec())
First of all you should not modify the code generated by QtDesigner since that could cause other bugs so to apply my solutions you have to restore the file and call it gui.py
The problem is that using the same attribute is destroying the previous animation.
There are several solutions such as changing the name of the attribute assigned to one of them (for example, changing the name of the second to self.animation2) but the implementation can still be improved since with the current one, animations are always being created unnecessarily since one is enough single for each QListWidget.
from PyQt6.QtCore import QEasingCurve, QPropertyAnimation
from PyQt6.QtWidgets import QApplication, QWidget
from gui import Ui_Form
class Form(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.ui.pushButton_2.clicked.connect(self.animate_listwidget2)
self.ui.pushButton_3.clicked.connect(self.animate_listwidget3)
self.animation1 = self.build_animation(self.ui.listWidget_2)
self.animation2 = self.build_animation(self.ui.listWidget_3)
self.animate_listwidget2()
self.animate_listwidget3()
def build_animation(self, listwidget):
animation = QPropertyAnimation(listwidget, b"maximumWidth")
animation.setDuration(800)
animation.setEasingCurve(QEasingCurve.Type.Linear)
return animation
def start_animation(self, animation):
width = animation.targetObject().width()
animation.stop()
animation.setStartValue(width)
animation.setEndValue(0 if width != 0 else 350)
animation.start()
def animate_listwidget2(self):
self.start_animation(self.animation1)
def animate_listwidget3(self):
self.start_animation(self.animation2)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = Form()
w.show()
sys.exit(app.exec())

keyPressEvent not working for Enter key in PyQt5 (but works for every other key)

I have a PyQt5 GUI which has a main window with buttons and a QLineEdit in it.
I made the keyPressEvent function and set certain keys on the keyboard to do different things. All of the keys that I set work other than the Enter button. When you press the Enter key it either triggers the number 7 onscreen pushbutton (which is the first button made in the GUI) if no onscreen pushbutton was clicked. Once a pushbutton is clicked then the Enter key will always trigger the last onscreen pushbutton that was clicked.
All the other events work fine.
Anyone know why this is happening?
MRE:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QDialog, QPushButton
from PyQt5.QtCore import*
from PyQt5.QtWidgets import*
if hasattr(QtCore.Qt, 'AA_EnableHighDpiScaling'):
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
if hasattr(QtCore.Qt, 'AA_UseHighDpiPixmaps'):
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
# I know global variables is bad programming. Just doing this for the example
outputText = ""
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setFixedSize(331, 411)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.button_7 = QtWidgets.QPushButton(self.centralwidget)
self.button_7.setGeometry(QtCore.QRect(20, 190, 71, 41))
self.button_7.setStyleSheet("QPushButton\n"
"{\n"
"border: none;\n"
"background-color: rgb(255, 255, 255);\n"
"font: 20pt \"Arial\";\n"
"}\n"
"QPushButton:hover{\n"
"background-color: rgb(220, 220, 220);\n"
"}\n"
"QPushButton:pressed\n"
"{\n"
"background-color: rgb(212, 212, 212);\n"
"}\n"
"\n"
"")
self.button_7.setAutoDefault(True)
self.button_7.setDefault(False)
self.button_7.setFlat(True)
self.button_7.setObjectName("button_7")
self.button_7.clicked.connect(self.click_and_update)
self.screenOutput = QtWidgets.QLineEdit(self.centralwidget)
self.screenOutput.setGeometry(QtCore.QRect(20, 30, 291, 20))
self.screenOutput.setStyleSheet("border: none; background: transparent;"
"font: 12pt \"MS Shell Dlg 2\";\n""color: rgb(190, 190, 190);")
self.screenOutput.setAlignment(QtCore.Qt.AlignCenter)
self.screenOutput.setObjectName("eqInput")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 331, 22))
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", " MRE"))
self.button_7.setText(_translate("MainWindow", "7"))
self.screenOutput.setText(_translate("MainWindow", "Do Something"))
# set keyPressEvent to current widgets that we'd like it to be overridden
self.centralwidget.keyPressEvent = self.keyPressEvent
self.screenOutput.keyPressEvent = self.keyPressEvent
def keyPressEvent(self,e):
if e.key() == Qt.Key_Enter:
self.equal_click()
if e.key() == Qt.Key_Equal:
self.equal_click()
def update_screen(self):
self.screenOutput.setText(outputText)
return
def equal_click(self):
global outputText
outputText = "Pressed Key"
self.update_screen()
return
def click_and_update(self):
global outputText
outputText+=" 7"
self.update_screen()
return
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_())
The Equal key works fine, the Enter key does not.
The problem is that the Enter key is associated with Qt.Key_Return, and only in keypads is it Qt.Key_Enter. So a generic solution is to check both keys:
if e.key() in (Qt.Key_Return, Qt.Key_Enter):
self.equal_click()
However, it does not correct the real error since the problem is that the button has focus, so the keypress event is not propagated to its parent.
Also it is not advisable to do foo.keyPressEvent = bar since in many cases it can fail and if you have "n" widgets you will have to implement that logic for all of them. A more elegant solution is to use an event filter on the window. So you must restore the .py file since it is not recommended to modify it (see this post: QtDesigner changes will be lost after redesign User Interface) and I will assume that it is called main_ui.py
from PyQt5 import QtCore, QtWidgets
from main_ui import Ui_MainWindow
class KeyHelper(QtCore.QObject):
keyPressed = QtCore.pyqtSignal(QtCore.Qt.Key)
def __init__(self, window):
super().__init__(window)
self._window = window
self.window.installEventFilter(self)
#property
def window(self):
return self._window
def eventFilter(self, obj, event):
if obj is self.window and event.type() == QtCore.QEvent.KeyPress:
self.keyPressed.emit(event.key())
return super().eventFilter(obj, event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def handle_key_pressed(self, key):
if key in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.update_text()
def update_text(self):
text = self.ui.screenOutput.text() + "7"
self.ui.screenOutput.setText(text)
if hasattr(QtCore.Qt, "AA_EnableHighDpiScaling"):
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
if hasattr(QtCore.Qt, "AA_UseHighDpiPixmaps"):
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
helper = KeyHelper(w.windowHandle())
helper.keyPressed.connect(w.handle_key_pressed)
sys.exit(app.exec_())

QGraphicsScene. How do I draw an ellipse over a loaded image in pyqt5?

I have a QGraphicsView with a QGraphicsScene. On QGraphicsScene, I output the image using QGraphicsPixmapItem. And I would like to draw an ellipse over the image with my mouse.
I have that code now. And the ellipse is drawn on MainWindow.
What do I need to do to have the ellipse drawn on an image in QGraphicsView?
Code OFT_MainWindow
# OFT_MainWindow
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(862, 710)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setGeometry(QtCore.QRect(10, 90, 841, 571))
self.graphicsView.setMouseTracking(True)
self.graphicsView.setObjectName("graphicsView")
self.buttonBox = QtWidgets.QDialogButtonBox(self.centralwidget)
self.buttonBox.setGeometry(QtCore.QRect(360, 670, 81, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.buttonBox.setFont(font)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(760, 10, 91, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(10, 10, 731, 31))
self.lineEdit.setObjectName("lineEdit")
self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit_2.setGeometry(QtCore.QRect(10, 670, 331, 31))
self.lineEdit_2.setObjectName("lineEdit_2")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(10, 50, 841, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.pushButton_2.setFont(font)
self.pushButton_2.setObjectName("pushButton_2")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Browse"))
self.pushButton_2.setText(_translate("MainWindow", "Highlight field area"))
Main code
import OFT_MainWindow
import sys
import os
import numpy as np
import cv2
from PIL import Image, ImageQt, ImageEnhance
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.Qt import Qt
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
class MainWindow(QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow, QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.browse_file)
self.pushButton_2.clicked.connect(self.imageFrame)
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.show()
###################################################################################
def browse_file(self):
self.lineEdit.clear()
file = QtWidgets.QFileDialog.getOpenFileName(self, "Choose file")
file = str(file[0])
if file:
self.lineEdit.setText(file) # добавить путь в lineEdit
# cap = cv2.VideoCapture(file)
###################################################################################
def imageFrame(self):
file = self.lineEdit.text()
self.drawing = False
self.lastPoint = QPoint()
scene = QtWidgets.QGraphicsScene(self)
self.image = QPixmap(file)
item = QtWidgets.QGraphicsPixmapItem(self.image)
scene.addItem(item)
view = self.graphicsView.setScene(scene)
# self.show()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
br = QtGui.QBrush(QtGui.QColor(0, 255, 0, 25))
qp.setBrush(br)
ellipse = qp.drawEllipse(QtCore.QRect(self.begin, self.end))
coord_a = self.begin
coord_a = str(coord_a)
coord_a = coord_a[20:][:-1]
coord_b = self.end
coord_b = str(coord_b)
coord_b = coord_b[20:][:-1]
coord = ('begin = ' + coord_a + ' end = ' + coord_b)
self.lineEdit_2.setText(coord)
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
###################################################################################
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.aboutToQuit.connect(app.deleteLater)
sys.exit(app.exec_())
If you want to paint something on a QGraphicsView, you have to add QGraphicsItem to its scene, otherwise you're making almost useless to crete a QGraphicsView to begin with.
One possible solution is to install an event filter on the scene, listen for mouse button events and draw an ellipse (using QGraphicsEllipseItem) on the scene if the first click is done within the contents of a QGraphicsPixmapItem.
Note that another possibility is to subclass from QGraphicsPixmapItem and implement its mouse events instead. It all depends on what you're going to do and what you're going to need from your program.
class MainWindow(QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# ...
self.ellipseItem = None
def imageFrame(self):
# ...
scene.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.GraphicsSceneMousePress:
for item in self.graphicsView.scene().items(event.scenePos()):
if isinstance(item, QtWidgets.QGraphicsPixmapItem):
self.reference = item
self.ellipseItem = QtWidgets.QGraphicsEllipseItem(item)
self.ellipseItem.setBrush(QtGui.QColor(0, 255, 0, 25))
self.start = item.mapFromScene(event.scenePos())
elif event.type() == QtCore.QEvent.GraphicsSceneMouseMove and self.ellipseItem:
end = self.reference.mapFromScene(event.scenePos())
self.ellipseItem.setRect(QtCore.QRectF(self.start, end))
elif event.type() == QtCore.QEvent.GraphicsSceneMouseRelease and self.ellipseItem:
self.ellipseItem = None
return super().eventFilter(source, event)
Note that subclassing your Main window from all those classes (QtWidgets.QMainWindow, OFT_MainWindow.Ui_MainWindow, QtWidgets.QGraphicsView, QtWidgets.QGraphicsScene) is not only unnecessary and meaningless, but absolutely WRONG: multiple-inheritance subclassing should only be done when you know what you're inheriting from and why, otherwise, just don't. For Qt widgets that load from UI files, just subclass from the base widget class and the Ui.

Clear QLineEdit on click event

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 :

How to create keyboard and mouse events with Pyqt widgets

I've just started doing Qt designing using python 3.x in Pycharms. I've watched a tuturial converting a .ui file to .py file. I'm good right now. I'm implementing a chat program.
Now, I want to type in TextEdit, linEdit but it dosen't wait for me type. I want to connect a keyboard or mouse event with them so when i click, it wait for me to type and when I hit Enter it stores the string.
The code between space and #here that's where I need help with. Basically I want to def methods for these events and calling them from them later.
My Ui_MainWindow class is as follows:
class Ui_MainWindow(QtGui.QMainWindow):
def __init__(self):
super(Ui_MainWindow,self).__init__()
self.setObjectName(_fromUtf8("MainWindow"))
self.resize(611, 487)
self.setTabShape(QtGui.QTabWidget.Rounded)
self.centralwidget = QtGui.QWidget(self)
self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
self.frame = QtGui.QFrame(self.centralwidget)
self.frame.setGeometry(QtCore.QRect(10, 30, 591, 41))
self.frame.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame.setFrameShadow(QtGui.QFrame.Raised)
self.frame.setObjectName(_fromUtf8("frame"))
self.label = QtGui.QLabel(self.frame)
self.label.setGeometry(QtCore.QRect(10, 10, 81, 17))
self.label.setObjectName(_fromUtf8("label"))
self.label_2 = QtGui.QLabel(self.frame)
self.label_2.setGeometry(QtCore.QRect(320, 10, 66, 17))
self.label_2.setObjectName(_fromUtf8("label_2"))
#Here
self.lineEdit = QtGui.QLineEdit(self.frame)
self.lineEdit.setGeometry(QtCore.QRect(90, 10, 221, 21))
self.lineEdit.setObjectName(_fromUtf8("lineEdit"))
#Here
self.lineEdit_3 = QtGui.QLineEdit(self.frame)
self.lineEdit_3.setGeometry(QtCore.QRect(360, 10, 221, 21))
self.lineEdit_3.setObjectName(_fromUtf8("lineEdit_3"))
self.frame_2 = QtGui.QFrame(self.centralwidget)
self.frame_2.setGeometry(QtCore.QRect(10, 70, 291, 361))
self.frame_2.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtGui.QFrame.Raised)
self.frame_2.setObjectName(_fromUtf8("frame_2"))
#Here
self.textEdit = QtGui.QTextEdit(self.frame_2)
self.textEdit.setGeometry(QtCore.QRect(10, 10, 271, 301))
self.textEdit.setObjectName(_fromUtf8("textEdit"))
self.pushButton_3 = QtGui.QPushButton(self.frame_2)
self.pushButton_3.setGeometry(QtCore.QRect(10, 310, 161, 41))
self.pushButton_3.setObjectName(_fromUtf8("pushButton_3"))
self.pushButton_4 = QtGui.QPushButton(self.frame_2)
self.pushButton_4.setGeometry(QtCore.QRect(180, 310, 98, 41))
self.pushButton_4.setObjectName(_fromUtf8("pushButton_4"))
self.pushButton_4.clicked.connect(self.clrLogs) # Clear Logs from WidgetList by clicking
self.verticalScrollBar = QtGui.QScrollBar(self.frame_2)
self.verticalScrollBar.setGeometry(QtCore.QRect(260, 10, 20, 301))
self.verticalScrollBar.setMinimumSize(QtCore.QSize(16, 301))
self.verticalScrollBar.setCursor(QtGui.QCursor(QtCore.Qt.SizeVerCursor))
self.verticalScrollBar.setAutoFillBackground(False)
self.verticalScrollBar.setOrientation(QtCore.Qt.Vertical)
self.verticalScrollBar.setInvertedAppearance(False)
self.verticalScrollBar.setObjectName(_fromUtf8("verticalScrollBar"))
######################################################
# Scroll to the bottom of chat windows
# self.textEdit.verticalScrollBar().setValue(self.textEdit.verticalScrollBar().maximum)
self.frame_3 = QtGui.QFrame(self.centralwidget)
self.frame_3.setGeometry(QtCore.QRect(300, 70, 301, 361))
self.frame_3.setFrameShape(QtGui.QFrame.StyledPanel)
self.frame_3.setFrameShadow(QtGui.QFrame.Raised)
self.frame_3.setObjectName(_fromUtf8("frame_3"))
self.listWidget = QtGui.QListWidget(self.frame_3)
self.listWidget.setGeometry(QtCore.QRect(10, 10, 281, 341))
self.listWidget.setObjectName(_fromUtf8("listWidget"))
self.verticalScrollBar_2 = QtGui.QScrollBar(self.frame_3)
self.verticalScrollBar_2.setGeometry(QtCore.QRect(270, 10, 21, 341))
self.verticalScrollBar_2.setOrientation(QtCore.Qt.Vertical)
self.verticalScrollBar_2.setObjectName(_fromUtf8("verticalScrollBar_2"))
self.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(self)
self.menubar.setGeometry(QtCore.QRect(0, 0, 611, 25))
self.menubar.setObjectName(_fromUtf8("menubar"))
self.menuMenu_Actions = QtGui.QMenu(self.menubar)
self.menuMenu_Actions.setObjectName(_fromUtf8("menuMenu_Actions"))
self.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(self)
self.statusbar.setObjectName(_fromUtf8("statusbar"))
self.setStatusBar(self.statusbar)
self.actionVersion = QtGui.QAction(self)
self.actionVersion.setObjectName(_fromUtf8("actionVersion"))
self.actionVersion.triggered.connect(Chat.app_ver) # When submenu Action item Version is clicked
self.actionExit = QtGui.QAction(self)
self.actionExit.setObjectName(_fromUtf8("actionExit"))
self.actionExit.triggered.connect(qApp.quit) #When submenu Action item Exit is clicked
self.menuMenu_Actions.addAction(self.actionVersion)
self.menuMenu_Actions.addAction(self.actionExit)
self.menubar.addAction(self.menuMenu_Actions.menuAction())
self.retranslateUi(self)
QtCore.QMetaObject.connectSlotsByName(self)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", WindowTitle, None))
self.setWindowIcon(QtGui.QIcon('chat_icon'))
self.label.setText(_translate("MainWindow", "IP Address:", None))
self.label_2.setText(_translate("MainWindow", "Nick:", None))
self.pushButton_3.setText(_translate("MainWindow", "Send SMS", None))
self.pushButton_4.setText(_translate("MainWindow", "Clear Logs", None))
self.menuMenu_Actions.setTitle(_translate("MainWindow", "Menu Actions", None))
self.actionVersion.setText(_translate("MainWindow", "Version", None))
self.actionExit.setText(_translate("MainWindow", "Exit", None))
def clrLogs(self):
self.listWidget.clear()
The big left is TextEdit and rightmost is listWidget. I want to type in TextEdit and stores it and and send this msg to Chatlog(ListWidget).
I would start saying that you have to care about the following things:
Your keyboard UI, let's say a small prototype.
Be aware of who is getting your keyboard focus.
Take care of your filter to catch the events you need.
Send the right response to the claimant object from your keyboard.
I'd show your here some really nice example I've spent some considerable time to do and another one really simple and small. Since it's a quite amount of code I'd be leaving this small example and this more complex example from my github.
You can clone or copy and paste the code, just be sure it comes with the right imports if you copy and paste.
Edited[Added]
Here is the small example catching the events from the receiver you pass, and posting the equivalent events:
import sys
from PyQt5.QtCore import QCoreApplication
from PyQt5.QtCore import QEvent
from PyQt5.QtCore import Qt
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QWidget
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.central_widget = QWidget()
self.cw_layout = QHBoxLayout()
self.central_widget.setLayout(self.cw_layout)
self.setCentralWidget(self.central_widget)
self.line = LineEdit()
self.kb = KeyBoard(self.line)
self.cw_layout.addWidget(self.line)
self.create_connections()
def create_connections(self):
self.line.signal_evoke_kb.connect(self.show_kb)
def show_kb(self):
if self.kb.isHidden():
self.kb.show()
else:
self.kb.hide()
class LineEdit(QLineEdit):
signal_evoke_kb = pyqtSignal()
def __init__(self):
super(LineEdit, self).__init__()
def mousePressEvent(self, QMouseEvent):
super(LineEdit, self).mousePressEvent(QMouseEvent)
self.signal_evoke_kb.emit()
class Key(QPushButton):
def __init__(self, name, event, receiver):
super(Key, self).__init__()
self.name = name
self.event = event
self.setText(name)
class KeyBoard(QWidget):
def __init__(self, receiver):
super(KeyBoard, self).__init__()
self.receiver = receiver
self.layout = QHBoxLayout()
self.keys = ['q','w','e','r','t','y']
self.dict_keys ={'q':Qt.Key_Q,'w':Qt.Key_W,'e':Qt.Key_E,'r':Qt.Key_R,'t':Qt.Key_T,'y':Qt.Key_Y,}
for key in self.keys:
key_keyboard = Key(key,self.dict_keys[key],receiver)
key_keyboard.clicked.connect(self.key_pressed)
self.layout.addWidget(key_keyboard)
self.setLayout(self.layout)
def key_pressed(self):
try:
event = QKeyEvent(QEvent.KeyPress, self.sender().event, Qt.NoModifier,
self.sender().name, False)
QCoreApplication.postEvent(self.receiver, event)
except Exception as e:
print(e)
def keyPressEvent(self, evt):
event = QKeyEvent(QEvent.KeyPress, evt.key(), evt.modifiers(),
evt.text(), False)
QCoreApplication.postEvent(self.receiver, event)
evt.ignore()
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
In this way you can personalize your key since your have your own Key, and organize it better when you need upper case and all else. If you are willing to do that I'd strongly recommend looking at the more complete example I linked before.

Categories

Resources