pythonqtqpushbuttonqlineeditpyqt6

How to change EchoMode of QLineEdit between Normal and Password


I am writing a little program, but the buttons don't work as I expected.

I wish the text to change state when I click on the button of that text.

Here is the code to test it:

from sys import exit
from sys import argv
from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QWidget, QLineEdit

class MainWindow(QWidget):
    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        self.screenWidth = 1920
        self.screenHeight = 1080
        self.windowWidth = 1000
        self.windowHeight = 800
        self.setWindowTitle("test 19")
        self.setGeometry((self.screenWidth - self.windowWidth) // 2, (self.screenHeight - self.windowHeight) // 2, self.windowWidth, self.windowHeight)
        self.initUi()
    
    def initUi(self) -> None:
        mainLayout = QVBoxLayout()
        headLayout = QHBoxLayout()
        nameLabel = QLabel("Name")
        headLayout.addWidget(nameLabel)
        mainLayout.addItem(headLayout)
        row1 = Row("google.com")
        mainLayout.addItem(row1.returnValues())
        row2 = Row("yahoo.com")
        mainLayout.addItem(row2.returnValues())
        for i in range(20):
            rowi = Row(f"{i}")
            mainLayout.addItem(rowi.returnValues())
        self.setLayout(mainLayout)

class Row():
    def __init__(self, name) -> None:
        super().__init__()
        self.rowLayout = QHBoxLayout()
        self.nameLineEdit = QLineEdit(f"{name}")
        self.nameLineEdit.setDisabled(True)
        self.rowLayout.addWidget(self.nameLineEdit)
        self.hiddenOrShowButton = QPushButton("")
        self.hiddenOrShowButton.clicked.connect(self.hiddenOrShow)
        self.rowLayout.addWidget(self.hiddenOrShowButton)
    
    def returnValues(self) -> QHBoxLayout:
        return self.rowLayout
    
    def hiddenOrShow(self) -> None:
        if self.nameLineEdit.echoMode() == QLineEdit.EchoMode.Password:
            self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Normal)
        else:
            self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Password)


if __name__ == "__main__":
    app = QApplication(argv)
    window = MainWindow()
    window.show()
    exit(app.exec())

I expect the text to change state when I click on the button of that text.


Solution

  • Your best bet is to subclass QHBoxLayout, as suggested by musicamante in the comments, and your Row class isn't that far off from doing just that.

    The only changes that really need to be made are to add in the subclass reference in your Row to Row(QHBoxLayout), then would want to remove the self.rowLayout line because the Row class would become the layout. and you would change all the references to it to just self instead of self.rowLayout.

    For example:

    from sys import exit
    from sys import argv
    from PyQt6.QtWidgets import QApplication, QHBoxLayout, QPushButton, QVBoxLayout, QLabel, QWidget, QLineEdit
    
    class MainWindow(QWidget):
        def __init__(self, parent=None) -> None:
            super().__init__(parent)
            self.screenWidth = 1920
            self.screenHeight = 1080
            self.windowWidth = 1000
            self.windowHeight = 800
            self.setWindowTitle("test 19")
            self.setGeometry((self.screenWidth - self.windowWidth) // 2, (self.screenHeight - self.windowHeight) // 2, self.windowWidth, self.windowHeight)
            self.initUi()
    
        def initUi(self) -> None:
            mainLayout = QVBoxLayout()
            headLayout = QHBoxLayout()
            nameLabel = QLabel("Name")
            headLayout.addWidget(nameLabel)
            mainLayout.addLayout(headLayout)
            row1 = Row("google.com")   # the row now is the layout
            mainLayout.addLayout(row1)   # so you add it directly to the main layout
            row2 = Row("yahoo.com")
            mainLayout.addLayout(row2)   # use addLayout instead of addItem
            for i in range(20):
                rowi = Row(f"{i}")
                mainLayout.addLayout(rowi)
            self.setLayout(mainLayout)
    
    class Row(QHBoxLayout):  # use subclass declaration
        def __init__(self, name):
            super().__init__()
            self.nameLineEdit = QLineEdit(f"{name}")
            self.nameLineEdit.setDisabled(True)  
            self.addWidget(self.nameLineEdit)    # add the widget to self
            self.hiddenOrShowButton = QPushButton("")   
            self.hiddenOrShowButton.clicked.connect(self.hiddenOrShow)
            self.addWidget(self.hiddenOrShowButton)   # same thing here
    
        # the returnValues method can be removed.
    
        def hiddenOrShow(self) -> None:
            if self.nameLineEdit.echoMode() == QLineEdit.EchoMode.Password:
                self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Normal)
            else:
                self.nameLineEdit.setEchoMode(QLineEdit.EchoMode.Password)
    
    
    if __name__ == "__main__":
        app = QApplication(argv)
        window = MainWindow()
        window.show()
        exit(app.exec())