Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to convert to MVC Design?
Forum Updated to NodeBB v4.3 + New Features

How to convert to MVC Design?

Scheduled Pinned Locked Moved Solved General and Desktop
mvcc++design
5 Posts 2 Posters 555 Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    Curtwagner1984
    wrote on 6 Jun 2022, 14:02 last edited by
    #1

    Greetings,

    I have quite a few indicators like this: alt text

    They are currently not implement using the MVC Qt classes, the state for the indicator is saved directly in the indicator class.
    I'd like to convert this into a MVC design where I'll use a ListView for the view where each row houses an indicator.

    On the model side, I'll subclass QAbstractListModel which will have a QList of data structs corresponding to the data the indicator should use.

    Where I'm having a problem is, like you see in the picture, some rows have only one indicator while others have three. I'm not sure exactly what's the best way to design a data struct to house them.

    I thought about making a base class for the data structure that has a label and subclassing it into a class that has a single led value and another class that has multiple.

    This is a somewhat messy class diagram I came up with while prototyping.

    alt text

    I also have similar structure indicators where the data is a numerical value instead of an LED so this is why it's also in a diagram.

    (The diagram contains some errors as I was playing around with Mermaid.)

    I feel like this is extremely convoluted and there must be a better way I'm not clearly seeing.

    I'll be very happy to hear some advice on how to simplify the design. Maybe my approach is in a completely wrong direction.

    Thank you for the help.

    M 1 Reply Last reply 6 Jun 2022, 14:43
    0
    • C Curtwagner1984
      6 Jun 2022, 14:02

      Greetings,

      I have quite a few indicators like this: alt text

      They are currently not implement using the MVC Qt classes, the state for the indicator is saved directly in the indicator class.
      I'd like to convert this into a MVC design where I'll use a ListView for the view where each row houses an indicator.

      On the model side, I'll subclass QAbstractListModel which will have a QList of data structs corresponding to the data the indicator should use.

      Where I'm having a problem is, like you see in the picture, some rows have only one indicator while others have three. I'm not sure exactly what's the best way to design a data struct to house them.

      I thought about making a base class for the data structure that has a label and subclassing it into a class that has a single led value and another class that has multiple.

      This is a somewhat messy class diagram I came up with while prototyping.

      alt text

      I also have similar structure indicators where the data is a numerical value instead of an LED so this is why it's also in a diagram.

      (The diagram contains some errors as I was playing around with Mermaid.)

      I feel like this is extremely convoluted and there must be a better way I'm not clearly seeing.

      I'll be very happy to hear some advice on how to simplify the design. Maybe my approach is in a completely wrong direction.

      Thank you for the help.

      M Offline
      M Offline
      mpergand
      wrote on 6 Jun 2022, 14:43 last edited by mpergand 6 Jun 2022, 14:48
      #2

      @Curtwagner1984 said in How to convert to MVC Design?:

      I thought about making a base class for the data structure that has a label and subclassing it into a class that has a single led value and another class that has multiple.

      Classic way to do it.
      The other way is to define a generic class, something like:

      class Indicator
      {
        IndicatorType type;  // enum of the different types
        QVariantList values;  // various  data values specific to the type
      // or QMap(QString, QVariant) if you want to find values by name
      }
      

      I'm using this kind of design often.

      1 Reply Last reply
      0
      • C Offline
        C Offline
        Curtwagner1984
        wrote on 7 Jun 2022, 06:29 last edited by
        #3

        @mpergand said in How to convert to MVC Design?:

        The other way is to define a generic class, something like:

        I thought about it. But I do want to seperate the API. For example, single LED indicator need to have a setLedState(LED_STATE_ENUM ledState) method. Where the input for this method will be a state of this single LED. On the other hand, the indicator with 3 axis might have the same method but with other arguments setLEDState(AXIS_ENUM axis, LED_STATE_ENUM state).

        With a single class design, I'll have to put both functions in there:

        class Indicator
        {
            IndicatorType type;  // enum of the different types
            QVariantList values;  // various  data values specific to the type
            // or QMap(QString, QVariant) if you want to find values by name
        
            void SetLedState(LED_STATE_ENUM ledState);
            void SetLedState(AXIS_ENUM axis, LED_STATE_ENUM ledState);
        
        }
        

        Which will clutter the class.

        What do you think about this:

        enum AXIS_ENUM { X, Y, Z, NO_AXIS };
        enum LED_STATE { LED_OFF,LED_ON_GREEN,LED_ON_RED };
        enum INDICATOR_TYPE {LED_INDICATOR_SINGLE, LED_INDICATOR_AXIS, NUMERICAL_INDICATOR_SINGLE, NUMERICAL_INDICATOR_AXIS}
        
        Q_ENUM(AXIS_ENUM)
        Q_ENUM(LED_STATE)
        
        /*
        Base Indicator class that houses all the data common to all types of indicators
        in a QVariant Map. And a Indicator type enum
        */
        class IndicatorBase{    
        
            INDICATOR_TYPE GetIndicatorType(){
                return this._indicatorType;
            }
        
            protected:
                QMap<AXIS_ENUM,QVariant> _indicatorStateMap;
                INDICATOR_TYPE _indicatorType;
        }
        
        /*
        LED indicator base. The Led indicators have a boolean variable that determines 
        if the indicator is critical or not. It's common to all LED indicators.
        */
        class LedIndicatorBase: IndicatorBase{
        
            public:
                bool GetCriticalStatus(){
                    return this._bIsCritical;
                }
        
        
            protected:
                bool _bIsCritical = false;
        }
        
        /*
        Class for a single LED indicator that houses **only the API** for 
        a single indicator. While the data is stored in the base class.
        */
        class LedSingleIndicator: LedIndicatorBase{
            public:
                LedSingleIndicator(bool bIsCritical, LED_STATE indicatorInitialLedState){
                    this._bIsCritical = bIsCritical;
                    this._indicatorType = INDICATOR_TYPE::LED_INDICATOR_SINGLE
                    this._indicatorStateMap[AXIS_ENUM::NO_AXIS] = QVariant::fromValue(indicatorInitialLedState);            
                }
        
                void SetIndicatorState(LED_STATE stateToSet){
                    this._indicatorStateMap[AXIS_ENUM::NO_AXIS] = QVariant::fromValue(stateToSet);
                }
        
                QVariant GetIndicatorState(){
                    return this._indicatorStateMap[AXIS_ENUM::NO_AXIS];
                }
        }
        
        
        /*
        Same as above but for axis LED indicator
        */
        class LedAxisIndicator: LedIndicatorBase{
            public:
                LedAxisIndicator(bool bIsCritical, LED_STATE initialLEDsState){
                    this._bIsCritical = bIsCritical;
                    this._indicatorType = INDICATOR_TYPE::LED_INDICATOR_AXIS;
                    this._indicatorStateMap[AXIS_ENUM::X] = QVariant::fromValue(initialLEDsState);
                    this._indicatorStateMap[AXIS_ENUM::Y] = QVariant::fromValue(initialLEDsState);
                    this._indicatorStateMap[AXIS_ENUM::Z] = QVariant::fromValue(initialLEDsState);
                }
        
                void SetIndicatorState(AXIS_ENUM axis, LED_STATE stateToSet){
                    this._indicatorStateMap[axis] = QVariant::fromValue(stateToSet);
                }
        
                QVariant GetIndicatorState(AXIS_ENUM axis){
                    return this._indicatorStateMap[axis];
                }
        }
        
        /*
        Numerical indicator have common data in the form of an int that 
        determines the decimal percision of the number.
        */
        class NumericalIndicatorBase: IndicatorBase{
        
            public:
                int GetDecimalPercision(){
                    return this._decimalPercision;
                };
        
            protected:
                int _decimalPercision = 4;
        }
        
        //Very simular to the LED indicator
        class NumericalSingleIndicator: NumericalIndicatorBase{
            public:
                NumericalSingleIndicator(int decimalPercision, double initialValue){
                    this._decimalPercision = decimalPercision;
                    this._indicatorType = INDICATOR_TYPE::NUMERICAL_INDICATOR_SINGLE;
                    this._indicatorStateMap[AXIS_ENUM::NO_AXIS] = QVariant::fromValue(initialValue);
                }
        
                void SetIndicatorState(double valueToSet){
                    this._indicatorStateMap[AXIS_ENUM::NO_AXIS] = QVariant::fromValue(valueToSet);
                }
        
                QVariant GetIndicatorState(){
                    return this._indicatorStateMap[AXIS_ENUM::NO_AXIS];
                }
        }
        //Very simular to the LED indicator
        class NumericalAxisIndicator: NumericalIndicatorBase{
            public:
                NumericalAxisIndicator(int decimalPercision, double initialValue){
                    this._decimalPercision = decimalPercision;
                    this._indicatorType = INDICATOR_TYPE::NUMERICAL_INDICATOR_AXIS;
                    this._indicatorStateMap[AXIS_ENUM::X] = QVariant::fromValue(initialValue);
                    this._indicatorStateMap[AXIS_ENUM::Y] = QVariant::fromValue(initialValue);
                    this._indicatorStateMap[AXIS_ENUM::Z] = QVariant::fromValue(initialValue);
                }
        
                void SetIndicatorState(AXIS_ENUM axis,double valueToSet){
                    this._indicatorStateMap[axis] = QVariant::fromValue(valueToSet);
                }
        
                QVariant GetIndicatorState(AXIS_ENUM axis){
                    return this._indicatorStateMap[AXIS_ENUM::NO_AXIS];
                }
        }
        
        
        /*
        In Subclass of QAbstractListModel. 
        It will have a QList<IndicatorBase*> as data.
        */
        
        enum Roles{
            isCriticalRole = Qt::UserRole,
            singleStatusRole = Qt::UserRole + 1,
            xAxisStatusRole = Qt::UserRole + 2,
            yAxisStatusRole = Qt::UserRole + 3,
            zAxisStatusRole = Qt::UserRole + 4,
            decimalPercisonRole = Qt::UserRole + 5,
        }
        
        QVariant MyListModel::data(const QModelIndex &index, int role) const{
             if ( !index.isValid() ){
                 return QVariant();
             }
                
        
            IndicatorBase *indicator = static_cast<IndicatorBase*>( index.internalPointer());
            //get the indicator type from the base class. 
            INDICATOR_TYPE indicatorType = indicator->GetIndicatorType();
            switch(indicatorType){
                case INDICATOR_TYPE::LED_INDICATOR_SINGLE{
                    LedSingleIndicator* currentIndicator = dynamic_cast<LedSingleIndicator*>(indicator);
                    if (role == Roles::isCriticalRole){
                        return QVariant::fromValue(currentIndicator->GetCriticalStatus());
                    }else if (role == Roles::singleStatusRole){
                        return currentIndicator->GetIndicatorState();
                    }
                    break;
                }
                case INDICATOR_TYPE::LED_INDICATOR_AXIS{
                    LedAxisIndicator* currentIndicator = dynamic_cast<LedAxisIndicator*>(indicator);
                    if (role == Roles::isCriticalRole){
                        return QVariant::fromValue(currentIndicator->GetCriticalStatus());
                    }else if (role == Roles::xAxisStatusRole){
                        return currentIndicator->GetIndicatorState(AXIS_ENUM::X);
                    }else if (role == Roles::yAxisStatusRole){
                        return currentIndicator->GetIndicatorState(AXIS_ENUM::Y);
                    }else if (role == Roles::zAxisStatusRole){
                        return currentIndicator->GetIndicatorState(AXIS_ENUM::Z);
                    }            
                    break;
                }
                case INDICATOR_TYPE::NUMERICAL_INDICATOR_SINGLE{
                    NumericalSingleIndicator* currentIndicator = dynamic_cast<NumericalSingleIndicator*>(indicator);
                    if (role == Roles::singleStatusRole){
                        return QVariant::fromValue(currentIndicator->GetCriticalStatus());
                    }else if (role == Roles::decimalPercisonRole){
                        return QVariant::fromValue(currentIndicator->GetDecimalPercision());
                    }
                    break;
                }
                case INDICATOR_TYPE::NUMERICAL_INDICATOR_AXIS{
                    NumericalSingleIndicator* currentIndicator = dynamic_cast<NumericalSingleIndicator*>(indicator);
                    if (role == Roles::xAxisStatusRole){
                        return currentIndicator->GetIndicatorState(AXIS_ENUM::X);
                    }else if (role == Roles::yAxisStatusRole){
                        return currentIndicator->GetIndicatorState(AXIS_ENUM::Y);
                    }else if (role == Roles::zAxisStatusRole){
                        return currentIndicator->GetIndicatorState(AXIS_ENUM::Z);
                    }else if (role == Roles::decimalPercisonRole){
                        return QVariant::fromValue(currentIndicator->GetDecimalPercision());
                    }   
                    break;
                }
                
            }
        
                
        }
        
        1 Reply Last reply
        0
        • M Offline
          M Offline
          mpergand
          wrote on 7 Jun 2022, 10:12 last edited by
          #4

          After a quick look at your code, seems ok to me.

          1 Reply Last reply
          1
          • C Offline
            C Offline
            Curtwagner1984
            wrote on 7 Jun 2022, 11:01 last edited by
            #5

            Thank you, I hope I'm not overcomplicating this. I just can't seem to see a better solution.

            1 Reply Last reply
            0

            1/5

            6 Jun 2022, 14:02

            • Login

            • Login or register to search.
            1 out of 5
            • First post
              1/5
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved