2016-12-30 7 views
2

Я работаю над проектом с участием PyQt5, и я борюсь с управлением наследованием между виджетами.Python - как заставить это множественное наследование работать?

У меня есть один экран QWidget, который наследует QtWidgets.QWidget и другой класс, который генерируется QtDesigner. Он читает что-то вроде этого:

class a(QtWidgets.QWidget, Ui_a): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init__(self, parent) 
     self.setupUi(self) 

     <some attributes> 

    <some functions 

Здесь я унаследовать от Ui_a, отдельный класс хранится в созданном файле, и я могу назвать setupUi (метод Ui_a) штрафа.

Теперь я хочу создать еще один класс b, который также является QWidget, который необходимо отобразить. Этот класс b требует использования некоторых функций и атрибутов из класса a. Я могу просто скопировать вставку необходимых материалов, но это плохая практика, поэтому я ищу более аккуратное решение. Если я код:

class b(QtWidgets.QWidget, Ui_b, a): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init(self, parent) 
     self.setupUi(self) 

Это то происходит сбой с сообщением об ошибке, что он не может создать последовательный порядок разрешения метода.

Мой первый вопрос: я знаю, что мне нужно вызвать метод init класса a, так как там созданы атрибуты a, но я не знаю, как это сделать.

Мой второй вопрос: как исправить эту ошибку MRO и создать новый класс b, который может использовать атрибуты и функции a?

+0

Посмотрите на http://stackoverflow.com/questions/1848474/method-resolution-order-mro-in-new-style-python-classes – dahrens

+0

Возможный дубликат [TypeError: невозможно создать согласованный порядок разрешения метода (MRO)] (http://stackoverflow.com/questions/29214888/typeerror-cannot-create-a-consistent-m ethod-resolution-order-mro) – whereswalden

ответ

5

Вы пытаетесь смешивать родительские классы перед производным классом. Там нет необходимости, просто наследовать непосредственно от a и нового Ui_b и ничего:

class b(a, Ui_b): 
    # *no* __init__ needed either 

a уже тянет в QtWidgets.QWidget.

Ui_a и Ui_bмай не играет хорошо вместе. Возможно, вам придется вызвать как Ui_a.setupUi(), так и Ui_b.setupUi(). Вы можете сделать это явно:

class b(a, Ui_b): 
    def __init__(self, parent=None): 
     super().__init__(parent) 
     # Ui_b.setupUi would have shadowed Ui_a.setupUi, so 
     # call the latter explicitly 
     Ui_a.setupUi(self, self) # unbound 

Может быть, Ui_a и Ui_b не могут быть смешаны на всех. В этом случае вам нужно просто вытащить все методы, которые вы хотите использовать повторно в отдельном базовом классе и имеют как a и b наследуют от этого:

class SharedStuff: 
    # ... 

class a(QtWidgets.QWidget, SharedStuff, Ui_a): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init__(self, parent) 
     self.setupUi(self) 

class b(QtWidgets.QWidget, SharedStuff, Ui_b): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init__(self, parent) 
     self.setupUi(self) 
+0

Говоря, что «Ui_a' и' Ui_b' могут плохо сочетаться друг с другом », является довольно преуменьшением, если они были сгенерированы из файлов конструктора qt (откуда приходит метод' setupUi') , Как правило, небезопасно вызывать 'setupUi' более одного раза с теми же аргументами (хотя он может все еще« работать »через безумную удачу). – ekhumoro

+0

@ekhumoro: У меня есть 0 опыт работы с qt, не говоря уже о автоматически сгенерированном коде. Добавлен альтернативный вариант. –

0

Ваш вопрос немного неясно, но я собираюсь предположим, что Ui_a и Ui_b не являются и классами, созданными из файлов конструктора Qt, потому что нет никакого разумного способа наследования от двух таких классов.

Я предполагаю, что текущие классы эквивалентны следующему:

class A(QtWidgets.QWidget, Ui_FromQtDesigner): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init__(self, parent) 
     self.setupUi(self) 

    def methodA(self): 
     print('A:', self.windowTitle()) 

class B(QtWidgets.QWidget): 
    def __init__(self, parent=None): 
     QtWidgets.QWidget.__init__(self, parent) 

    def methodB(self): 
     print('B:', self.windowTitle()) 

и вы хотите класс C который будет QWidget подкласс, который получает как элементы конструктора пользовательского интерфейса Qt и пользовательские методы из классов A и B.

Теперь Qt использует одиночный наследование почти исключительно. Наследование от двух классов QWidget обычно является ошибкой, если только классы не имеют общего набора базовых классов (и даже тогда существует ряд ограничений, которые по-прежнему делают сомнительный выбор дизайна - более подробно см. this blog post).

В вашем случае было бы лучше использовать простой класс mixin. Это только действительно необходимо для класса A наследовать от QWidget, поэтому множество классов может быть определена следующим образом:

class WidgetA(QtWidgets.QWidget, Ui_FromQtDesigner): 
    def __init__(self, parent=None): 
     super(WidgetA, self).__init__(parent) 
     self.setupUi(self) 

    def methodA(self): 
     print('A:', self.windowTitle()) 

class WidgetMixinB(object): 
    def methodB(self): 
     print('B:', self.windowTitle()) 

class WidgetC(WidgetA, WidgetMixinB): 
    pass 

И если вы хотите использовать WidgetMixinB в качестве виджета в своем собственном праве, вы можете создать другой класс для него, как это:

class WidgetB(QtWidgets.QWidget, WidgetMixinB): 
    pass 
Смежные вопросы