12

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"))
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
adam
  • 179
  • 1
  • 1
  • 12
  • Why not just clear the line-edit automatically instead of requiring an extra mouse-click? Also, wouldn't it be nicer if the user could just press enter to copy the text? – ekhumoro Oct 10 '17 at 16:36
  • @ekhumoro The application I'm working on uses the QLineEdit fields a bit differently then the given example code. After the user enters a ticker code, the inputted text is changed to show the full company name associated with the ticker code entered by user (as a reference and confirmation). The enter shortcut has been implemented in my example. – adam Oct 10 '17 at 16:50
  • I still don't understand why you need the extra mouse-click. Why not just reset the line-edit in the `copy_and_print` slot? And what if the user wants to use the mouse to move the caret in the line-edit? It would be pretty annoying if that cleared the current text. – ekhumoro Oct 10 '17 at 17:17
  • @ekhumoro As I said, the inputted ticker code in the QLineEdit field will be replaced by the full company name. I want this information to stay visible as a reference until the user decides to enter a new ticker code. If I clear the QLineEdit in the copy_and_print(), it will disappear after the user clicks the button. Unless I misunderstand what you're saying... – adam Oct 10 '17 at 17:37

5 Answers5

11

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 ...:

enter image description here

A menu will open and place the following

enter image description here

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_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Thanks for the quick answer, I had indeed missed this option. Having said that, is it possible to replicate the same behaviour without the clearButton? By having the user click anywhere in the QLineEdit field? Also, if is not possible, can the colors of the clearButton be modified? – adam Oct 10 '17 at 16:28
  • Sorry about that. I'll come back to you as soon as I have tried your solution. Thank you. – adam Oct 10 '17 at 16:56
4
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()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
2

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 :

ButtonPanel

Udesh
  • 2,415
  • 2
  • 22
  • 32
2

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

user662650
  • 176
  • 1
  • 12
1

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

  • mmm, it is a solution but I do not think it is optimal since the mouseReleaseEvent: https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qlineedit.cpp?h=dev#n1598 method implements other things that with your solution do not cancel – eyllanesc Oct 15 '19 at 18:17
  • You can change mouseReleaseEvent by mousePressEvent – Javier Escalona Oct 15 '19 at 18:44
  • the same problem: you eliminate the default behavior that causes secondary problems: https://code.qt.io/cgit/qt/qtbase.git/tree/src/widgets/widgets/qlineedit.cpp?h=dev#n1551 – eyllanesc Oct 15 '19 at 18:46
  • yes sure, it is a solution too simple to be the best, the parsimony principle does not apply here. – Javier Escalona Oct 15 '19 at 19:07
  • My comment is to warn the community of the inconveniences of your solution. – eyllanesc Oct 15 '19 at 19:09
  • thanks for that, I was not realizing that I was replacing a method that had other functionalities – Javier Escalona Oct 15 '19 at 19:11