Help with QMap in Qt

Pages: 12
QMap works find for me when I only have 2 QStrings I need to put into it by using this code:
QMap<QString, QString> variable;

What I would like to do though is put 8 QStrings in there how would I do this? I tried this code:
QMap<QString,QString,QString,QString,QString,QString,QString,QString>variable;

unfortunately this code does not work I get an error saying it can only have two QString's.

Any help would be greatly appreciated.

Thanks.
P.S. The only reason I need 8 of them is because I have 8 lineEdit boxes that I want to open and load the data from these are the only two errors I am getting that are making my program not run =/

(same error twice)
---------------------------------------------------------------------------------------------------
error: no matching function for call to 'QMap<QString, QString>::insert(QString&, QString&, QString&, QString&, QString&, QString&, QString&, QString&)'
---------------------------------------------------------------------------------------------------
Assuming QMap is like some kind of Qt specific recreation of std::map, that's now how they work.

maps have two parts (not 8): a key, and a value. It allows you to look up any contained value by giving a key.

Now, the neat thing is that neither the key nor the value have to be a single string. They can be complex objects or even other containers, as long as the key is searchable.

So, if you want to assiciate 1 string with 7 other strings (ie: a string key, whose value is a collection of 7 other strings), one way to do this would be to put those 7 other strings in a struct.

1
2
3
4
5
6
7
struct MyStruct
{
  QString stuff[7];
};


QMap<QString, MyStruct> foo;



But if that's not what you're looking for, then you'll have to be more specific about what you want from this map.


Really... I don't see what a map has to do with having edit boxes....
okay thanks i'll try this out in about a half an hour and let you know if it worked
oh and it has to do with the edit boxes because I want to keep the data from my 8 text boxes when I move from entry one to entry 2 the QMap worked fine when I only had Name and one entry but more than one entry its not working have to try your suggestion out.
Are you sure you want a map for this?
shit I wish you had skype or something would be easier to communicate and
heres a link to something that is very similar:
http://doc.qt.digia.com/4.7-snapshot/tutorials-addressbook-part2.html

except when I use that it only works when I have two QStrings but I have 8 I need to put in there since I have 8 text fields.

EDIT::
its like the very botttom section and at the very top it has the cpp and the h codes


the actual code I have on my header is
1
2
3
4
5
6
7
8
9
 QMap<QString, QString> foods;
    QString oldFood;
    QString oldCalorie;
    QString oldProtein;
    QString oldCarb;
    QString oldFat;
    QString oldSugar;
    QString oldSodium;
    QString oldFiber;


and in my c++ file i have this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
void CalorieCounter::submitFood()
{
    QString food = foodLine->text();
    QString calorie = calorieLine->text();
    QString protein = proteinLine->text();
    QString carb = carbLine->text();
    QString fat = fatLine->text();
    QString sugar = sugarLine->text();
    QString sodium = sodiumLine->text();
    QString fiber = fiberLine->text();

    if (food.isEmpty() || calorie.isEmpty() || protein.isEmpty()
            || carb.isEmpty() || fat.isEmpty() || sugar.isEmpty()
            || sodium.isEmpty() || fiber.isEmpty()) {
        QMessageBox::information(this, tr("Empty Field"),
            tr("Please enter food, calorie, protein, carb, fat, sugar, sodium and fiber"));
        return;
    }

    if (currentMode == AddingMode) {

        if (!foods.contains(food)) {
            foods.insert(food, calorie, protein, carb, fat, sugar, sodium, fiber);
            QMessageBox::information(this, tr("Add Successful"),
                tr("\"%1\" has been added to your calorie counter.").arg(food));
        } else {
            QMessageBox::information(this, tr("Add Unsuccessful"),
                tr("Sorry, \"%1\" is already in your calorie counter.").arg(food));
        }
    } else if (currentMode == EditingMode) {

        if (oldFood != food) {
            if (!foods.contains(food)) {
                QMessageBox::information(this, tr("Edit Successful"),
                    tr("\"%1\" has been edited in your calorie counter.").arg(oldFood));
                foods.remove(oldFood);
                foods.insert(food, calorie, protein, carb, fat, sugar, sodium, fiber);
            } else {
                QMessageBox::information(this, tr("Edit Unsuccessful"),
                    tr("Sorry, \"%1\" is already in your calorie counter.").arg(food));
            }
        } else if (oldCalorie != calorie) {
            QMessageBox::information(this, tr("Edit Successful"),
                tr("\"%1\" has been edited in your calorie counter.").arg(food));
            foods[food] = calorie;
        } else if (oldProtein != protein) {
            QMessageBox::information(this, tr("Edit Successful"),
                tr("\"%1\" has been edited in your calorie counter.").arg(food));
            foods[food] = protein;
        }
        else if (oldCarb != carb) {
                    QMessageBox::information(this, tr("Edit Successful"),
                        tr("\"%1\" has been edited in your calorie counter.").arg(food));
                    foods[food] = carb;
                } else if (oldFat != fat) {
            QMessageBox::information(this, tr("Edit Successful"),
                tr("\"%1\" has been edited in your calorie counter.").arg(food));
            foods[food] = fat;
        } else if (oldSugar != sugar) {
            QMessageBox::information(this, tr("Edit Successful"),
                tr("\"%1\" has been edited in your calorie counter.").arg(food));
            foods[food] = sugar;
        } else if (oldSodium != sodium) {
            QMessageBox::information(this, tr("Edit Successful"),
                tr("\"%1\" has been edited in your calorie counter.").arg(food));
            foods[food] = sodium;
        }
        else if (oldFiber != fiber) {
                    QMessageBox::information(this, tr("Edit Successful"),
                        tr("\"%1\" has been edited in your calorie counter.").arg(food));
                    foods[food] = fiber;
                }

    }

    updateInterface(NavigationMode);
}




EDIT::::

the error is on line 23 not 16 sorry for that earlier
Last edited on
I changed the foods.insert(food, calorie, protein, carb, fat, sugar, sodium, fiber); with foods.insert(food, calorie);
but then it makes all the text fields the value of "calorie" instead of what their values are supposed to be

EDIT:
I tried putting them into a QStringList like you said but I get error saying I cant put QStringList into QMap, so then I tried doing list[0] or any number, but then it displays that data in all the other text boxes but I need each text box to display its actual data. have 8 strings: calorie, protein, carb, fat, sugar, sodium, fiber. and I need to insert all of those but it seems to only let me insert one =/
Last edited on
I don't see how adding elements to a map would change a text field. I must be misunderstanding what a QMap is.

Sorry. You'll have to get help from someone more familiar with Qt.
I tried switching the QMap to the QStringList and it got rid of the insert error but then I get a new erorr on this line of code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void CalorieCounter::next()
{
    QString food = foodLine->text();
    QMap<QString, QString>::iterator i = foods.find(food);

    if (i != foods.end())
        i++;

    if (i == foods.end())
        i = foods.begin();

    foodLine->setText(i.key());
    calorieLine->setText(i.value());
    proteinLine->setText(i.value());
    carbLine->setText(i.value());
    fatLine->setText(i.value());
    sugarLine->setText(i.value());
    sodiumLine->setText(i.value());
    fiberLine->setText(i.value());
}

void CalorieCounter::previous()
{
    QString food = foodLine->text();
    QMap<QString, QString>::iterator i = foods.find(food);

    if (i == foods.end()) {
        foodLine->clear();
        calorieLine->clear();
        proteinLine->clear();
        carbLine->clear();
        fatLine->clear();
        sugarLine->clear();
        sodiumLine->clear();
        fiberLine->clear();
        return;
    }

    if (i == foods.begin())
        i = foods.end();

    i--;
    foodLine->setText(i.key());
    calorieLine->setText(i.value());
    proteinLine->setText(i.value());
    carbLine->setText(i.value());
    fatLine->setText(i.value());
    sugarLine->setText(i.value());
    sodiumLine->setText(i.value());
    fiberLine->setText(i.value());
}


Get errors on line 4: error: conversion from 'QMap<QString, QStringList>::iterator' to non-scalar type 'QMap<QString, QString>::iterator' requested

6&9: error: ambiguous overload for 'operator!=' in 'i != ((CalorieCounter*)this)->CalorieCounter::foods.QMap<Key, T>::end [with Key = QString, T = QStringList]()'

10: error: no match for 'operator=' in 'i = ((CalorieCounter*)this)->CalorieCounter::foods.QMap<Key, T>::begin [with Key = QString, T = QStringList]()'

25: same error as line 4.

and about 20 more errors after that relating to the QMap.


@Disch

QMap is a very similar thing to std::map - your original instincts are right giblit probably needs a different data structure.

@giblit
There are all kinds of combinations of ways to do this, if you would like to use a map, then go with the pair of: a key value; and class or struct object with a vector of 8 items inside, which would allow you to easily modify things if another Edit box is added.

But a list or vector or array of a class object would probably do just as well. Having an array means it is not extendible though.

Some more observations: Provide an interface to your class so that the code in lines 12 to 19 is in a class function of it's own - thereby avoiding the duplication of code in lines 43 - 50. Some thing similar for lines 28 -35.

In your original code, the various modes you have should not be coded with if statements, rather they should be in functions that form the interface for the class. For example have the functions AddInfo & UpdateInfo.

Instead of else if's for each item, consider having a private bool variable (with it's corresponding setExisting & IsExisting functions) to test whether data exists or not. That way you can greatly reduce your code, and avoid variable names that start with "old". There is a convention that member names start with m_ - this can make naming things easier.

I know this all means that you will have to rewrite your code quite a bit, but hopefully you can see the benefits.

I look forward to seeing how you go - cheers.

Edit: Actually I was lucky to see this - it is in the windows programming section which I don't look at much, because I thought it was for MS Windows programming. Putting it in General C++ programming might give it more exposure.


Last edited on
Well when I insert a QStringList instead of just the QString it gives me a lot of other errors. Is there a way to .insert() more than one QString without using a QStringList? or would it be better to try and figure out a new way to get all my data in the text boxes? Right now I can dispaly them in there when i submit, but if I go to a previous or next entry then it will put the QString data from the one Qstring into all the text boxes and i would like to have their individual text into the text box it belongs to. btw is there a way to put files on this forum so that you could see the problem I am having first hand

EDIT want to post my complete cpp code but its like 15k characters and can only post 8k =/
Last edited on
Tried using a loop on a list and when I do that then it puts the last data (fiber) into all the other text boxes by using this code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 QStringList list;
    QString food = foodLine->text();
    QString calorie = calorieLine->text();
    QString protein = proteinLine->text();
    QString carb = carbLine->text();
    QString fat = fatLine->text();
    QString sugar = sugarLine->text();
    QString sodium = sodiumLine->text();
    QString fiber = fiberLine->text();
    list << calorie << protein << carb << fat << sugar << sodium << fiber;

if (!foods.contains(food)) {
            for(int i = 0; i<7;i++){
                foods.insert(food, list[i]);
            }

}


I want it to insert value of list[0] all the way to list[7] into the food string and not only insert 1 value (the last value);

when I insert I pretty much need to insert the values of these:

foodLine->setText(i.key());
calorieLine->setText(i.value());
proteinLine->setText(i.value());
carbLine->setText(i.value());
fatLine->setText(i.value());
sugarLine->setText(i.value());
sodiumLine->setText(i.value());
fiberLine->setText(i.value());

by using food as the key in the insert function cant seem to figure out how to get the value of all them added, tried doing 1 at a time but then it only does the last one just like using a loop.
Last edited on
If I am not making myself very clear I am sorry, but pretty much if you go to this link http://qt-project.org/doc/qt-5.0/qtwidgets/tutorials-addressbook-part2.html it has a tutorial on an addressbook where it has only Name: and Address:

what I would like to do would be something like Name and then two values 1 of Address and 1 of Phonenumber.

how would I do this?

EDIT:
I found another addressbook tutorial which is alot nicer looking gui at http://harmattan-dev.nokia.com/docs/library/html/qt4/itemviews-addressbook.html , but
it once again only has two fields the key: Name, and value:Address, and I want more than one value eg(Address, Phone, DoB);
Last edited on
@giblit
What I think you need to do is create a struct for a person's information. It's convenient to use QMap<QString, QString> for a name and address, but, as Disch has mentioned, it is made up of only a key and a value.
If you define a struct, say, 'information'
1
2
3
4
5
struct information
{
    QString name, address, DoB, phone;
    //.... etc etc
};

Then you can use a vector, or something to store multiple 'information' structures. Or you could even use a QMap<QString, information> to associate a QString name with an information structure.
The same goes for your food data.
Because you're dealing with multiple variables that relate to a specific idea, you need to abstract that into a structure, and then store instances of that structure in a Qt container.
tried using the struct doesnt work, I get an error it acts as if the struct isnt even in the insert function.

I found this other website that has what I want except they are very confusing been trying to get an address book like theirs set up but with no luck atm =/

http://www.digitalfanatics.org/projects/qt_tutorial/chapter07.html

thats basically what I need 1 key and then 2+ values

they have Name; email , phone
tried using the struct doesnt work, I get an error it acts as if the struct isnt even in the insert function.


Can you post the code you had for that? The solutions that we have mentioned should work - but maybe you haven't coded it correctly?

You can use the [] operator to access/ insert members of the map, rather than the insert function.

If you want to post all of your code, you can use the pastebin site, and provide us with a link to it.

thats basically what I need 1 key and then 2+ values


Then you need to do what Thumper and the rest of us have said:

1
2
3
4
5
6
7
struct information
{
    QString name, address, DoB, phone;
    //.... etc etc
};

QMap<QString, information>
Last edited on
giblit wrote:
tried using the struct doesnt work
Show the code you're using, and the exact error you get, please.

giblit wrote:
I need 1 key and then 2+ values
Then that's exactly what you need to do; create a structure/class that contains 2+ values, and use it as the value portion of the QMap container.
There are no existing container (afaik) that can handle a variable amount of values per key. There's really no need for them too either.
I did this:
1
2
3
4
5
//code.cpp
struct info {
QString calorie, protein, carb, fat, sugar, sodium, fiber
};


after doing that I get this:
[output error: expected primary-expression before ')' token[/output]

and if I change the QMap<QString, QString>foods
to QMap<QString, info>foods
on my header I get a ton of errors even if I put a second info struct in the header

I found a way I can do it though by using this tutorial http://qt-project.org/doc/qt-5.0/qtsql/sqlwidgetmapper.html

have one question about that though I am trying not to have to type all 8 of those variables like 1000000 times each so instead im trying to use a for loop but it doesnt seem to be working I need to combine like 4 strings into 1 string for example:
1
2
3
4
5
6
7
8
9
char type(void){
         QString itemlist[] = {"food","calorie","protein","carb","fat","sugar","sodium","fiber"};
         QString labellist[] = {"QLabel*","QSpinBox*","QLineEdit*"};
         QString labellist2[] = {"Label","Spin","Line"};
         for(int i=0;i<sizeof itemlist/sizeof(QString); i++){
             labellist[0]+=itemlist[i]+=labellist2[0];
             labellist[1]+=itemlist[i+1]+=labellist2[1];
             labellist[2]+=itemlist[0]+=labellist2[2];
         };


is supposed to give me this:
[output]QLabel*foodLabel
QLabel*calorieLabel
//ect....[/output]
but it doesnt and if I change the += to << in the output I get what I want but I can not use that in the private: or I get this error:
error: no match for 'operator<<' in 'labellist[0] << itemlist[i]'




Would it be better for me to just type it all out manually? I did that origonally and took for ever but having to restart so I can get around the .insert and someone told me earlier that its better to use the loops so I dont have to repeat everything but can't seem to find away to do it.

PS sorry for being such a noob only had a programming class for about 3 weeks but we only did basic stuff like "hello world" which was easy and my mom wants me to make her a program so she can keep track of what she is eating

EDIT:
just uploaded a .rar that has all the files from my calorie counter to this link you can see what I am having wrong if u quickly submit two things and then hit the next/prev button. link is:
http://www.filefactory.com/file/49zt4ccvvi1f/n/CalorieCounter.rar
Last edited on
Glad you solved what you were trying to initially do.

As for not wanting to type all the variable names, what you're trying to do isn't actually possible. You would be writing code to create/modify the existing code at runtime, which can't be done (in C++, I can't speak for other langauges). Those specific variable names don't actually exist after you compile the program. If you want to access an existing variable in code, you have to type the variable name out.

You can create strings of label names, but that's all they'll be, strings that don't represent the variable.
Last edited on
Pages: 12