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. Trouble subclassing QSlider
QtWS25 Last Chance

Trouble subclassing QSlider

Scheduled Pinned Locked Moved General and Desktop
14 Posts 3 Posters 7.5k Views
  • 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.
  • D Offline
    D Offline
    dnadave
    wrote on last edited by
    #1

    I'm trying to subclass QSlider so that it takes a double argument instead of an int for setValue and valueChanged slots/signals. Here's my subclass code:

    @
    class QDSlider : public QSlider
    {
    Q_OBJECT
    public:
    explicit QDSlider():QSlider() {}
    explicit QDSlider( QWidget *parent = 0 ):QSlider( parent ) {}
    explicit QDSlider( Qt::Orientation orientation , QWidget *parent = 0 ):QSlider( orientation , parent ) {}
    signals:
    void valueDChanged( double value )
    {
    int ivalue = value;
    emit setValue( ivalue );
    }
    private slots:
    void setDValue( double value )
    {
    int ivalue = value;
    emit setValue( ivalue );
    }
    };
    @

    And here is the error I get when I try to load the compiled library:

    @
    Error in dyn.load(file, DLLpath = DLLpath, ...) :
    unable to load shared object '/usr/local/lib64/R/library/gsDesignExplorer/libs/libgsdesigngui.so':
    /usr/local/lib64/R/library/gsDesignExplorer/libs/libgsdesigngui.so: undefined symbol: _ZTV8QDSlider
    ERROR: loading failed
    @

    Using c++filt, I can see that this refers to the vtable:

    @
    GSDesignGUI/package> c++filt _ZTV8QDSlider
    vtable for QDSlider
    @

    Do I need to redefine all of the virtual functions in QSlider to get this to work? Or, do I just need to redefine one? Are there other, better solutions to what I'm trying to accomplish? I've been working on this for the past 5 days without any luck, nor has Google been helpful in finding a solution.

    Thanks!!

    Dave H

    [EDIT: code formatting, please use @-tags, Volker]

    1 Reply Last reply
    0
    • G Offline
      G Offline
      goetz
      wrote on last edited by
      #2

      Your class is unlikely to compile. You must not implement a signal! Just declare it in the header file. The actual implementation is done by moc (a Qt tool that parses headers) and if you provide your own, the method is implemented twice.

      It's very likely that due to the compiler error, your lib is not recreated and thus lacks the symbols for your slider subclass.

      http://www.catb.org/~esr/faqs/smart-questions.html

      1 Reply Last reply
      0
      • D Offline
        D Offline
        dnadave
        wrote on last edited by
        #3

        Well, it does compile:

        @
        make[3]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' [ 20%] Building CXX object CMakeFiles/gsdesigngui.dir/gsdesign.cpp.o [ 30%] Building CXX object CMakeFiles/gsdesigngui.dir/gsDesignGUI.cpp.o [ 40%] Building CXX object CMakeFiles/gsdesigngui.dir/gsDesignTips.cpp.o [ 50%] Building CXX object CMakeFiles/gsdesigngui.dir/GsRList.cpp.o [ 60%] Building CXX object CMakeFiles/gsdesigngui.dir/main.cpp.o [ 70%] Building CXX object CMakeFiles/gsdesigngui.dir/qrc_images.cpp.o [ 80%] Building CXX object CMakeFiles/gsdesigngui.dir/moc_gsdesign.cpp.o [ 90%] Building CXX object CMakeFiles/gsdesigngui.dir/Rcpp.cpp.o [100%] Building CXX object CMakeFiles/gsdesigngui.dir/moc_Rcpp.cxx.o Linking CXX shared library libgsdesigngui.so make[3]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
        [100%] Built target gsdesigngui
        make[2]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' make[2]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
        make[3]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' Linking CXX shared library CMakeFiles/CMakeRelink.dir/libgsdesigngui.so make[3]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
        make[2]: Leaving directory `/home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
        Install the project...
        -- Install configuration: ""
        -- Installing: /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/inst/libs/./libgsdesigngui.so
        @

        If there was a compiler error, that would have been very helpful. But, there isn't.

        Now, how does this signal creation magic happen? Do I say in my best Picard voice: "Computer. Make a double precision signal for QSlider." and the computer does it? I find it very hard to believe that I can just do:

        @
        class foo:public QSlider
        {
        Q_OBJECT
        signal:
        setValue( double );
        }
        @

        and things will magically work perfectly.

        So, to be helpful, how does one do this as you clearly seem to indicate I'm doing it wrong.

        Dave H

        [EDIT: code formatting, Volker]

        1 Reply Last reply
        0
        • G Offline
          G Offline
          goetz
          wrote on last edited by
          #4

          A short not for the beginning: please put your code snippets and log outputs between two @-signs (one before the first line, one after the last) or use the code button of the editor, this makes the code and logs formatted nicely.

          To your question: Yes Captain, you're right! :)
          You can (and must!) just put that signal declaration into the header. The rest is subject to Qt. For the gory details: You put Q_OBJECT into your header, you add the header file to the list of files that are to be moc'ed. In .pro files all files in the HEADERS variable are scanned. In CMake it might be that you have to add it to some special variable, I'm not sure on this, as I'm not using CMake actively - please check. Then for all classes containing Q_OBJECT in their header, that tool called moc (for Meta Object Compiler) generates the magic stuff, including the implemenation of the signal's method body.

          Ah, your missing compiler error could be based on CMake not catching up that the header file is subject to moc, thus not calling moc on it and no automated implementation code is coming into the way of the linker.

          http://www.catb.org/~esr/faqs/smart-questions.html

          1 Reply Last reply
          0
          • D Offline
            D Offline
            dnadave
            wrote on last edited by
            #5

            Well, just tried doing that and I still get the unresolved symbol error with vtable.

            Here's the new version of the class:

            @
            class QDSlider : public QSlider
            {
            Q_OBJECT
            public:
            explicit QDSlider():QSlider() {}
            explicit QDSlider( QWidget *parent = 0 ):QSlider( parent ) {}
            explicit QDSlider( Qt::Orientation orientation , QWidget *parent = 0 ):QSlider( orientation , parent ) {}
            signals:
            void valueChanged( double );
            private slots:
            void setValue( double );
            };
            @

            I added the file to the list of MOC_SRCS in CMake and let it do its thing. Still no go...

            This is getting pretty frustrating...

            Dave H

            1 Reply Last reply
            0
            • D Offline
              D Offline
              dnadave
              wrote on last edited by
              #6

              I was using the wrong macro in CMakelist.txt, so moc was no running. I now have that running and creating the .cxx files which do get compiled and linked. However, I am still getting an unresolved symbol error, but for the exact function moc was supposed to magically generate the definition for:

              @
              make[3]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' [ 7%] Generating ui_gsdesign.h [ 15%] Generating moc_gsdesign.cxx [ 23%] Generating moc_QDSlider.cxx [ 30%] Generating qrc_images.cxx Scanning dependencies of target gsdesigngui make[3]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
              make[3]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' [ 38%] Building CXX object CMakeFiles/gsdesigngui.dir/gsdesign.cpp.o [ 46%] Building CXX object CMakeFiles/gsdesigngui.dir/gsDesignGUI.cpp.o [ 53%] Building CXX object CMakeFiles/gsdesigngui.dir/gsDesignTips.cpp.o [ 61%] Building CXX object CMakeFiles/gsdesigngui.dir/GsRList.cpp.o [ 69%] Building CXX object CMakeFiles/gsdesigngui.dir/main.cpp.o [ 76%] Building CXX object CMakeFiles/gsdesigngui.dir/Rcpp.cpp.o [ 84%] Building CXX object CMakeFiles/gsdesigngui.dir/moc_gsdesign.cxx.o [ 92%] Building CXX object CMakeFiles/gsdesigngui.dir/moc_QDSlider.cxx.o [100%] Building CXX object CMakeFiles/gsdesigngui.dir/qrc_images.cxx.o Linking CXX shared library libgsdesigngui.so make[3]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
              [100%] Built target gsdesigngui
              make[2]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' make[2]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
              make[3]: Entering directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' Linking CXX shared library CMakeFiles/CMakeRelink.dir/libgsdesigngui.so make[3]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
              make[2]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build' Install the project... -- Install configuration: "" -- Installing: /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/inst/libs/./libgsdesigngui.so make[1]: Leaving directory /home/david/workspace/GSDesignGUI/package/gsDesignExplorer/explorergui-build'
              ** testing if installed package can be loaded
              Error in dyn.load(file, DLLpath = DLLpath, ...) :
              unable to load shared object '/usr/local/lib64/R/library/gsDesignExplorer/libs/libgsdesigngui.so':
              /usr/local/lib64/R/library/gsDesignExplorer/libs/libgsdesigngui.so: undefined symbol: _ZN8QDSlider8setValueEd
              ERROR: loading failed

              • removing ‘/usr/local/lib64/R/library/gsDesignExplorer’
              • restoring previous ‘/usr/local/lib64/R/library/gsDesignExplorer’
                @

              Here is the unmangled symbol:

              @
              GSDesignGUI/package> c++filt _ZN8QDSlider8setValueEd
              QDSlider::setValue(double)
              @

              So, how do I get this slot and signal created?? I was told not to generate this myself, but let moc do it for me. Clearly, moc is not doing that, so how do you get it to work?!?

              Here's a copy of the class as defined in the header file moc is processing:

              @
              class QDSlider : public QSlider
              {
              Q_OBJECT
              public:
              explicit QDSlider():QSlider() {}
              explicit QDSlider( QWidget *parent = 0 ):QSlider( parent ) {}
              explicit QDSlider( Qt::Orientation orientation , QWidget *parent = 0 ):QSlider( orientation , parent ) {}
              signals:
              void valueChanged( double );
              private slots:
              void setValue( double );
              };
              @

              1 Reply Last reply
              0
              • A Offline
                A Offline
                andre
                wrote on last edited by
                #7

                If you invoke moc manually on your header file, does it generate the needed code? If so (and I see no reason why it should not), you have a problem with your build system. I am not experienced with cmake, so I can't help you with that, but i will guarantee you that Volker is right and you must let moc generate the signals implementation for you.

                1 Reply Last reply
                0
                • D Offline
                  D Offline
                  dnadave
                  wrote on last edited by
                  #8

                  moc does generate the needed code when called by hand.

                  1 Reply Last reply
                  0
                  • A Offline
                    A Offline
                    andre
                    wrote on last edited by
                    #9

                    Then your problem is with your project definition in cmake, or with cmake itself somehow. Perhaps you can get better assistance in a cmake specific channel.

                    1 Reply Last reply
                    0
                    • D Offline
                      D Offline
                      dnadave
                      wrote on last edited by
                      #10

                      I'm not quite convinced it's cmake yet. I just did the following:

                      @

                      moc QDSlider.h > moc_QSlider.cpp
                      @

                      and then added moc_QSlider.cpp to the list of source files for compilation thinking that maybe the moc file was compiled, but not linked.

                      I then get the following error:

                      @
                      Linking CXX shared library libgsdesigngui.so
                      CMakeFiles/gsdesigngui.dir/moc_QDSlider.cxx.o: In function QDSlider::metaObject() const': moc_QDSlider.cxx:(.text+0x0): multiple definition of QDSlider::metaObject() const'
                      CMakeFiles/gsdesigngui.dir/moc_QSlider.cpp.o:moc_QSlider.cpp:(.text+0x0): first defined here
                      CMakeFiles/gsdesigngui.dir/moc_QDSlider.cxx.o:(.data.rel.ro+0x0): multiple definition of QDSlider::staticMetaObject' CMakeFiles/gsdesigngui.dir/moc_QSlider.cpp.o:(.data.rel.ro+0x0): first defined here CMakeFiles/gsdesigngui.dir/moc_QDSlider.cxx.o: In function QDSlider::qt_metacast(char const*)':
                      moc_QDSlider.cxx:(.text+0x20): multiple definition of QDSlider::qt_metacast(char const*)' CMakeFiles/gsdesigngui.dir/moc_QSlider.cpp.o:moc_QSlider.cpp:(.text+0x20): first defined here CMakeFiles/gsdesigngui.dir/moc_QDSlider.cxx.o: In function QDSlider::valueChanged(double)':
                      moc_QDSlider.cxx:(.text+0x70): multiple definition of QDSlider::valueChanged(double)' CMakeFiles/gsdesigngui.dir/moc_QSlider.cpp.o:moc_QSlider.cpp:(.text+0x70): first defined here CMakeFiles/gsdesigngui.dir/moc_QDSlider.cxx.o: In function QDSlider::qt_metacall(QMetaObject::Call, int, void**)':
                      moc_QDSlider.cxx:(.text+0xb0): multiple definition of `QDSlider::qt_metacall(QMetaObject::Call, int, void**)'
                      CMakeFiles/gsdesigngui.dir/moc_QSlider.cpp.o:moc_QSlider.cpp:(.text+0xb0): first defined here
                      collect2: ld returned 1 exit status
                      @

                      The file moc_QSlider.cpp contained:

                      @
                      GSDesignGUI/package> cat gsDesignExplorer/src/explorergui/moc_QSlider.cpp
                      /****************************************************************************
                      ** Meta object code from reading C++ file 'QDSlider.h'
                      **
                      ** Created:
                      ** by: The Qt Meta Object Compiler version 62 (Qt 4.7.1)
                      **
                      ** WARNING! All changes made in this file will be lost!
                      *****************************************************************************/

                      #include "../explorergui/QDSlider.h"
                      #if !defined(Q_MOC_OUTPUT_REVISION)
                      #error "The header file 'QDSlider.h' doesn't include <QObject>."
                      #elif Q_MOC_OUTPUT_REVISION != 62
                      #error "This file was generated using the moc from 4.7.1. It"
                      #error "cannot be used with the include files from this version of Qt."
                      #error "(The moc has changed too much.)"
                      #endif

                      QT_BEGIN_MOC_NAMESPACE
                      static const uint qt_meta_data_QDSlider[] = {

                      // content:
                      5, // revision
                      0, // classname
                      0, 0, // classinfo
                      2, 14, // methods
                      0, 0, // properties
                      0, 0, // enums/sets
                      0, 0, // constructors
                      0, // flags
                      1, // signalCount

                      // signals: signature, parameters, type, tag, flags
                      10, 9, 9, 9, 0x05,

                      // slots: signature, parameters, type, tag, flags
                      31, 9, 9, 9, 0x08,

                         0        // eod
                      

                      };

                      static const char qt_meta_stringdata_QDSlider[] = {
                      "QDSlider\0\0valueChanged(double)\0"
                      "setValue(double)\0"
                      };

                      const QMetaObject QDSlider::staticMetaObject = {
                      { &QSlider::staticMetaObject, qt_meta_stringdata_QDSlider,
                      qt_meta_data_QDSlider, 0 }
                      };

                      #ifdef Q_NO_DATA_RELOCATION
                      const QMetaObject &QDSlider::getStaticMetaObject() { return staticMetaObject; }
                      #endif //Q_NO_DATA_RELOCATION

                      const QMetaObject *QDSlider::metaObject() const
                      {
                      return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
                      }

                      void QDSlider::qt_metacast(const char _clname)
                      {
                      if (!_clname) return 0;
                      if (!strcmp(_clname, qt_meta_stringdata_QDSlider))
                      return static_cast<void
                      >(const_cast< QDSlider
                      >(this));
                      return QSlider::qt_metacast(_clname);
                      }

                      int QDSlider::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
                      {
                      _id = QSlider::qt_metacall(_c, _id, _a);
                      if (_id < 0)
                      return _id;
                      if (_c == QMetaObject::InvokeMetaMethod) {
                      switch (_id) {
                      case 0: valueChanged((reinterpret_cast< double()>(_a[1]))); break;
                      case 1: setValue((reinterpret_cast< double()>(_a[1]))); break;
                      default: ;
                      }
                      _id -= 2;
                      }
                      return _id;
                      }

                      // SIGNAL 0
                      void QDSlider::valueChanged(double _t1)
                      {
                      void _a[] = { 0, const_cast<void>(reinterpret_cast<const void*>(&_t1)) };
                      QMetaObject::activate(this, &staticMetaObject, 0, _a);
                      }
                      QT_END_MOC_NAMESPACE
                      @

                      I'll keep looking at my CMakelist.txt file, but I'm not yet convinced that this is where the problem is.

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        andre
                        wrote on last edited by
                        #11

                        So... try it out (with the same sources) with qmake. If that works ok, then the problem is cmake.

                        1 Reply Last reply
                        0
                        • G Offline
                          G Offline
                          goetz
                          wrote on last edited by
                          #12

                          setDouble() is a slot, you must implement this manually.

                          It's only the signals that must not be implemented manually, but are implemented by moc autogenerated code.

                          http://www.catb.org/~esr/faqs/smart-questions.html

                          1 Reply Last reply
                          0
                          • D Offline
                            D Offline
                            dnadave
                            wrote on last edited by
                            #13

                            Ah! OK, so I implemented my QDSlider slot as follows and connected it to the QDSpinBox as follows, as well.

                            qdslider.h
                            @
                            #define QDSLIDER_H

                            #include <QSlider>

                            class QDSlider : public QSlider
                            {
                            Q_OBJECT
                            public:
                            explicit QDSlider();
                            explicit QDSlider( QWidget * );
                            explicit QDSlider( Qt::Orientation , QWidget * );
                            signals:
                            void valueChanged( double );
                            private slots:
                            void setValue( double );
                            };

                            #endif
                            @

                            qdslider.cpp
                            @
                            #include "qdslider.h"

                            QDSlider::QDSlider():QSlider() {}
                            QDSlider::QDSlider( QWidget *parent = 0 ):QSlider( parent ) {}
                            QDSlider::QDSlider( Qt::Orientation orientation , QWidget *parent = 0 ):QSlider( orientation , parent ) {}

                            void QDSlider::setValue( double value )
                            {
                            int ivalue = value;
                            emit QSlider::setValue( ivalue );
                            }
                            @

                            connect code in main program:
                            @
                            QObject::connect( ui->anlErrorDSpin , SIGNAL( valueChanged( double ) ) ,
                            ui->anlErrorHSlider , SLOT( setValue( double ) ) );
                            QObject::connect( ui->anlErrorHSlider , SIGNAL( valueChanged( double ) ) ,
                            ui->anlErrorDSpin , SLOT( setValue( double ) ) );
                            @

                            This compiles, links, and loads. The problem is that when I run the program, I get the following error:

                            @
                            Object::connect: No such slot QSlider::setValue( double )
                            Object::connect: (sender name: 'anlErrorDSpin')
                            Object::connect: (receiver name: 'anlErrorHSlider')
                            Object::connect: No such signal QSlider::valueChanged( double )
                            Object::connect: (sender name: 'anlErrorHSlider')
                            Object::connect: (receiver name: 'anlErrorDSpin')
                            @

                            Why is the compiled code looking for QSlider::setValue( double ) when anlErrorHSlider is defined as a QDSlider which does have a setValue( double ) defined? I tried doing the following:

                            @
                            QObject::connect( ui->anlErrorDSpin , SIGNAL( valueChanged( double ) ) ,
                            ui->anlErrorHSlider , SLOT( QDSlider::setValue( double ) ) );
                            @

                            which resulted in the following error at run time:

                            @
                            Object::connect: No such slot QSlider::QDSlider::setValue( double )
                            Object::connect: (sender name: 'anlErrorDSpin')
                            Object::connect: (receiver name: 'anlErrorHSlider')
                            @

                            What do I have to do to get the right setValue called?!?

                            1 Reply Last reply
                            0
                            • D Offline
                              D Offline
                              dnadave
                              wrote on last edited by
                              #14

                              Figured out why the wrong setValue was being used. the ui_xxx.h file was not being updated due to the way I was building the project. Once I deleted the offending ui_xxx.h file and pointed the include directory to the right location of the correct ui_xxx.h file, things worked better.

                              Now to set the signals such that updating the slider changes the spinbox and the reverse...

                              1 Reply Last reply
                              0

                              • Login

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