Как мне использовать функцию на двух классах?

У меня есть вот такой код

class Radio(QRadioButton): 
    def __init__(self, icon, size, margin, parent=None):
        super(Radio, self).__init__(parent)
        change_color(self)
        self._animation = QtCore.QVariantAnimation(
            startValue=QtGui.QColor("red"),  
            endValue=QtGui.QColor("white"), 
            valueChanged=self._on_value_changed,
            duration=400,
        )
        self._update_stylesheet(QtGui.QColor("blue"), QtGui.QColor("black")) 
        self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))


    def _on_value_changed(self, color):
        foreground = (
            QtGui.QColor("yellow")  
            if self._animation.direction() == QtCore.QAbstractAnimation.Forward
            else QtGui.QColor("green") 
        )
        self._update_stylesheet(color, foreground)


    def _update_stylesheet(self, background, foreground):
        self.setStyleSheet(
        """
            background-color: %s;
            color: %s;
        """
            % (background.name(), foreground.name())
        )

    def enterEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()
        super().enterEvent(event)

    def leaveEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()
        super().leaveEvent(event)


class Label(QLabel): 
    def __init__(self, icon, size, margin, parent=None):
        super(Label, self).__init__(parent)
        change_color(self)
        self._animation = QtCore.QVariantAnimation(
            startValue=QtGui.QColor("red"),  
            endValue=QtGui.QColor("white"), 
            valueChanged=self._on_value_changed,
            duration=400,
        )
        self._update_stylesheet(QtGui.QColor("blue"), QtGui.QColor("black")) 
        self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))


    def _on_value_changed(self, color):
        foreground = (
            QtGui.QColor("yellow")  
            if self._animation.direction() == QtCore.QAbstractAnimation.Forward
            else QtGui.QColor("green")  
        )
        self._update_stylesheet(color, foreground)


    def _update_stylesheet(self, background, foreground):
        self.setStyleSheet(
        """
            background-color: %s;
            color: %s;
        """
            % (background.name(), foreground.name())
        )

    def enterEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()
        super().enterEvent(event)

    def leaveEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()
        super().leaveEvent(event)

И я хочу написать функцию чтобы сократить код

def color(self):
    def face_init(self):
        self._animation = QtCore.QVariantAnimation(
            startValue=QtGui.QColor("red"),  
            endValue=QtGui.QColor("white"),  
            valueChanged=self._on_value_changed,
            duration=400,
        )
        self._update_stylesheet(QtGui.QColor("blue"), QtGui.QColor("black"))  
        self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))


    def _on_value_changed(self, color):
        foreground = (
            QtGui.QColor("yellow")  
            if self._animation.direction() == QtCore.QAbstractAnimation.Forward
            else QtGui.QColor("green")  
        )
        self._update_stylesheet(color, foreground)


    def _update_stylesheet(self, background, foreground):
        self.setStyleSheet(
        """
            background-color: %s;
            color: %s;
        """
            % (background.name(), foreground.name())
        )

    def enterEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()
        super().enterEvent(event)

    def leaveEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()
        super().leaveEvent(event)

class Radio(QRadioButton): 
    def __init__(self, icon, size, margin, parent=None):
        super(Radio, self).__init__(parent)
        color(self)

class Label(QLabel): 
    def __init__(self, icon, size, margin, parent=None):
        super(Label, self).__init__(parent)
        color(self)

Но проблема в том что я все еще плохо знаю как работать с классами. Я могу обработать только то что находится внутри одного метода

def color(self):
    self._animation = QtCore.QVariantAnimation(
        startValue=QtGui.QColor("red"), 
        endValue=QtGui.QColor("white"), 
        valueChanged=self._on_value_changed,
        duration=400,
    )
    return self

Но как запихнуть в функцию все методы _on_value_changed, _update_stylesheet,enterEvent,leaveEvent. Я не знаю.


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

Автор решения: gil9red

Это типичная задача ООП -- наследование.

Оформляйте color как класс от QWidget и указываете его предком для Radio и Label.

Пример:

class MyColor(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.face_init()

    def face_init(self):
        self._animation = QtCore.QVariantAnimation(
            startValue=QtGui.QColor("red"),
            endValue=QtGui.QColor("white"),
            valueChanged=self._on_value_changed,
            duration=400,
        )
        self._update_stylesheet(QtGui.QColor("blue"), QtGui.QColor("black"))
        self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))

    def _on_value_changed(self, color):
        foreground = (
            QtGui.QColor("yellow")
            if self._animation.direction() == QtCore.QAbstractAnimation.Forward
            else QtGui.QColor("green")
        )
        self._update_stylesheet(color, foreground)

    def _update_stylesheet(self, background, foreground):
        self.setStyleSheet(
        """
            background-color: %s;
            color: %s;
        """
            % (background.name(), foreground.name())
        )

    def enterEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Backward)
        self._animation.start()
        super().enterEvent(event)

    def leaveEvent(self, event):
        self._animation.setDirection(QtCore.QAbstractAnimation.Forward)
        self._animation.start()
        super().leaveEvent(event)


class Radio(QRadioButton, MyColor):
    def __init__(self, icon, size, margin, parent=None):
        super().__init__()


class Label(QLabel, MyColor):
    def __init__(self, icon, size, margin, parent=None):
        super().__init__()

Пример запуска

from PyQt5.QtWidgets import QWidget, QRadioButton, QLabel, QApplication
from PyQt5 import QtCore
from PyQt5 import QtGui

...

app = QApplication([])

b = Radio(1, 2, 3)
b.setText('[Button] Hello World!')
b.show()

l = Label(1, 2, 3)
l.setText('[Label] Hello World!')
l.show()

app.exec()

PS.

Для отлова ошибок советую использовать sys.excepthook. Пока отлаживал ответ, мне очень пригодилось.

Пример:

from PyQt5.QtWidgets import QMessageBox

...

def log_uncaught_exceptions(ex_cls, ex, tb):
    text = '{}: {}:\n'.format(ex_cls.__name__, ex)
    import traceback
    text += ''.join(traceback.format_tb(tb))

    print(text)
    QMessageBox.critical(None, 'Error', text)
    quit()


import sys
sys.excepthook = log_uncaught_exceptions

...

app = QApplication([])
→ Ссылка