Снятие фокуса с lineedit в PyQt5

Я решил создать анимированное поле для ввода на PyQt5 для своего проекта и столкнулся со следующей проблемой: при нажатии на другое поле фокус с других не убирается.

проблема

Код:

import sys
import re
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *


class animatedLineEdit(QLineEdit):
    def __init__(self, *args, **kwargs):
        QLineEdit.__init__(self, *args, **kwargs)
        self.installEventFilter(self)

        self.co_set = 0

        byar = QByteArray()
        byar.append('texcolor')

        self.click_anim = QPropertyAnimation(self, byar)
        self.click_anim.setEndValue('#2979ff')
        self.click_anim.setDuration(170)
        self.click_anim.setLoopCount(1)

        self.off_anim = QPropertyAnimation(self, byar)
        self.off_anim.setEndValue('#f5f5f5')
        self.off_anim.setDuration(150)
        self.off_anim.setLoopCount(1)
        self.off_anim.start()

        self.on_anim = QPropertyAnimation(self, byar)
        self.on_anim.setEndValue('#e6e6e6')
        self.on_anim.setDuration(50)
        self.on_anim.setLoopCount(1)

        self.focusOutEvent = self.offClicked
        self.mousePressEvent = self.onClicked

    def parseStyleSheet(self):
        ss = self.styleSheet()
        sts = [s.strip() for s in ss.split(';') if len(s.strip())]
        return sts

    def offClicked(self, *args, **kwargs):
        if self.isEnabled():
            self.off_anim.start()

    def onClicked(self, *args, **kwargs):
        if self.isEnabled():
            self.click_anim.start()

    def getBackColor(self):
        return self.palette().color(self.pal_ele)

    def setBackColor(self, color):
        self.co_set += 1
        sss = self.parseStyleSheet()
        bg_new = 'border: 2px solid rgba(%d,%d,%d,%d); border-width: 0 0 2px 0;' % (color.red(), color.green(), color.blue(), color.alpha())

        for k, sty in enumerate(sss):
            if re.search('\Aborder:', sty):
                sss[k] = bg_new
                break
        else:
            sss.append(bg_new)

        self.setStyleSheet('; '.join(sss))

    pal_ele = QPalette.Window
    texcolor = pyqtProperty(QColor, getBackColor, setBackColor)
if __name__ == "__main__":
    class Test(QWidget):
        def __init__(self, parent=None):
            QWidget.__init__(self, parent)
            self.setWindowTitle('Animation test')
            self.main = QVBoxLayout()

            for q in range(5):
                layout = QHBoxLayout()
                for i in range(5):
                    linedit = animatedLineEdit(f'Line{str(q)}{str(i)}')
                    linedit.setFixedSize(100, 30)
                    layout.addWidget(linedit)
                self.main.addLayout(layout)
            self.setLayout(self.main)


    app = QApplication(sys.argv)
    main = Test()
    main.show()

    app.exec_()


Ответы (1 шт):

Автор решения: S. Nick

Попробуйте так:

import sys
import re
from PyQt5.Qt import *


class AnimatedLineEdit(QLineEdit):
    clicked = pyqtSignal(object)                                       # +++
    
    def __init__(self, *args, **kwargs):
        QLineEdit.__init__(self, *args, **kwargs)
        self.installEventFilter(self)
        self.co_set = 0
        byar = QByteArray()
        byar.append('texcolor')

        self.click_anim = QPropertyAnimation(self, byar)
        self.click_anim.setEndValue('#2979ff')
        self.click_anim.setDuration(170)
        self.click_anim.setLoopCount(1)

        self.off_anim = QPropertyAnimation(self, byar)
        self.off_anim.setEndValue('#f5f5f5')
        self.off_anim.setDuration(150)
        self.off_anim.setLoopCount(1)
        self.off_anim.start()

        self.on_anim = QPropertyAnimation(self, byar)
        self.on_anim.setEndValue('#e6e6e6')
        self.on_anim.setDuration(50)
        self.on_anim.setLoopCount(1)

# -       self.focusOutEvent = self.offClicked                         # ---
        self.mousePressEvent = self.onClicked

    def parseStyleSheet(self):
        ss = self.styleSheet()
        sts = [s.strip() for s in ss.split(';') if len(s.strip())]
        return sts

    def offClicked(self, *args, **kwargs):
        if self.isEnabled():
            self.off_anim.start()

    def onClicked(self, *args, **kwargs):
        self.clicked.emit(self)                                        # +++
        if self.isEnabled():
            self.click_anim.start()

    def getBackColor(self):
        return self.palette().color(self.pal_ele)

    def setBackColor(self, color):
        self.co_set += 1
        sss = self.parseStyleSheet()
        bg_new = 'border: 2px solid rgba(%d,%d,%d,%d); border-width: 0 0 2px 0;' % (color.red(), color.green(), color.blue(), color.alpha())

        for k, sty in enumerate(sss):
            if re.search('\Aborder:', sty):
                sss[k] = bg_new
                break
        else:
            sss.append(bg_new)

        self.setStyleSheet('; '.join(sss))

    pal_ele = QPalette.Window
    texcolor = pyqtProperty(QColor, getBackColor, setBackColor)
 

class Test(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Animation test')
        self.main = QVBoxLayout(self)

        self.linedits = {}                                             # +++
        for r in range(5):
            layout = QHBoxLayout()
            for c in range(5):
                linedit = AnimatedLineEdit(f'Line{str(r)}{str(c)}')
                linedit.setFixedSize(100, 30)
                
                linedit.setFocusPolicy(Qt.ClickFocus)                  # +++  
                self.linedits[f'{r}{c}'] = linedit                     # +++
                linedit.clicked.connect(self.on_clicked)               # +++
                layout.addWidget(self.linedits[f'{r}{c}'])
                
            self.main.addLayout(layout)

# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv            
    def on_clicked(self, lineEdit):
        for le in self.linedits.values():    
            if le != lineEdit:
                le.offClicked()
            else:
                lineEdit.setFocus()
   
    
if __name__ == "__main__":
    app = QApplication(sys.argv)
    main = Test()
    main.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка