difference between connections in qt - qt

I have some constructor for the class LCDRange:
LCDRange::LCDRange(QWidget *parent)
: QWidget(parent)
{
QLCDNumber *lcd = new QLCDNumber(2);
lcd->setSegmentStyle(QLCDNumber::Filled);
slider = new QSlider(Qt::Horizontal);
slider->setRange(0, 99);
slider->setValue(0);
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(lcd);
layout->addWidget(slider);
setLayout(layout);
}
but I can't understand the difference between these lines:
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
thanks in advance

Remember that we are in OO land, so we are operating on objects.
In order to connect a signal to something, those signal/slots have to be apart of an object.
Another way to think about it is you can't have a signal by itself, because a signal has to come from somewhere. Likewise, you can't have a slot all by itself it has to be attached to something.
Now, Qt allows you to connect a signal to a slot, but it also allows you to connect a signal to a signal, which is what is happening in the second connect line. This allows you to chain signals from one object to another, or you could think about it as passing a signal through.
Usually this happens when an Object or Widget has a private internal child that emits a signal, and the parent Object/Widget wants to emit the same signal to whoever is listening to it.
In the case of your example the LCDRange Widget contains a slider, which is an internal implementation detail. The user of LCDRange doesn't need to know about all the different components that make up the LCDRange (slider, lcdnumber, layout, etc), that's a basic requirement of encapsulation which is a huge advantage of OO.
However, the user of LCDRange will want to know when the value of LCDRange changes. And rather then creating a slot in LCDRange, that simply re-emits the signal valueChanged signal, you can forward or passthrough the valueChanged signal from the slider.
The following achieves the same effect of passing the signal through, however it requires much more code.
class LCDRange : public QWidget
{
// constructor and other methods
//...
signals:
void valueChanged(int)
private slots:
void sliderValueChanged(int);
// ...
};
// in the LCDRange constructor
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(sliderValueChanged(int)));
// elsewhere in LCDRange's definition
void LCDRange::sliderValueChanged( int value )
{
emit valueChanged( value );
}

connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
tells, if the value of the slider gets changed then valueChanged signal will be emited and it will be reflected in LCD view. i.e display slots gets called, whose implementation will be present in QLCDNumber
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
Qt offers, mechanism of connecting one signal to another signal, it implies if slider valueChangedsignal is emited means present class valueChangedsignal is emited.
the connected slot for valueChanged gets called

Related

How to know which QLineEdit is focused?

I'm new in QT. Could someone help me with this?
I'm coding a widget application (with QMainWindow) with three QLineEdits widgets, I used setText to set a random text and connect the timeout() signal to a slot. When the timer "interrupts" I want to know in which QLineEdit the cursor is.
MainWindow constructor:
ui->setupUi(this);
timer = new QTimer(this);
timer -> start(1000); // 1 sec
connect(timer, SIGNAL(timeout()), this, SLOT(FinishTimer()));
ui->lineEdit1->setText("Line1");
ui->lineEdit2->setText("Line2");
ui->lineEdit1->setFocus();
In finish timer function I want to move the cursor but first I need to know in wich QLineEdit I am and the position of the cursor.
FinishTimer slot:
QString debug;
debug = this->focusWidget()->objectName(); //this is a debug line, it works fine
// this line doesn't work
int position = this->focusWidget()->cursorPosition();
cursorPosition it's a method of QLineEdit, the error is "class QWidget has no member named 'cursorPosition'". I hope you will understand me.
I used qobject_cast and it works really well. Thanks
position=qobject_cast<QLineEdit*>(this->focusWidget())->cursorPosition();

QTimer timeout signal not being emitted

I have a subclass of QObject called Updater that I want to use to manage some widgets in my app. I want it to run updateDisp() every 16 ms, so I created a QTimer in the constructor and connected the timeout signal to the updateDisp() slot. However, updateDisp() never runs, and I can't for the life of me figure out why.
in updater.h:
class Updater : public QObject {
Q_OBJECT
ToUpdate* toUpdate;
QTimer* timer;
...
public slots:
void updateDisp();
};
in updater.cpp:
Updater::Updater(ToUpdate* t, QObject *parent)
: QObject(parent) {
toUpdate = t;
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateDisp()));
timer->setInterval(16);
timer->start();}
I instantiate an Updater object in MainWindow.cpp. Also, I have the GUI thread separate from main() (using winapi CreateThread()); I've seen some other posts about problems with QTimers and QThreads but obviously this is a bit different.
There's some similar issues.
I'd a similar problem in the past: https://github.com/codelol/QtTimer/commit/cef130b7ad27c9ab18e03c15710ace942381c82a#commitcomment-10696869
Basically it seems that Qt5 timer doesn't work as expected while in background, it's sync with the animation timer... which doesn't run often while in background.
This guy solved a similar issue setting the timer type to Qt::PreciseTimer
https://github.com/codelol/QtTimer/commit/cef130b7ad27c9ab18e03c15710ace942381c82a#commitcomment-10696869
timer->setTimerType(Qt::PreciseTimer);
The description of the timer types: http://doc.qt.io/qt-5/qt.html#TimerType-enum
Qt::PreciseTimer 0 Precise timers try to keep millisecond accuracy
Not sure if they're the exactly same problem, but you can give a try on that.

displaying QSlider value in QLabel/QDebug() using QThread

I am implementing a simple function where slider value is constantly displayed on label and qDebug(). I already got the label updated using signal/slots, but somehow the qDebug() thread is not working properly. I expected to see the console flooded with the value of the slider.
Below is my code:
SliderThread.h:
class HorizontalSliderThread : public QThread {
Q_OBJECT
public:
HorizontalSliderThread(Ui::MainWindow *ui);//in order to call slider value in HorizontalSliderThread class
~HorizontalSliderThread();
public slots:
void process();
private:
};
SliderThread.cpp
HorizontalSliderThread::HorizontalSliderThread(Ui::MainWindow *ui){
ui_global = *ui;
}
void HorizontalSliderThread::process(){
qDebug("Test Thread");
int value = ui_global.horizontalSlider_windowSize->value();
QObject::connect(ui_global.horizontalSlider_windowSize,SIGNAL(valueChanged(int)),ui_global.label_SliderWindowSize,SLOT(setNum(int)));//update value to label
qDebug()<<value; //update value in console
}
mainwindow.h
move Ui::MainWindow *ui; from private to public.
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QThread* thread = new QThread;
HorizontalSliderThread* slider = new HorizontalSliderThread(ui);
slider->moveToThread(thread);
connect(thread, SIGNAL(started()), slider, SLOT(process()));
thread->start();
}
Current Output: qDebug() displays the value of slider once, label is updated constantly.
Expected Output: qDebug() displays the value of slider continuously, label is updated constantly.
Since label is updated when the slider is moved, then the signal/slot for this function is working, which means my thread should be working. Don't know what I'm doing wrong.
QThread implementation is reference from: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
I am fairly new to this, especially QThread, so if there is a better way to implement this function, please let me know!
Thanks a lot.
EDIT1: add slider->moveToThread(thread);
Well you've only connected the started() signal to your process() function, so your thread starts and it calls process, which dutifully shows your debug output and returns.
I suspect you want to call your process function every time the value changes, which would require another signal/slot connection (along these lines):
connect(ui_global.horizontalSlider_windowSize, SIGNAL(valueChanged(int)), thread, SLOT(setNum(int)));
Also, it looks like you intend for your HorizontalSliderThread to actually run in that separate thread you've created, in which case you'll need a call to QObject::moveToThread() in there, something along these lines:
slider->moveTothread(thread);

Passing signals through hierarchies

I am having some difficulty fully grasping how signals and slots are used in Qt. I am sure it is really basic but I'm just no getting it today.
I have a set of widgets a bit like this:
MainWindow
-->StackedWidget
-->ChildForms
Now the idea is that there are some actions on the Child widgets that will cause the stacked widget to display a different page.
So if I understand it properly I thought the way to connect signals and slots is to use the connect() at the scope that knows about the objects but what I have managed to get working doesn't do it this way. At the moment in my child form I use parentWidget() to access the slot of the StackedWidget but I am not very happy with really because it is giving the child information about the parent which it shouldn't have:
void TaskSelectionForm::setButtonMappings()
{
// Set up a mapping between the buttons and the pages
QSignalMapper *mapper = new QSignalMapper(this);
connect(mapper, SIGNAL(mapped(int)), parentWidget(), SLOT(setCurrentIndex(int)));
mapper->setMapping(ui->utilitiesButton, 2); // Value of the index
connect(ui->utilitiesButton, SIGNAL(clicked()), mapper, SLOT(map()));
}
But I am not really sure how I should do this and connect it up. Do I need to have signals at each level and emit through the tree?
A Bit of Signal-Slot Theory
The signal-slot connections are oblivious to parent-child relationships between QObjects, and any such relationship doesn't matter. You're free to connect objects to their children, to their siblings, to their parents, or even to QObjects that are in a separate hierarchy, or to lone QObjects that have neither parents nor children. It doesn't matter.
A signal-slot connection connects a signal on a particular instance of QObject to slot on another instance of QObject. To use the connect method, you need the pointers to the instance of sender QObject and the instance of receiver QObject. You then use the static QObject::connect(sender, SIGNAL(...), receiver, SLOT(...)). Those connections have nothing to do with any hierarchy there is between the sender and receiver.
You can also connect a signal to a signal, to forward it -- for example from a private UI element to a signal that's part of the API of the class. You cannot connect a slot to a slot, because it'd incur a bit of runtime overhead for a rarely-used case. The overhead would be an extra bool member in QObjectPrivate, plus a failed if (bool) test. If you want to forward slots to slots, there are at least two ways to do it:
Emit a signal in the source slot and connect that signal to the destination slot.
Obtain a list of all signals connected to the source slot, iterate on it and connect them to to the target slot. There's no easy way to maintain such connections when further signals are connected or disconnected from the source slot. Unfortunately, QObject only has a connectNotify(const char*) protected function, but not a signal -- so you can't hook up to it unless you would modify src/corelib/kernel/qobject[.cpp,_p.h,.h] to emit such a signal. If you truly need it, just modify the Qt source, you have access it for a reason, after all. Hacking the vtable without modifying Qt is possible, but discouraged for obvious reasons.
The Answer
Below is a self contained example that shows how to do what you want. Turns out I have answers to quite a few questions from my various experiments I've done in Qt in the past. I'm a packrat when it comes to test code. It's all SSCCE to boot :)
// https://github.com/KubaO/stackoverflown/tree/master/questions/signal-slot-hierarchy-10783656
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Window : public QWidget
{
QSignalMapper m_mapper;
QStackedLayout m_stack{this};
QWidget m_page1, m_page2;
QHBoxLayout m_layout1{&m_page1}, m_layout2{&m_page2};
QLabel m_label1{"Page 1"}, m_label2{"Page 2"};
QPushButton m_button1{"Show Page 2"}, m_button2{"Show Page 1"};
public:
Window(QWidget * parent = {}) : QWidget(parent) {
// the mapper tells the stack which page to switch to
connect(&m_mapper, SIGNAL(mapped(int)), &m_stack, SLOT(setCurrentIndex(int)));
// Page 1
m_layout1.addWidget(&m_label1);
m_layout1.addWidget(&m_button1);
// tell the mapper to map signals coming from this button to integer 1 (index of page 2)
m_mapper.setMapping(&m_button1, 1);
// when the button is clicked, the mapper will do its mapping and emit the mapped() signal
connect(&m_button1, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page1);
// Page 2
m_layout2.addWidget(&m_label2);
m_layout2.addWidget(&m_button2);
// tell the mapper to map signals coming from this button to integer 0 (index of page 1)
m_mapper.setMapping(&m_button2, 0);
connect(&m_button2, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
Connect(stackedwidget->currentactivewidget,SIGNAL(OnAction()),this,SLOT(PrivateSlot()));
PrivateSlot() is a slot declared privately. So in this function, you can add your code to change the page of stackedwidget corresponding to the action produced by currentactivewidget.
Again if you really want to pass the signal up the heirarchy, emit a publicsignal() at the end of private slot function.
Connect(this,SIGNAL(publicsignal()),Parentwidgetofstackedwidget(here mainwindow),SLOT(mainwindow_slot()));

Qt force QCheckBox to emit signal on setChecked

If I called QCheckBox::setChecked( x ) the toggled signal is only emitted if x is not the same as the current checkbox state. I understand the logic behind this, to avoid signaling if nothing has changed. However, in some situations where I have a more complicated widgets setup, I need the signal to always be emitted. This ensures anybody who has connected to the checkbox will receive the first state.
Is there a way to have QCheckBox::setChecked(bool) emit a signal regardless of whether the state has changed?
My simple workaround now is to just force the checkbox into multiple states by doing setChecked(!x) and setChecked(x). I was hoping for a more correct way of doing this.
Looking into the QAbstractButton implementation, I found the following lines of code:
if (!d->checkable || d->checked == checked) {
if (!d->blockRefresh)
checkStateSet();
return;
}
where checkStateSet is a virtual function. QCheckBox overrides this and emits a stateChanged() signal only if the state changed.
I haven't tested this, but I think d->blockRefresh is set to false if you call QCheckBox::setChecked( ... ) directly.
If this is the case, it means you could subclass QCheckBox and override the checkStateSet() method to something like this:
void MyCheckBox::checkStateSet()
{
QCheckBox::checkStateSet();
if( m_oldState == checkState() )
{
// emit the signal here, as QCheckBox::checkStateSet() didn't do it.
emit stateChanged( m_oldState );
}
else
{
// don't emit the signal as it has been emitted already,
// but save the old state
m_oldState = checkState();
}
}
where the header file contains
private:
Qt::CheckState m_oldState;
which must be initialised to Qt::Unchecked in the constructor.
Here is another solution which may or may not be possible for your case:
If you can be 100% sure that your signals and slots are connected before the checkbox has a chance to change its state, every connected class can initialize itself safely assuming the checkbox is not checked. This is because checkboxes are always unchecked upon construction.
This way you might not have to call setChecked() after connecting the signals.
However, This approach does not work if there is a chance a signal gets connected after the checkbox has already changed. I'm not 100% fond of this approach myself but it might be an option for you nevertheless.
One way would be to subclass QCheckBox and implement the emitting of signals in that where you need it, for example :
class MyCheckBox : public QCheckBox
{
Q_OBJECT
public:
MyCheckBox(QWidget *parent = 0) : QCheckBox(parent) {};
virtual void setChecked(bool checked) {
QCheckBox::setChecked(checked); emit checkWasSet(checked);
};
signals:
void checkWasSet(bool value);
};
Now use this class instead of the regular QCheckBox class, and you can connect to the checkWasSet() signal for whenever the check state is set.
You could emit the signal with the current state yourself:
checkbox.stateChanged.emit(checkbox.checkState())

Resources