Solved Using Signals and Slots
-
I have created my own Slider class using QSlider widget.
I want the QLCDNumber Widget to be implemented inside main.cpp.
I have not created the connection between the two widgets yet.
Do I have to write the definition of valueChanged() as a signal?I am getting the following errors:
-
symbol(s) not found for architecture x86_64
-
linker command failed with exit code 1 (use -v to see invocation)
Please take a look at my code:
main.cpp:
#include <QSlider> #include <QLCDNumber> #include <QApplication> #include <QVBoxLayout> #include "slider.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Slider *slider = new Slider(Qt::Horizontal); slider->setRange(-100, 100); slider->setValue(20); QLCDNumber *lcd = new QLCDNumber; lcd->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QWidget *top = new QWidget; QVBoxLayout *layout = new QVBoxLayout(top); layout->addWidget(slider); layout->addWidget(lcd); top->show(); return app.exec(); }
slider.cpp:
#include "slider.h" Slider::Slider(Qt::Orientation orient, QWidget *parent) : QWidget(parent) { m_slider = new QSlider(orient); QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(m_slider); setLayout(layout); } void Slider::setRange(int min, int max) { m_slider->setRange(min, max); } void Slider::setValue(int newValue) { if (newValue != m_value) { m_slider->setValue(newValue); m_value = newValue; emit m_slider->valueChanged(newValue); } } void Slider::valueChanged(int newValue){ m_slider->valueChanged(newValue); }
slider.h:
#ifndef SLIDER_H #define SLIDER_H #include <QSlider> #include <QVBoxLayout> class QSlider; class Slider : public QWidget { Q_OBJECT public: Slider(Qt::Orientation orient = Qt::Horizontal, QWidget *parent = 0); void setRange(int min, int max); public slots: void setValue(int val); signals: void valueChanged(int newValue); private: QSlider *m_slider; int m_value; }; #endif // SLIDER_H
-
-
@JimmyMars said in Using Signals and Slots:
Do I have to write the definition of valueChanged() as a signal?
No, you only declare it in your class as signal, definition is done by moc compiler.
Remove this:void Slider::valueChanged(int newValue){ m_slider->valueChanged(newValue); }
Regarding your errors: what Qt version? Operating system? Do you use QtCreator? Please post the whole error messages.
-
To add to jsulm
you need code to emit the signal or you can connect it to another signal (e.g. of QSlider).
-
@jsulm
Qt 5.8.0 (Clang 7.0 (Apple))
macOS Sierra
QtCrreator 4.3.0That was the whole error message:
-
@JimmyMars Please go to "Compile Output" to get whole error messages.
But first change the code as I said. -
@jsulm
I have removed the definition of valueChanged now.Still getting this error:
0:50:34: Running steps for project lab-slider... 10:50:34: Configuration unchanged, skipping qmake step. 10:50:34: Starting: "/usr/bin/make" /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -stdlib=libc++ -headerpad_max_install_names -arch x86_64 -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -mmacosx-version-min=10.10 -Wl,-rpath,@executable_path/Frameworks -Wl,-rpath,/Users/gautam/Qt/5.9/clang_64/lib -o lab-slider.app/Contents/MacOS/lab-slider main.o slider.o -F/Users/gautam/Qt/5.9/clang_64/lib -framework QtWidgets -framework QtGui -framework QtCore -framework DiskArbitration -framework IOKit -framework OpenGL -framework AGL Undefined symbols for architecture x86_64: "vtable for Slider", referenced from: Slider::Slider(Qt::Orientation, QWidget*) in slider.o NOTE: a missing vtable usually means the first non-inline virtual member function has no definition. ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [lab-slider.app/Contents/MacOS/lab-slider] Error 1 10:50:34: The process "/usr/bin/make" exited with code 2. Error while building/deploying project lab-slider (kit: Desktop Qt 5.9.0 clang 64bit) When executing step "Make" 10:50:34: Elapsed time: 00:00.
-
@koahnig said in Using Signals and Slots:
To add to jsulm
you need code to emit the signal or you can connect it to another signal (e.g. of QSlider).
isn't
emit
a placeholder? Andemit mySignal();
acts the same asmySignal();
But it gets quickly confusing if you omit the
emit
! -
@J.Hilk He means that the signal needs to be emitted somewhere
-
@JimmyMars How did you add Slider class? Manually or using QtCreator wizard?
-
@jsulm
I did it manually. -
@JimmyMars Then either read and follow http://doc.qt.io/qt-5.9/moc.html or do it using QtCreator wizard.
QObject derived classes need special handling using moc meta compiler from Qt. This isusually done for you, but not if you add a class manually. -
@JimmyMars Actually it should work without any manual work if you use qmake.
Can you show your pro file? -
I think there needs to be:
QT += core gui widgetsI have it currently like this.
HEADERS= slider.h SOURCES= main.cpp slider.cpp OTHER_FILES += \ readme.txt QT += widgets
-
TEMPLATE = app QT += core gui widgets
-
@jsulm
That solved it.
Thanks for helping me out. -
To solve this problem, you need to follow the steps below.
-
In slider.cpp, change this expression emit m_slider->valueChanged(newValue) to emit valueChanged(newValue).
-
In slider.cpp, remove the implementation of valueChanged method. This means you need to remove the following part.
void Slider::valueChanged(int newValue){
m_slider->valueChanged(newValue);
}Build it and you will find everything goes well.
Why?
When you declare valueChanged in slider.h with signals Macro as well as QObject Macro. It means Qt's moc compiler will help you deal with the implementation of valueChanged. So you shouldn't implement it. Unlike other C++ code, when you declare some method in .h file, you need to implement it in .cpp file. Actually, Qt follows this, but it has already made it done.
-