The values are like is not null, canconvert is true and is valid. But still segmentation fault occurs when trying to cast. I am debugging and the value set might have been deleted just before setValue is called with a new value.
QVariant m_model = 0;
is a member var
void Handler::setValue(const QVariant &var)
{
bool isNull = m_model.isNull();
bool canConvert = m_model.canConvert<QObject*>();
bool isValid = m_model.isValid();
if(!m_model.isNull() && m_model.canConvert<QObject*>()) {
bool sConverts = (nullptr != m_model.value<QObject*>());
}
m_model = var;
}
Can someone tell why it crashes when still m_model has some data in it.
First some problems with your code:
QVariant::canConvert() returns whether the type of the value is convertible at all, not if the actually contained value can be converted. Example: you create a QVariant with a QString as value. Calling myValue.canConvert<double>() will return true, even if your string was "nonsense". That's because QVariant is generally able to convert strings like "1.0" to a double value of 1.0.
QVariant::isValid() returns whether the contained type is not QMetaType::UnknownType. This mostly only happens when you create a QVariant without assigning a value.
QVariant m_model = 0; will create a QVariant with type int. Don't do that. Just declare it without the = 0 part. QVariant (like other value types in Qt, i.e. QString, QSize etc.) doesn't need to be initialized to be null, empty or invalid. Declaring it like you did will make isValid() return true, though you might intend it to return false.
That said, i'm unsure of what you want to achieve in your code snippet. Basically you're testing m_model before assigning a new untested value var to it (why???).
As you said your value var (or probably the contained value) might have been deleted just before setValue() is called. If the QObject has been deleted and the pointer has not been set to nullptr explicitly you're handing a QVariant with a dangling pointer to the function. As setValue() doesn't test the new value var you will have that same dangling pointer in m_model, resulting in a crash whenever you try accesing it.
Related
I have a QQuickItem that corresponds to a MapPolyline object. The polyline has a property called path, which is defined in the documentation to be of type list<coordinate>. coordinate is a type that maps to QGeoCoordinate in the C++ world. I'm trying to figure out how to set this property's value from C++.
If I check the QMetaObject for the item and look for the type that it reports for the path property, it indicates a type of QJSValue. It's unclear to me how I can set this value from C++ using either QObject::setProperty() or QQmlProperty::write(). I've tried the following:
I tried creating a QJSValue that is of array type, with each element holding the coordinate values that I want, something like this:
void set_property_points(QQuickItem *item, const QVector<QGeoCoordinate> &pointList)
{
// Get the QML engine for the item.
auto engine = qmlEngine(item);
// Create an array to hold the items.
auto arr = engine->newArray(pointList.size());
// Fill in the array.
for (int i = 0; i < pointList.size(); ++i) arr.setProperty(i, engine->toScriptValue(pointList[i]));
// Apply the property change.
item->setProperty("path", arr.toVariant());
}
This didn't work; the call to setProperty() returns false.
I also tried stuffing the list of points into a QVariantList, which seems to be the best match I can find in C++ for a list<coordinate> (QGeoCoordinate is capable of being placed in a QVariant):
/// Apply a list of `QGeoCoordinate` points to the specified `QQuickItem`'s property.
void set_property_points(QQuickItem *item, const QVector<QGeoCoordinate> &pointList)
{
QVariantList list;
for (const auto &p : pointList) list.append(QVariant::fromValue(p));
item->setProperty("path", list);
}
This didn't work either; same results.
This process doesn't seem to be well-documented. What format do I need to put my data into to make this work?
Turns out that a third approach that isn't mentioned in the documentation actually seems to work. I needed to set the property like this:
QJSValue arr; // see above for how to initialize `arr`
item->setProperty("path", QVariant::fromValue(arr));
My QTableView doesn't show strings from a QStringList.
In QTableWidget I have QTableWidgetItems. Must I set the strings manually or will the view show them automatically? In all the tutorials I don't see a "->setItem", they appear automatically.
I have 2 QLineEdits that give the QStrings to my Model :
void View::pushButtonClicked() {
meinModel->setData(txtname->text(), txtvalue->text());
}
In setData I push the Strings in two QLists.
names.push_back(name);
values.push_back(value);
I emit a dataChanged signal with the index from topleft and bottomright.
QModelIndex topLeft = createIndex(names.size()+1,0);
QModelIndex bottomRights = createIndex(names.size()-1,1);
emit dataChanged(topLeft, bottomRights);
I have a QAbstractTableModel and so i override the columnCount, rowCount and data Method.
In my data() Method I return my value and name:
QString returnValue;
if(0 == index.column()) { returnValue = names.at(index.row()); }
All of this compiles without warnings, but doesn't work correctly :( Is there something I'm doing obviously wrong?
One obvious problem is that you didn't get the semantics of dataChanged correctly. dataChanged means that an existing item has changed its value. When you change the structure of the model by adding/removing rows or columns, you have to enclose the modification in beginXxx and endXxx calls - see this answer for details.
For example:
void MyModel::setData(const QString & name, const QString & value) {
beginInsertRows(QModelIndex(), names.size(), names.size());
names.push_back(name);
values.push_back(value);
endInsertRows();
}
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);
I know you can do it when you have access to the QStandardItemModel but using combobox->model() returns a QAbstractItemModel which doesn't have the item(int row, int col) accessor. I've tried working with QAbstractItemModel::itemData(QModelIndex) but can't get it to work as I require.
I just need to get the CheckState of the items, if(item.checkState() == Qt::Checked) etc...
Edit: I have this code, can I cast it to a QStandardItem?
QModelIndex index(1, 0);
QVariant item = ui->SearchAssessmentCombo->model()->data(index, Qt::CheckStateRole);
You can't declare an index yourself, all indices are tied to a model. Internally, the data() function will determine that the index you gave in the parameter does not belong to the model and will return null values for everything.
You need to ask your model to give you a valid index before you can use it.
QModelIndex index = ui->SearchAssessmentCombo->model()->index(1,0);
I think that this is not a question regarding especially Qt but a quaestion of a lack of programming expeience.
I derived a class from QTreeWidgetItem and I added some bolean flags. When i initialize a QTreeWidget I add two of them by
_NewItem1=MyQTreeWidgetItem(_treewidget);
than later I add some items by
_NewItem1_1=MyQTreeWidgetItem(_NewItem1);
_NewItem1_1->boleanvalue1=true;
If I later want to return these Items I call
(MyQTreeWidgetItem)_NewItem1->child(i)
but this of course just returns me a MyQTreeWidgetItem with newly initialized bolean flags.
Do I have to override the child function to retun the true Items which I initialized earlier?
_NewItem1->child(i) returns pointer to QTreeWidgetItem, which is a base class for MyQTreeWidgetItem. You have cast is safely to MyQTreeWidgetItem, taking into account it may be also real QTreeWidgetItem. This is achieved with dynamic_cast in C++, which checks type at runtime.
QTreeWidgetItem *item = _NewItem1->child(i);
MyQTreeWidgetItem *myItem = dynamic_cast<MyQTreeWidgetItem>(item);
if (myItem) {
qDebug() << myItem->boleanvalue1;
} else {
qDebug() << item << "is not of type MyQTreeWidgetItem";
}
On the other hand, type-casting operator () allows to convert any type into any other type without any checking, if this kind of conversion is possible. Like, for example, you've converted pointer to QTreeWidget into object of type MyQTreeWidgetItem. The subsequent access to the variable will produce either a run-time error or a unexpected result.