3

This code:

MyAxis *ax;
ax = static_cast<MyAxis*>(ui->customPlot->axisRect()->addAxis(QCPAxis::atLeft));
connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)),
        ax, SLOT(MyAxis::rescale(QCPRange)));

gives me this run-time error:

QObject::connect: No such slot QCPAxis::MyAxis::rescale(QCPRange) in plotwindow.cpp:267

Usually when I get errors like this, I add Q_OBJECT macro to class and run qmake to fix it, but that didn't work this time.

Here is the declaration of the class:

class MyAxis : public QCPAxis
{
    Q_OBJECT
public:
    void setRefAxis(QCPAxis *refAxis);
    void setScale(double newScale);


public Q_SLOTS:
    virtual void rescale(const QCPRange &range);

private:
    double scale;
    QCPAxis *ref;
};

Changing the declaration to public slots: didn't make any difference.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Krzysztof Bieda
  • 187
  • 1
  • 2
  • 10
  • Hint: use Qt Creator autocomplete to fill out the SIGNAL and SLOT macros. If it refuses, there's a problem somewhere. If it does autocompletion, you avoid potential typo bugs. – hyde Jun 22 '16 at 19:14

4 Answers4

1

I think you have a problem here in what you are trying to do:

ui->customPlot->axisRect()->addAxis(QCPAxis::atLeft)

returns a QCPAxis and not a MyAxis class. Lets say QCPAxiz takes 100 bytes of memory and MyAxis takes 110 bytes then you are trying to do this:

A_110_Byte_Type* p110Bytes = static_cast<110-bytes *> (<100-bytes>); // not real code!

I don't see how that can work. The function you are calling returns a QCPAxis and you can't just convert it into a MyAxis just because they share the same base class... its a bit like have a having a Ford-Fiesta and saying, "now it is a Ferrari" just because they have the same base type of "car".

So at the moment I think you are into un-defined behavior...

What is it that you are trying to do? - you can copy the values of the QCPAxis into your MyAxis (with a copy constructor - I think you need one of those to do this)

code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • No, that's not the problem (and it's part of the reason the connect-by-name is still useful even in Qt5). `connect()` will use the run-time metaobject to lookup the slots of `ax`. The real problem is that the `SLOT` macro requires an *unqualified* method name, i.e. `SLOT(rescale(QCPRange))` instead of `SLOT(MyAxis::rescale(QCPRange))`. – Toby Speight Jun 22 '16 at 08:38
  • 1
    No, I'm wrong; that *is* the problem! Simply casting (with `static_cast<>()`, ugh!) doesn't make one object into another. If Krzysztof had used `qobject_cast<>()`, his mistake would have been more obvious. I'm guessing the mis-written `SLOT()` macro was part of a trial-and-error 'fix' to the problem... – Toby Speight Jun 22 '16 at 08:44
  • @TobySpeight... I have to give you +1 for arguing with yourself :)) , yes I agree I think the first question was a "red herring" – code_fodder Jun 22 '16 at 08:46
1

You can't just cast the existing axis to a MyAxis*. You need to instantiate a new MyAxis and assign that to the graph:

QCPGraph *graph = new QCPGraph(this);
MyAxis *ax = new MyAxis(graph);
graph->setValueAxis(ax);
connect(...);

Tip for future: avoid static_cast<>() where there's a checking alternative (here, qobject_cast<>(), otherwise dynamic_cast<>()). That will help identify invalid assumptions.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
1

Qt stores some meta information about classes that inherit from QObject. One of these information is the slots of the class. By static casting an object these meta information doesn't update in cast, so your casted object's meta information doesn't contain the slot you implemented in your MyAxis class. that's why it can't connect the signal to the casted object at runtime. Even if you reimplement a virtual slot in your MyAxis class, by static casting your object new casted object's slot points to the old slot and doesn't upgrade to point to the reimplemented one.

UPDATE: By using qobject_cast (which is the safe cast way for Qt objects) you can see that it the casted object is NULL.

Sassan
  • 2,187
  • 2
  • 24
  • 43
  • 1
    Replacing `static_cast` with `qobject_cast` is a good idea, but it won't make the code work. It will make the problem diagnosable, by giving a null pointer, so it's definitely advisable, but the problem is that the referent is not a `MyAxis` - he needs to sort that out. – Toby Speight Jun 22 '16 at 09:28
-1
  1. The moc-generator of Qt is very restrictive: so write with the same signature:

    connect(..., SLOT(...(const QCPRange &)));
    
  2. In one of the h-files a statement is missing:

        Q_DECLARE_METATYPE(QCPRange)
    
Roland
  • 336
  • 2
  • 8
  • 2
    When using the Qt 4 connect syntax, prefer normalized slot signatures. Thus `connect(..., SLOT(...(QCPRange)));`. The `const` and `&` are redundant: the signature normalizer called from `connect` will remove them anyway. – Kuba hasn't forgotten Monica Jun 22 '16 at 14:40