Qt: Creating a QDoubleSlider - c++

I want to connect a QDoubleSpinBox with a QSlider like this:
QObject::connect(ui->myDoubleSpinBox, SIGNAL(valueChanged(double)),
ui->mySlider, SLOT(setValue(double)));
QObject::connect(ui->mySlider, SIGNAL(valueChanged(double)),
ui->myDoubleSpinBox, SLOT(setValue(double)));
This won't work, for a QSlider only handles int values. So I think i need to add a custom slot to QSlider.
I thought about creating a new class derived from QSlider and then implementing the slot, like this:
QDoubleSlider.hpp
#ifndef QDOUBLESLIDER_H
#define QDOUBLESLIDER_H
#include <QSlider>
class QDoubleSlider : public QSlider
{
Q_OBJECT
public:
explicit QDoubleSlider(QObject *parent = 0);
signals:
public slots:
void setValue(double givenValue);
};
#endif // QDOUBLESLIDER_H
QDoubleSlider.cpp
#include "qdoubleslider.h"
QDoubleSlider::QDoubleSlider(QObject *parent) :
QSlider(parent)
{
}
void QDoubleSlider::setValue(double givenValue)
{
// code
}
Now I have two problems:
The compiler complains about an invalid conversion from QObject* to QWidget* in the constructor.
I don't know how setValue works and thus I don't even know how to implement that slot.
Any ideas?

parent needs to be a QWidget*, just as the error states
Slots work like regular member functions. You should probably store an exact double as a member and set the underlying slider to the appropriate integer equivalent. Remember to only send valueChanged signals if the value really changes.
Furthermore you should probably inherit from QWidget instead and have a QSlider as a child, as you do not want users of your class to change the integer range of your internal slider.

just simply replace your QObject to QWidget, because QSlider constructor is
QSlider ( QWidget * parent = 0 )
you'd better have a new slot named setDoubleValue(double givenValue) and connect to this slot. in this slot, it is simple. like
void QDoubleSlider::setDoubleValue(double givenValue)
{
setValue(static_cast<int>(givenValue));
}

Related

Qt reimplement function

I need to subclass qt class and reimplement the virtual function.
Say that i have the QLCDNumber class and I want to reimplement the function that set the position of the number when resize the LCD number screen, how to achieve that?
I read that by inhert a class from QLCDNumber and reimplement the function,
but where to get that function code so that I can edit what needed in that function? I read the documentation but it explains the function uses and not show its code. Example image:
I mentioned the QLCDNumber class as example, I need to know the prosses of reimplemnt a virtual Qt class function.
For this particular problem you can use this type of approach where you can create an object which inherits QWidget and implement the paintEvent() of the class like this:
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
protected:
void paintEvent(QPaintEvent *pe);
signals:
public slots:
};
and in the paintEvent()
void MyWidget::paintEvent(QPaintEvent *pe)
{
QPainter *painter = new QPainter(this);
painter->begin(this);
// draw what you want here using painter
// and consider your different layouts
painter->end();
}

Passing a QString to a class method of parent with QSignalMapper

I have a parent class with its method to change a labels picture on certain Signals. E.g. When something happens in a QComboBox... (valueChanged, activated)
class parentClass : public QMainWindow
{
Q_OBJECT
...
public slots:
//this is the slot i want to connect to some signal of
//e.g a combo box to change the picture by passed in string
void changePicture(QString fileName);
Then i have this child:
class childClass : public QObject
{
Q_OBJECT
public:
childClass(parentClass *parent, QTabWidget *tab, QStringList *guards=0);
private:
bool readCombo(QXmlStreamReader *xmlreader);
Now inside of readCombo i want to read a string and pass it to change picture:
QString imageFileName = xmlreader->attributes().value("image").toString();
QSignalMapper * signalMapper = new QSignalMapper(parent);
//this is just one of many trials to get this working, i hope you get the picture
connect(combo , SIGNAL(activated(int)), parent, SLOT(changePicture(QString *)));
signalMapper->setMapping(combo, imageFileName);
But this gives me either No such Signal , No such Slot or in the upper case Incompatiple sender/receiver arguments
I would appreciate some help on this one since the syntax is really not being intuitive (imo) and i can't find any good reference that is working for my case (did trial and error a lot before asking)
Some issues with your code.
you really can't connect to a private slot of a QObject
You are creating a new signal mapper every time you call readCombo which you aren't clearing - resulting memleaks.
calling connect multiple times creates multiple connections i.e., you will call the same slot multiple times with single signal.
From your example code, I see that you can solve this either by making the parentClass slot public OR add a signal to the childClass and connect to it in the parentClass.
Other option is change the readCombo like this:
QString imageFileName = xmlreader->attributes().value("image").toString();
parentClass->changePicture(imageFileName);
and your parent class as
class parentClass : public QMainWindow
{
Q_OBJECT
...
public slots:
//this is the slot i want to connect to some signal of
//e.g a combo box to change the picture by passed in string
void changePicture(QString fileName);
I see several errors:
You are connecting to a private slot in parentClass from childClass, you should make it public if you want to connect it.
You connect a signal to a slot with another function signature. Your signal has parameter type int, and slot type QString*. The functions should share the same type of parameters.
In your connect you refer use the parameter type QString* in your slot, but in parentClass the parameter type is QString.
For more information about signals and slots see: Signals & Slots.
PS: your naming of childClass and parentClass is not clear either since they both inherit from QObject. See C++ inheritance.
OK, got it:
QString imageFileName = xmlreader->attributes().value("image").toString();
QSignalMapper * signalMapper = new QSignalMapper(parent);
signalMapper->setMapping(combo, imageFileName);
connect(signalMapper, SIGNAL(mapped(QString)), parent, SLOT(changePicture(QString)));
connect( combo, SIGNAL(activated(int)), signalMapper, SLOT(map()) );

Unable to connect even after deriving and adding macro

I made a class in a header file.
the class declaration:
class myTimer : public QObject
{
Q_OBJECT
~snipped~
I have a custom slot:
private slots:
void mySlot();
and a custom signal:
signals:
QString mySignal();
The slot simply emits mySignal which then returns a QString.
I connect a QPushButton with mySlot:
connect(ui->startButton, SIGNAL(clicked()),
timer, SLOT(mySlot()));
and mySignal to a LCD number:
connect(timer, SIGNAL(mySignal()),
ui->lcdNumber, SLOT(display(QString)));
Here timer is the object of the class I've declared. In both the connect statements I'm getting the error unable to convert parameter to const QObject* pointing to the object 'timer'.
I don't know why this error is occurring even though I have properly derieved from QObject adn added Q_OBJECT macro.
The connect function's first parameter is supposed to be a const QObject*. There's no way to convert a myTimer to a const QObject * because one of them is an object and the other is a pointer. You probably want &timer.
signals can't return any value (the return value should be void)
if you want to pas a value through a signal then you should add a parameter:
signals:
void mySignal(QString);
and then connect as:
connect(timer, SIGNAL(mySignal(QString)),
ui->lcdNumber, SLOT(display(QString)));

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.

Dynamic Creation in Qt of QSlider with associated QLCDNumber

I was wondering what's the best way to go about the following scenario?
I am dynamically creating QSliders that I wish to link to an associated QLCDNumber for display. The thing is I would like to have tenths available, so I would like to have a conversion between the QSLider and the QLCDNumber to divide by 10. At this point all I keep really is the QSlider, the QLCDNumbers I just create and forgot about. Is there an easy way of doing the conversion and connection without having to keep too much information?
Thanks in advance.
I'd try something along the following lines:
// create a new signal in your parent widget
signals:
void updateLCDNumber(double);
// and a slot which performs the conversion
private slots:
void performConversion(int value)
{
double convertedValue = value * 0.1;
emit(updateLCDNumber(convertedValue));
}
// then set the signals/slots up like this
connect(mySlider, SIGNAL(valueChanged(int)), this, SLOT(performConversion(int)));
connect(this, SIGNAL(updateLCDNumber(double)), myLCDNumber, SLOT(display(double)));
Afterwards you can completely "forget" about your LCD number, i.e. you don't need to keep a pointer or reference.
EDIT: A solution for several sliders:
class MySlider : public QSlider
{
Q_OBJECT
public:
MySlider(QWidget *parent=0) : QSlider(parent)
{
connect(this, SIGNAL(valueChanged(int)), this, SLOT(performConversion(int)));
}
signals:
void updateLCDNumber(double);
private slots:
void performConversion(int value)
{
double convertedValue = value * 0.1;
emit(updateLCDNumber(convertedValue));
}
};
Now create MySlider instances instead of QSlider ones and connect your QLCDNumbers:
connect(mySlider1, SIGNAL(updateLCDNumber(double)), myLCDNumber1, SLOT(display(double)));
connect(mySlider2, SIGNAL(updateLCDNumber(double)), myLCDNumber2, SLOT(display(double)));
...
This way you can also implement different conversion factors and the like, just modify the MySlider implementation.
I hope that helps.
This is basically what I ended up using; it seems to work (though it violates the whole object oriented philosophy).
signalMapper= new QSignalMapper(this);
QObject::connect(tmpSlider, SIGNAL(valueChanged(int)), signalMapper, SLOT(map()));
sliderMapper->setMapping(tmpSLider, tmpLCDNumber);
QObject::connect(signalMapper, SIGNAL(mapped(QWidget*)), this, SLOT(updateLCD(QWidget*)))
...
void MyClass::updateLCD(QWidget* lcdNum){
((QLCDNumber*)lcdNum)->display(((QSlider*)(signalMapper->mapping(lcdNum)))->value()*.1);
}