12

I am relatively new to programming with Qt and had a question. Short version:

How do I inherit signals defined in superclasses?

I am trying to subclass someone else's nicely made QTWidgets to change some of the default behavior:


//Plot3D is a QWidget that defines a signal "rotationChanged"
class matLinePlot : public QObject, public Plot3D {

    Q_OBJECT;
        //etc...
public:
       //etc...

        //Catch Plot3D's signal "rotationChanged" and do some magic with it:
    void initPlot(){
              QObject::connect(this, SIGNAL(rotationChanged( double , double , double )),
            this, SLOT(myRotationChanged(double, double, double)));
    }
};

The problem is in the QObject::connect line. What I would like to do is connect the rotationChanged SIGNAL (from qwt3D_plot.h) to a local function/SLOT - "myRotationChanged". However whenever I do this, at run time I get:

Object::connect: No such signal matLinePlot::rotationChanged(double, double, double)

in C:...\matrixVisualization.h. Of course, I know that rotationChanged isn't in matrixVisualization.h - it's in qwt_plot3D.h, but I thought that since I inherit from Plot3D everything should be fine. But, now that I think about it, since SIGNAL and SLOT are macros, I assume MOC doesn't know/care about inheritance.

Which leads me to my question - since MOC and SIGNALS / SLOTS don't seem to know about inheritance etc: how can I subclass a widget defined somewhere else and get access to the widget's signals?

I have a lot of examples of how to use encapsulation to accomplish something like this, but I'm afraid I don't understand how to do this with inheritance.

Sorry if this is a ridiculous question - I feel like I'm missing something obvious.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pete
  • 2,336
  • 2
  • 16
  • 23
  • 1
    the reference you see in the error to "matrixVisualization.h" shows in what file the failed QObject::connect is, not where it's trying to "look" for the matching signal. – Idan K May 10 '09 at 14:04

4 Answers4

10

I guess the problem is the multiple inheritance:

class matLinePlot : public QObject, public Plot3D
...

I assume that Plot3D is a subclass of QObject? In this case, you should do

class matLinePlot : public Plot3D
...

instead.

ashcatch
  • 2,327
  • 1
  • 18
  • 29
  • 1
    That makes things into a link error: 1>moc_matrixVisualization.obj : error LNK2001: unresolved external symbol "public: static struct QMetaObject const Qwt3D::Plot3D::staticMetaObject" (?staticMetaObject@Plot3D@Qwt3D@@2UQMetaObject@@B) The QT doc suggests using multiple inheritance: http://doc.trolltech.com/4.3/uitools-multipleinheritance.html Although they extend QWIdget, I need QObject. – Pete May 10 '09 at 15:20
  • 2
    The link you posted is showing an example on how to use .ui files (those files created by Qt Designer). One important difference is that Ui::CalculatorForm is not a subclass of QObject. The rule when subclassing from QObject (and using multiple inheritance) is that only one of the superclasses can be a QObject and that the QObject has to be the first part in the inheritance. – ashcatch May 10 '09 at 18:08
  • 1
    the doc suggests multiple inheritance in a different scenario. when using Qt Designer you'll get a .ui file, then a tool called uic will take that .ui file and generate a class that's basically a translation of the .ui file, only in actual C++. so what they're basically suggesting is to inherit from that class, instead of having it as a member. – Idan K May 10 '09 at 18:10
  • Under http://doc.trolltech.com/4.3/moc.html you can find the info about multiple inheritance. And when it comes to the compiler error, this is probably caused by a missing moc step of your header file for Plot3D. – ashcatch May 10 '09 at 18:11
  • ashcatch, this was correct. Thanks, I did not understand the difference between the UI inheritance and the regular inheritance. Once I linked with the moc_*.cpp and also only inherited from Plot3D this worked. – Pete May 10 '09 at 18:22
  • @ashcatch just updating the link (broken since Trolltech is not Qt's owner anymore): https://doc.qt.io/archives/qt-4.8/moc.html – cbuchart Jun 12 '18 at 06:46
2

SIGNAL(x) and SLOT(x) are macros that generate string literals. At runtime, slots and signals are matched up using string compares of those generated literals.

(I would have added a comment to mdec's comment, but I don't have enough rep)

sean e
  • 11,792
  • 3
  • 44
  • 56
  • Right - I think that's the heart of this problem; because the string matching MACRO/MOC combo is looking in only the current header file for the signal, it doesn't know to look in my other library of compiled code. – Pete May 10 '09 at 05:25
  • Pete, I'm pretty sure you're wrong. The signals and slots are kept somewhere (moc generates the code for this, you can see it in the *_moc file), it has nothing to do with the current header file. – Idan K May 10 '09 at 14:02
  • (curses! - I don't have enough rep to add to Pete's last comment about the link error) It looks like you are not linking in moc_qwt3D_plot.cpp. – sean e May 10 '09 at 16:10
  • Thanks daniel and sean. I am linking to the qwtPlot library, and have included the .h, .cpp, and moc_*.cpp files that define the signals in my project, but still no luck. I think because the connect function is looking for matPlotLine::rotationChanged, but the actual signal has signature:
    // SIGNAL 0
    void Qwt3D::Plot3D::rotationChanged(double _t1, double _t2, double _t3)
    
    in the moc_*.cpp file
    – Pete May 10 '09 at 17:59
  • Qwt3D is a namespace? Is your matLinePlot in the same namespace or do you have a using directive somewhere? – sean e May 10 '09 at 18:25
  • Yeah, I had the namespaces settled, the issue was a) the multiple inheritance and b) a linking issue - see above. thanks. – Pete May 10 '09 at 21:08
1

I believe that will work if the Plot3D::rotationChanged signal is public or protected. Are you sure the signal is not private?

Edit:

Although I could not find a specific reference, I'll have to conclude that signals are always public. At least a test I did here seemed to indicate that I could connect to a signal even if it was declared in the private section of a class.

I also verified that a signal declared in QObject could be connected using a subclass of QObject in the connect statement so signals are definitely inheritable. As I see in other answers and comments here, the issue must be elsewhere.

Arnold Spence
  • 21,942
  • 7
  • 74
  • 67
  • Hi, I tried putting a public keyword before the signal keyword, but Qt MOC did not like that: 1>MOC include\qwt3d_plot.h 1>include\qwt3d_plot.h(143): Error: Signals cannot have access specifier 1>Project : error PRJ0019: A tool returned an error code from "MOC include\qwt3d_plot.h" – Pete May 10 '09 at 05:03
  • Oops. Obviously I should have used "public: signals:", but that hasn't helped. – Pete May 10 '09 at 05:14
0

Incorrect -> see comments.

I'm using Qtopia at Uni and I believe I recall someone saying something about spacing in the SIGNAL and SLOT parameters for connect.

Try using

QObject::connect(this, SIGNAL(rotationChanged(double,double,double)),
            this, SLOT(myRotationChanged(double,double,double)));

I know it doesn't seem intuitive, as C++ isn't sensitive to whitespace, however I believe it has something to do with some of the magic that Qtopia/QT uses when connecting signals and slots. This may only apply to Qtopia, or I may have heard wrong, but give it a try. Additionally are the signals public or protected and have you included the appropriate header files?

mdec
  • 5,122
  • 4
  • 25
  • 26
  • I now have: public: signals: //! Emitted, if the rotation is changed void rotationChanged(double xAngle,double yAngle,double zAngle); In the header and the plotting library, and QObject::connect(this,SIGNAL(rotationChanged(double,double,double)), this,SLOT(myRotationChanged(double,double,double))); In my derived class... still same error. I have included the header: #include //has Plot3D class – Pete May 10 '09 at 05:19
  • When you declare the signals, do not declare a name for the parameter, only the types. That is public: signals: void rotationChanged(double, double, double); Hopefully that should fix your error. – mdec May 10 '09 at 05:44
  • Spacing does not effect signals & slots, what you heard is signal/slot normalization which just little-bit speeds up code but thats hardly noticable anyway. – ismail May 10 '09 at 11:33