how to send value in SIGNAL - qt

I am passing a QVBoxLayout as an argument to a method and creating controls at runtime.
QDoubleSpinBox *test; // Global variable at the top of the cpp file
void Sph::CreateUI(QVBoxLayout* layout)
{
QDoubleSpinBox *PositionXSpinBox = new QDoubleSpinBox;
test = PositionXSpinBox;
PositionXSpinBox->setRange(-10000, 10000);
PositionXSpinBox->setSingleStep(1.0);
PositionXSpinBox->setValue(40);
layout->addWidget(PositionXSpinBox);
bool ok = QObject::connect(PositionXSpinBox, SIGNAL(valueChanged(double)),
this, SLOT( ParamChange()));
}
In my current scenario I am declaring global varibles at the top of the .cpp file, for example in this case QDoubleSpinBox *test;
and in the ParamChanged function I am changing a private variable of the class .
void Sph::ParamChange()
{
this->fSegments = test->value();
this->isChanged = true;
}
1) is it possible to send the value of PositionXSpinBox in the connect signal itself.

I am not entirely sure if you asking this simple thing, but yes, slot can receive the parameter of the signal. Signal parameters wouldn't make much sense otherwise, now would they?
Something like this
void Sph::ParamChange(double value)
{
this->fSegments = value;
this->isChanged = true;
}
and this
bool ok = QObject::connect(PositionXSpinBox, SIGNAL(valueChanged(double)),
this, SLOT( ParamChange(double)));
The more modern way to do this connect would be to use the new syntax:
QObject::connect(PositionXSpinBox, &QSpinBox::valueChanged,
this, &Sph::ParamChange);
This is preferable because it will give compile time error if you for example make a typo in method names.
As a side note, if this indeed was your problem, I highly recommend going through the Qt basics, for example this: https://doc.qt.io/qt-5/signalsandslots.html

Related

Connecting a function with a slot in Qt5

As in Qt5, there's a new signal-slot syntax and I tried utilizing it.
Firstly, I created a void return type function:
void update()
{
cerr << "complete";
}
And connected it to &QRadioButton::pressed
QRadioButton *button = new QRadioButton;
QObject::connect(button, &QRadioButton::pressed, update);
Things went fine. Afterward, I tried inserting a parameter:
void update(bool trigger)
{
if (!trigger) {return;}
cerr << "complete";
}
And tried connecting:
QRadioButton *button = new QRadioButton;
QObject::connect(button, &QRadioButton::toggled(bool), update);
But it returned error: called to non-static member function without an object argument.
I tried this as well:
QObject::connect(button, &QRadioButton::toggled(bool), update(bool));
with the same result.
So, how can I patch this? Or, more favorable, how can I implement my function as a slot and get Qt to do the job the old fashion way with SIGNAL() and SLOT()?
Sidenote: I fully understood and also tested the first case (with void return type), but I want to know if I ever have to deal with the second case (which will be a lot, actually), what would be a good option.
You don't have to set the signature since Qt will use the signature of the slot so your initial code should work:
QObject::connect(button, &QRadioButton::pressed, update);

qt share variables between slots

Im having trouble figuring out how to use variables across slots. I have read the signals and slots page a few times over and haven't been able to figure out exactly how to use the connect function. I'm trying to have one button to select the directory, and then have it sent over to the other slot for when I hit print, so it can use that directory. Thanks for the help.
void MainWindow::on_pushButton_clicked()
{
QApplication app(int argc, char** argv());
int n = 107;
for (int q = 1; q <= n; q++)
{
QString fileName =(folderName + "/batch_%1.jpg").arg(q);
// QPrinter printer;
//QPrintDialog *dlg = new QPrintDialog(&printer,0);
//if(dlg->exec() == QDialog::Accepted) {
QPrinter printer(QPrinter::HighResolution);
printer.setResolution(300);
printer.setCopyCount(1);
printer.setDoubleSidedPrinting(false);
printer.setDuplex(QPrinter::DuplexNone);
printer.setColorMode(QPrinter::Color);
printer.setPageSize(QPrinter::Letter);
printer.setPaperSize(QPrinter::Letter);
printer.setPaperSource(QPrinter::Auto);
printer.setOrientation(QPrinter::Portrait);
printer.setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Inch);
QString outputFileName = QStringLiteral("/Users/alexdotzler/Desktop/testing/test%1.pdf").arg(q);
printer.setOutputFileName(outputFileName);
printer.setOutputFormat(QPrinter::PdfFormat);
QImage img(fileName);
QPainter painter(&printer);
painter.drawImage(QPoint(0,0),img);
painter.end();
}
//delete dlg;
}
void MainWindow::on_pushButton_2_clicked()
{
QString folderName = QFileDialog::getExistingDirectory(0, ("Select file"), QDir::currentPath());
}
At first, remember about Minimal reproducible example. This is not only about example, but also about minimal. In this case, your printing code is not nessessary.
Following your question, slot is just a function of class. And in your case, you can jist create printing function, that will be called from both pushButton 1 and 2.
Also, don't be await of real magic from sig/slots. It looks like, but not. Connect slot to signal is just virtual call to function B when function A called.
Then let's go a bit deeply into the world of signals and slots.
You can connect (slots or signals) to signals . No other way.
Basically, signals and slots used to pass data between different objects or to inform them about something.
// foo.h
class First {
...
signals:
void newData(QVariant val);
};
// bar.h
class Another {...
public slots:
void getNewData(QVariant val);
};
// main.cpp
Another another1;
First first1;
QObject::connect(first1, &First::newData, another1, &Another::getNewData);
You can also create something can be called "Connections tree", when signal [Another::sig1] connected to [Third::sig2], which connected to signal [Fourth::sig3] and slot [Fifth::slot1], and so on. I'm not sure someone really need it, but be free to play with.
AFAIK, the only reason to use signal/slot connection inside single class, is when you need to pass some data to GUI thread from another thread running in GUI. Please, don't do that in real projects.
Make folderName a member of your MainWindow class so it will be accessible by your pushButton clicked slots. Then you can read/write it as necessary from those slots.

How to fire a signal with QMetaObject::activate

I found an interesting article on how to impement QObject with dynamic properties (see C++ class DynamicObject). The code from the article works fine, the properties of DynamicObject are get and set successfully from both C++ and QML, but the only thing I cannot figure out is how to fire dynamic signals.
I tried to fire "nameChanged()" signal with the following code:
bool DynamicObject::emitDynamicSignal(char *signal, void **arguments)
{
QByteArray theSignal = QMetaObject::normalizedSignature(signal);
int signalId = metaObject()->indexOfSignal(theSignal);
if (signalId >= 0)
{
QMetaObject::activate(this, metaObject(), signalId, arguments);
return true;
}
return false;
}
myDynamicObject->emitDynamicSignal("nameChanged()", nullptr);
the index of the signal is found and signalId is assigned to 5, but the signal is not fired. But if I do, for example,
myDynamicObject->setProperty("name", "Botanik");
the property is changed and the signal is fired successfully.
What is wrong in my code? What should I pass as 'arguments' parameter of QMetaObject::activate ?
EDIT1:
The full source code is temporarily available here.
A signal is also a method. You can invoke it from the meta object.
So, replace your line QMetaObject::activate(...) by:
metaObject()->method(signalId).invoke(this);
And let Qt handles the call to activate().
There is also an issue in DynamicObject::qt_metacall(): you are handling only QMetaObject::ReadProperty and QMetaObject::WriteProperty calls.
You have to add QMetaObject::InvokeMetaMethod if you want to emit your signal.

Remove first bytes from QByteArray

I want to write a function in which QByteArray is input to the function.
I want to remove some header from receive data and store it into global QByteArray.
void abc::CopyData(const QByteArray &data)
{
switch(RequestPacketCount)
{
case REQUEST_FIRST_PACKET:
{
ByteArrayData = data;
}
break;
case REQUEST_SECOND_PACKET:
case REQUEST_THIRD_PACKET:
ByteArrayData.append(data);
}
}
I want to remove 'n' no. of byte from start of 'data' and store remaining data into 'ByteArrayData'
Thanks in advance.
What you seem to want is simply copy the original array and use remove;
ByteArrayData = data;
ByteArrayData.remove(0, n); // Removes first n bytes of ByteArrayData,
// leaving data unchanged
Since a QByteArray is implicitly shared, the construction of the copy takes constant time, and the modification (deletion) is what will make the actual copy when needed.
To append efficiently, you can just use data to get to the byte array, and append the part you want. That will prevent un-necessary temporary objects. That would look something like;
ByteArrayData.append(data.data() + n, data.size() - n);
You can use QByteArray::mid:
ByteArrayData = data.mid(n);
//...
ByteArrayData.append(data.mid(n));
Adding to Joachim's answer, in C++ it's rather unfortunate that some implementation details leak into the interface, but it's still preferred for performance reasons to let the compiler do the copying by passing the argument as value. So, paraphrasing, the best solution would be:
void abc::CopyData(QByteArray data)
{
...
data.remove(0, n);
...
ByteArrayData.append(data);
}
The only place where you definitely do not want to have such arguments passed by value is a signal declaration - signals never modify their data. It's fine for a slot to do so, though:
class MyClass : public QObject {
Q_OBJECT
...
public:
// pass by const reference in signals
Q_SIGNAL void dataSource(const QByteArray &); // The only correct signal form
// pass by const reference or value in slots, depending on use
Q_SLOT void dataSink1(const QByteArray &); // Valid
Q_SLOT void dataSink2(QByteArray); // Valid as well.
};
Connecting to either slot uses the same code whether it's Qt4 or Qt5 connection style. Thus you don't have to worry about such interface changes due to leaked implementation details breaking your code.
// Qt4 - you should elide const and reference anyway
connect(src, SIGNAL(dataSource(QByteArray)), dst, SLOT(dataSink1(QByteArray));
connect(src, SIGNAL(dataSource(QByteArray)), dst, SLOT(dataSink2(QByteArray));
// Qt5
connect(src, &MyClass::dataSource, dst, &MyClass::dataSink1);
connect(src, &MyClass::dataSource, dst, &MyClass::dataSink2);

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