Search code examples
pythonclassqcombobox

Python: select from a list of subclasses


i am a beginner of python and programming in general. I am trying to write a small program for some calculations. I have a material: concrete and several types of it. I created a base Concrete and several subclasses. Base class Concrete has some attributes that are equal for all subclasses.

class Concrete:
    self.Name = name  #
    self.Rb = rb   #changes depending on concrete subclass
    self.alphabt = 0.0001 #equal for every concrete subclass

class concreteB25(Concrete):
    self.Name = 'B25'
    self.Rb = 25.0
 class concreteB30(Concrete):
    self.Name = 'B30'
    self.Rb = 30.0

User should select a concrete class. So i have two questions:1. How do i access the value that is equal for all subclasses(alphabt in this case). 2. how do i keep the chosen concrete? I am trying to use QCombobox but can't figure out how to use it properly for assigning.

import sys
from PyQt5.QtWidgets import (QWidget,QComboBox,QLabel,QApplication)
import materials

class Form(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
    def initUI(self):
        self.lbl = QLabel("Concrete",self)
        self.combo = QComboBox(self)
        concreteclasses = ['B25', 'B30']
        self.combo.addItems(concreteclasses)
        self.combo.move(50, 50)
        self.combo.activated[str].connect(self.onActivated)
        self.setGeometry(300,300,300,200)
        self.setWindowTitle('ConcreteComboBox')
        self.show()

    def onActivated(self, text):
        chosenclass = self.combo.itemText(self.combo.currentIndex())
        chosenConcrete = None
        if chosenclass == 'B25':
            chosenConcrete = materials.concreteB25()
        else:
            chosenConcrete = materials.concreteB30()

in materials i have concrete classes declared. Can anyone tell/suggest/help what i am doing wrong or show an example of same usage.

Thank you in advance.


Solution

  • I don't use Qt, so I can't help you with that side of things, but I can offer some suggestions to improve your class.

    You don't need subclasses for the different types of concrete, just create instances of your Concrete class. To do that, you need to give the class an __init__ method.

    The alphabt attribute can be defined as a class attribute, which is shared by all instances of the class.

    It's a Good Idea to give a class a __repr__ and/or __str__ method so it provides useful information when you convert it to a string, either explicitly or when using print.

    class Concrete(object):
        alphabt = 0.0001
    
        def __init__(self, name, rb):
            self.name = name
            self.rb = rb
    
        def __repr__(self):
            return 'Concrete({0}, {1})'.format(self.name, self.rb)
    
    def make_concrete(name):
        return Concrete(name, float(name[1:]))
    
    concreteB25 = make_concrete('B25')
    concreteB30 = make_concrete('B30')
    
    print(concreteB25, concreteB30)
    print(concreteB25.alphabt, Concrete.alphabt)
    

    output

    Concrete(B25, 25.0) Concrete(B30, 30.0)
    0.0001 0.0001
    

    Note that we can access the .alphabt attribute from a Concrete instance or from the Concrete class itself.

    BTW, the format string 'Concrete({0}, {1})' can be simplified to 'Concrete({}, {})' in Python 2.7 and later.

    You could use the make_concrete helper function to create some pre-defined concrete instances in your materials module, or you could just use it in your onActivated method to create them "on the fly".