views:

2756

answers:

4

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.

+1  A: 

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
Hi,I tried putting a public keyword before the signal keyword, but Qt MOC did not like that:1>MOC include\qwt3d_plot.h1>include\qwt3d_plot.h(143): Error: Signals cannot have access specifier1>Project : error PRJ0019: A tool returned an error code from "MOC include\qwt3d_plot.h"
Pete
Oops. Obviously I should have used "public: signals:", but that hasn't helped.
Pete
A: 

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
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, andQObject::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 <qwt3d_plot.h> //has Plot3D class
Pete
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
cartman
Thanks for the clarification =]
mdec
+2  A: 

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
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
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
(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
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:<pre>// SIGNAL 0void Qwt3D::Plot3D::rotationChanged(double _t1, double _t2, double _t3)</pre>in the moc_*.cpp file
Pete
Qwt3D is a namespace? Is your matLinePlot in the same namespace or do you have a using directive somewhere?
sean e
Yeah, I had the namespaces settled, the issue was a) the multiple inheritance and b) a linking issue - see above.thanks.
Pete
+6  A: 

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
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.htmlAlthough they extend QWIdget, I need QObject.
Pete
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
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
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
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