How to iterate QAbstractListModel? - c++

I have a requirement where I have QAbstractListModel which is being updated continuously. The data type of QAbstractListModel is integar type.
I would like to copy the whole data at particular intervals into the vector so that vector is updated continuously and I can use it further.
Any idea how can I iterate QAbstractListModel by its index and copy it into vector.

Quick and dirty way of doing it :
QAbstractListModel m;
QVector<int> v;
const int nbRow = m.rowCount();
v.reserve(nbRow);
for (int i = 0; i < nbRow; ++i)
{
int myInt = m.index(i, 0).data().toInt();
v.append(myInt);
}

Related

I'm using qt to design a program and need help because my code is not DRY [duplicate]

I have a gui form, where multiple text boxes are present. I want to put their values inside an array. One way of doing it is by writing something like this
{array element } = ui->text_1->text();
and repeat it for text_2,text_3 upto n.
What I want is to run a loop and replace number portion of text box name in each cycle.
something like this {array element } = ui->text_{This number getting changed }->text();
How can it be done in qt?
There are two ways of doing this.
When you create the UI, instead of using text1, text2, etc. you create an array of QLineEdits (eg. std::vector<QLineEdit>) and then when you want to retrieve their values then simply iterate over this array
Iterate over the children of the container widget. You can get the list of the children using the following (documentation):
QList<QObject *> list = parentWidget->children();
Another option to those listed would be to create an array using an initializer list. Depending on how big the array is (and how often it changes), this might be workable.
QLineEdit* entries[] = { ui->text_0, ui->text_1, ui=>text_2 };
QStringList answers;
for ( int i = 0; i < 3; ++i )
{
answers += entries[i]->text();
}
here is an expanded version of Matyas' solution:
class MyClass : public QWidget
{
QStringList answers;
void FillAnswersList(QObject *base)
{
QLineEdit *lineEdit = qobject_cast<QLineEdit>(base);
if(lineEdit)answers.append(lineEdit->text());
else
{
foreach(QObject *child, base->children())
FillAnswersList(child);
}
}
};
If it is just the number changing, and always incrementing, there is another possible solution using QObject::findChild, which takes a name as a parameter.
QString name_template("text_%1");
QStringList answers;
for(int i = 0; i < MAX_TEXTS; ++i)
{
QLineEdit *edit = ui->findChild<QLineEdit *>(name_template.arg(i));
answers += edit->text();
}

Application stops responding when using QMap to store objects

A friend of mine and I are trying to make a game in C++ using Qt. We want to store a few QGraphicsTextItem in a QMap to access them during runtime. I've pasted the relevant parts of our code here, and our problem is that the program stops responding.
Game.cpp
int players = 6;
QGraphicsRectItem * overviewBox = new QGraphicsRectItem();
overviewBox->setRect(0, 0, 782, 686);
scene->addItem(overviewBox);
for(int i = 1; i <= players; i++) {
Container * ovContainer = new Container(overviewBox);
ovContainer->Overview(i, faceNo);
ovContainer->setPos(0, 0 + 110 * (i - 1));
info->textBoxMap[i-1] = ovContainer->textBox->playerText; // Program stops responding here
}
GameInfo.h
#ifndef GAMEINFO_H
#define GAMEINFO_H
#include "TextBox.h"
#include <QMap>
class GameInfo {
public:
GameInfo();
QMap<int, QGraphicsTextItem *> textBoxMap;
};
#endif // GAMEINFO_H
None of us have much experience using C++ or Qt, and we would appreciate any help.
Unless you are missing some code in your code snippet, then your QMap is not being used correctly. I think you have not allocated (inserted) any QMap items yet? - therefore you are accessing an element that is out of range (i.e. does not exist yet).
To add items into the QMap you can use insert(), like this (taken from Qt page):
QMap<int, QString> map;
map.insert(1, "one");
map.insert(5, "five");
map.insert(10, "ten");
Then to read your values back out:
QString str = map[1];
//or
QString str2 = map.value(5);
You don't need to iterate using a for loop but for your code you could do:
for(int i = 1; i <= players; i++)
{
:
:
info->textBoxMap.insert(i, ovContainer->textBox->playerText);
}
note
If you want to insert items with the same key you will need to use insertMulti(...), otherwise you will just overwrite the value of the key, e.g.:
QMap<int, QString> map;
map.insert(1, "test1");
map.insert(1, "test2");
Here, map[1] will return "test2". But I don't think this is what you want since your players are all going to be unique indexes I assume... but its worth pointing out that insert() with the same index just over-writes the value.

Retrieving Array Elements from a 2D array

I want to store 256*256 entries in a 2D array. I am doing like this:
struct Data
{
int Serial_Number;
int NextIndex;
} ;
struct Data Index[256][256];
Data obj1;
obj1.Serial_Number=1;
obj1.NextIndex=5;
Index[3][240]=obj1;
Now once I have stored all these values then How will I retrieve each value from an array element?
Like I want to retrieve a value stored at Index[3][240].
Secondly, Is this approach faster than unordered_map?
struct Data
{
int Serial_Number;
int NextIndex;
} ;
struct Data Index[256][256]; //should be this
Data obj1;
obj1.Serial_Number=1;
obj1.NextIndex=5;
Index[3][240]=obj1;
retrive the data:
struct Data data = Index[3][240];
acceess the struct's data:
data.Serial_Number;
If you want to retrieve each value one by one, just use the index from Index[0][0] to Index [256-1][256-1]. but if you want to access specific element from the array, you need to loop the array to find it.
for(int i = 0; i < 256; ++i)
for(int j = 0; j < 256; ++j)
if(Index[i][j] == what you are looking for)
{
found!
}
time complexity of this is O(m*n)(m is the length and n is width of the array) while unordered_map::find() runs in O(1) in the best case, O(n) in worst case (n is the number of elements, this may happen when the hash function is not good leading to too many hash collisions since unordered_map use hash table in its implementation).

What is the most efficient way to get all elements from a ProtoBuf RepeatedField?

I have serialized an array of floats into a RepeatedField using Google's Protcol Buffers.
When deserializing the data I use another settings class to hold the information in a more appropriate form for my game classes. A static CreateFrom method extracts and converts the data.
class VoxelTerrainSettings
{
public:
std::vector<int> indices;
btAlignedObjectArray<btVector3> vertices;
VoxelTerrainSettings(void);
~VoxelTerrainSettings(void);
static VoxelTerrainSettings CreateFrom(const VoxelTerrainProtoBuf::VoxelTerrainSettings &settings)
{
VoxelTerrainSettings s;
int numIndices = settings.indices().size();
s.indices.reserve(numIndices);
for (int i = 0; i < numIndices; ++i)
{
s.indices.push_back(settings.indices().Get(i));
}
int numVertices = settings.vertices().size();
s.vertices.reserve(numVertices);
int v = 0;
for (int i = 0; i < numVertices; ++i)
{
s.vertices.push_back(btVector3(settings.vertices().Get(v++), settings.vertices().Get(v++), settings.vertices().Get(v++)));
}
return s;
}
//VoxelTerrain Load();
};
However, the current method for extracting all the elements from the RepeatedField doesn't seem very elegant.
I've tried adopting a more efficient approach but they both throw out of range errors.
std::copy(settings.vertices().begin(), settings.vertices().end(), vv.begin());
std::copy(&settings.vertices().Get(0), &settings.vertices().Get(settings.vertices().size() - 1), &vv[0]);
What methods could I use to make element extraction more efficient?
std::copy uses std::front_inserter/std::back_inserter iterator types for inserting values into containers
Try the following:
// inserting into list/deque
std::copy(settings.vertices().begin(), settings.vertices().end(), std::front_inserter(vv));
// inserting into vector
std::copy(settings.vertices().begin(), settings.vertices().end(), std::back_inserter(vv));
Fastest is to reserve space up front, and then transform in one loop to optimize caching.
s.indices.reserve(settings.indices().size());
s.vertices.reserve(settings.vertices().size());
for (auto& vertex : settings.vertices()) {
s.indicies.push_back(...);
s.verticies.push_back(...);
}

How to run a loop using gui object names in qt?

I have a gui form, where multiple text boxes are present. I want to put their values inside an array. One way of doing it is by writing something like this
{array element } = ui->text_1->text();
and repeat it for text_2,text_3 upto n.
What I want is to run a loop and replace number portion of text box name in each cycle.
something like this {array element } = ui->text_{This number getting changed }->text();
How can it be done in qt?
There are two ways of doing this.
When you create the UI, instead of using text1, text2, etc. you create an array of QLineEdits (eg. std::vector<QLineEdit>) and then when you want to retrieve their values then simply iterate over this array
Iterate over the children of the container widget. You can get the list of the children using the following (documentation):
QList<QObject *> list = parentWidget->children();
Another option to those listed would be to create an array using an initializer list. Depending on how big the array is (and how often it changes), this might be workable.
QLineEdit* entries[] = { ui->text_0, ui->text_1, ui=>text_2 };
QStringList answers;
for ( int i = 0; i < 3; ++i )
{
answers += entries[i]->text();
}
here is an expanded version of Matyas' solution:
class MyClass : public QWidget
{
QStringList answers;
void FillAnswersList(QObject *base)
{
QLineEdit *lineEdit = qobject_cast<QLineEdit>(base);
if(lineEdit)answers.append(lineEdit->text());
else
{
foreach(QObject *child, base->children())
FillAnswersList(child);
}
}
};
If it is just the number changing, and always incrementing, there is another possible solution using QObject::findChild, which takes a name as a parameter.
QString name_template("text_%1");
QStringList answers;
for(int i = 0; i < MAX_TEXTS; ++i)
{
QLineEdit *edit = ui->findChild<QLineEdit *>(name_template.arg(i));
answers += edit->text();
}