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);
Related
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
I receive data in JSON using a QJsonObject. I also have a QObject-based object holding properties, using Q_PROPERTY(...), for the keys in the JSON. Since Qt now has some more datatypes than JSON how can one check if they are convertible.
The datatypes used in the object typically are one of the following but not limited to
uint
double
QString
QDateTime
bool
The idea is to automatically call setProperty(...) on the QOject derived object for every key/value in the QJsonObject. Since this could fail due to malformed input in the JSON I have to check validity based on the QMetaProperty and QJsonObject/QVariantMap data.
Since this should run generic as a base class implementing manual checks for every datatype fails. I know there is QVariant::isConvertible<T>().
#include <QJsonObject>
#include <QVariant>
#include <QMetaObject>
#include <QMetaProperty>
class Test {
Q_GADGET
Q_PROPERTY(QString test)
QString m_test;
QJsonObject jo;
void call();
}
void Test::call()
{
jo.insert("test",QJsonValue(5));
// This will fail, since int is not convertible to QString implicitly
staticMetaObject->property(staticMetaObject->propertyOffset()).writeOnGadget(this,jo["test"].toVariant());
}
Since I am parsing the JSON before to check if every property would have a corresponding key in the JSON-Object I really like to catch these there already without changing my original object. Something like:
jo["test"].toVariant().canConvert<staticMetaObject->property(staticMetaObject->propertyOffset()).type()>()
Instead of using templated bool QVariant::canConvert<T>() one can use bool QVariant::canConvert(int targetTypeId).
QMetaProperty po = staticMetaObject->property(staticMetaObject->propertyOffset());
jo["test"].toVariant().canConvert(po.type());
The execution of this simple snippet:
{
QModelIndexList sel = ui->tableView->selectionModel()->selectedRows(0);
sel.at(0).isValid(); // To prevent removing the previous line by optimization
}
takes more than 30 seconds when the number of selected rows is about one million.
The construction of QModelIndex list is almost immediate, but the destruction takes forever.
The time is spent in this function :
template <typename T>
Q_INLINE_TEMPLATE void QList<T>::node_destruct(Node *from, Node *to)
{
if (QTypeInfo<T>::isLarge || QTypeInfo<T>::isStatic)
while(from != to) --to, delete reinterpret_cast<T*>(to->v);
else if (QTypeInfo<T>::isComplex)
while (from != to) --to, reinterpret_cast<T*>(to)->~T();
}
Does somebody has a solution? Is there any way to get indexes of selected rows without creating QModelIndexList, or can I speedup the destruction somehow?
A QList will, unfortunately, perform a memory allocation and deletion on every model index. For some reason, on your platform, the deallocation is very slow.
As a workaround, you can run the deallocation in a worker thread, leveraging the fact that QList is an implicitly shared class.
This assumes that it's safe to delete a QModelIndex in a non-gui thread. You must audit your code and relevant Qt code to ascertain that.
C++11
auto sel{ui->tableView->selectionModel()->selectedRows(0)};
// Use sel.
sel.at(0).isValid();
// Deallocate in a separate thread.
QtConcurrent::run(std::bind([] (QModelIndexList& p) {}, std::move(sel)));
// At this point, sel has been moved from and its destruction is trivial.
C++14
auto sel{ui->tableView->selectionModel()->selectedRows(0)};
// Use sel.
sel.at(0).isValid();
// Deallocate in a separate thread.
QtConcurrent::run([sel{std::move(sel)}] {});
// At this point, sel has been moved from and its destruction is trivial.
See this question for techniques of lambda-capture of a movable type.
C++98
template <typename T> class CopyMoves {
mutable T data;
public:
CopyMoves(T & old) { std::swap(data, old); }
CopyMoves(const CopyMoves & old) { std::swap(data, old.data); }
void operator()() {}
};
int main() {
QModelIndexList sel;
QtConcurrent::run(CopyMoves<QModelIndexList>(sel));
}
The CopyMoves class implements a class that moves its data member upon copy-construction. This is the horrible hack used by std::auto_ptr (don't use auto_ptr!). The non-empty CopyMoves::data member will be destructed in the worker thread. The other two instances of CopyMoves, holding empty data, will be destructed in the main thread.
I have a simple data class that gets called from another class.
Data Class:
class Data
{
public:
QString getName() const
{
return this->mName;
}
void setName(AccessData* access, const QString& name)
{
this->mName = name;
access->emitNameChanged(this);
}
private:
QString mName;
QReadWriteLock mLock;
};
And here's the class I am using to get/set a new name that also handles the locking:
class AccessData : public QObject
{
public:
QString getName(Data* data)
{
QReadLocker lock(&data->mLock);
return data->getName();
}
void setName(Data* data, const QString& name)
{
QWriteLocker lock(&data->mLock);
data->setName(this, name);
}
void emitNameChanged(Data* data)
{
emit this->nameChanged(data);
}
signals:
void nameChanged(AccessData* access, Data* data);
};
What happens is this:
I use the AccessData class to read and write the name of a Data instance. The AccessData class is responsible for locking for read/write. However, the Data class as you can see, in it's setName() method calls back the AccessData instance to properly emit a signal about the change. NOTE: This is just pseudo code, in reality it is more complex that's why the Data class needs to be able to emit signals through it's caller.
And here's the problem:
Say I have an instance of "Data" called "d": Data* d;
I am now using an "AccessData" instance "a" to change the name: a->setName(d, "new name");
At the same time, I am conncected to the nameChanged() signal with this code:
...
void nameChanged(AccessData* access, Data* data)
{
// Read the new name
QString newName = access->getName();
}
And here's the issue:
Calling a->setName(d, "new name")
"d" is now locked by "a" (Write lock)
"d" emits a signal about the name change though still locked
My method connected to the nameChanged signal tries to access getName()
This will cause another QReadLock issued which simply results in a deadlock
What can I do to properly handle this? There's two things that came up to me:
Emit the signal delayed (aka non-blocking) to get it into the loop.
This is NOT what I want because I want the signals to be pushed immediately.
Move the lock/unlock stuff within the Data class and first unlock, then emit the signal.
This is NOT what I want because I want to keep the Data class completely free from locking stuff.
Any idea? Do I have a miss conception?
thanks a lot
Alex
You need to make your mind about what the objects in your model represent. The philosophy of Data is suspicious. It owns the lock (has-a composition), but you don't want it to be self-lockable. If Data is meant to be a simple data wrapper, then it shouldn't own the lock. So either allow it to handle its own lock (and then you can unlock before emiting), or move the lock and the emitting too away from Data to AccessData.
If for some reason you want to keep the presented design, you can "solve" this with initializing mLock as QReadWriteLock::Recursive. Then the same thread can lock it multiple times over - given that you still call an equivalent amount of unlock(). But my personal experience is that reentrant locking is a sure sign of runaway/misunderstood call flow and a creeping misconcept which will bite back hard. While i do read about theoretical concepts which supposedly cannot be solved without reentrant locks, i still have to see one practically unavoidable.
I have a class which looks like this :
class MyClass {
public:
void drawText(const QString& rText);
void drawText(const std::string& rText);
};
I overloaded the drawText() method because I want to accept QString as well as std::string.
But when I write something like this :
MyClass foo;
foo.drawText("Hello");
The compiler is complaining that the call to drawText() is ambiguous.
I understand that from an array of char, the compiler cannot decide between a QString or a std::string, because both provide a suitable constructor.
But is there a way for me to make sure the user can use the drawText() method either by passing a QString or a std::stringor an array of char ?
To answer your question, yes: add another overload which takes const char*
The implicit conversion from const char* to QString is problematic because it assumes that the input is ASCII. I suspect the Qt folks would like to remove that constructor altogether but it would break source compatibility. If you want to disable it in your app, you can define QT_NO_CAST_FROM_ASCII.