PDA

View Full Version : Multiple QListWidget Sorting Problem



giblit
27th March 2013, 05:37
Basically I have 8 QListWidgets but only 1 of them is visable I use the other Widgets to keep track of my data
I have a text file that has Food name (the visible QListWidget), calorie amount, protein amount....ect (for the other 7 that are not visible).
I have it so when I read my text file that contains all the data it will put the values in the QListWidgets
example:
QListWidget1 reads in the text of "Banana" for row # 1.
QListWidget2 reads in the text of "121" for row # 1 in widget #2.
QListWidget3 reads in the text of "232" for row # 1 in widget # 3.
ect....for the rest of the QListWidgets;
I then turn the strings for QListWidgets 2-8 into ints so I can keep track of their values and add them together.
everything works perfect as QListWidgetItem row 1 = row 1 for the other 7 QListWidgets

but say I have another type of food in QListWIdget1 called "Apple" that is row # 2 and it has its values for the other QListWidgets in row2 in all of them.
Everything works perfect.

I put sorting on in QListWidget1 say Ascending order so Apple1 gets switched to row 1 and Banana to row 2.
How do I switch the values of the other 7 QListWidgets to match the order?

here is my code for header:

#ifndef LISTWIDGETDIALOG_H
#define LISTWIDGETDIALOG_H

#include <QDialog>
#include <QListWidgetItem>

class QListWidget;
class QPushButton;


class ListWidgetDialog : public QDialog
{
Q_OBJECT

public:
ListWidgetDialog();
//~ListWidgetDialog();





private:
QListWidget *listWidget;
QListWidget *invisWidget[7];


};

#endif

and the code for my c++

#include <QtGui>
#include "listwidgetdialog.h"
#include <iostream>

using namespace std;
int value[7];
int totalValue[7];



int row;





ListWidgetDialog::ListWidgetDialog()
{

listWidget = new QListWidget;
for(int i = 0; i<7;i++){
invisWidget[i] = new QListWidget;
}

QFile file(QDir::homePath() + "/caloriecounter.txt");
if (file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
in.setCodec("UTF-8");
while (!in.atEnd()) {
listWidget->addItems(QString(in.readLine()).split('\n'));
for(int i = 0; i<7; i++){
invisWidget[i]->addItems(QString(in.readLine()).split('\n'));
}
in.readLine();
}
}

QGridLayout *layout = new QGridLayout;
layout->addWidget(listWidget,25, 1);
listWidget->sortItems(Qt::AscendingOrder);
for(int i = 0; i<7; i++){
invisWidget[i]->sortItems(Qt::AscendingOrder);
}
setLayout(layout);











listWidget->setCurrentRow(0);
connect(listWidget,SIGNAL(currentItemChanged(QList WidgetItem*,QListWidgetItem*)),
this,SLOT(listWidgetItemClicked(QListWidgetItem*)) );

selectedItem = listWidget->currentItem()->text();
}

void ListWidgetDialog::listWidgetItemClicked(QListWidge tItem *item)
{
selectedItem = item->text();
row = listWidget->currentRow();
for(int i = 0; i<7; i++){
invisWidget[i]->setCurrentRow(row);
value[i] = invisWidget[i]->currentItem()->text().toInt();
}

}

I tried to delete all the stuff that has nothing to do with this problem so it might look a little funky
hopefully I didnt delete any important lines

Added after 34 minutes:

One more question ontop of this one sorry =/
I have two c++ files,
one has a few QStringLists and I need add new items to it from another c++ file how would I do this?
I have this in my c++ file 1:

QStringList dates, foods, totalCalories, totalProteins, totalCarbs, totalFats, totalSugars, totalSodiums, totalFibers;
im using those to set items in a QTreeWidget and I would like to add new items via QDialog.
here is the code I have in c++ file two:

void ListWidgetDialog::okButton_pressed(){
extern QStringList foods, totalCalories, totalProteins, totalCarbs, totalFats, totalSugars, totalSodiums, totalFibers;
for(int i = 0; i<24;i++){
foods << selectedFoods[i];
}
for(int i = 0; i<7; i++){
QString totalValueStr[7] = QString("%1").arg(totalValue[i]);
totalCalories << totalValueStr[i];
totalProteins << totalValueStr[i];
totalCarbs << totalValueStr[i];
totalFats << totalValueStr[i];
totalSugars << totalValueStr[i];
totalSodiums << totalValueStr[i];
totalFibers << totalValueStr[i];
}
ListWidgetDialog::close();
}

and I get these errors:
undefined reference to 'foods'
undefined reference to 'totalCalories'
ect...for them all
Any suggestions would be greatly appreciated

Santosh Reddy
27th March 2013, 05:39
What you are doing not a good approach, you will have problems maintaining such code, the probelms just started.

I suggest not to maintain multiple QListWidgets, instead maintain only one QListWidget, and implement a custom QListWidgetItem class, and just re-implemnt data() and setData() virtual functions to handle user defined data roles. Each of the custom data like, calorie amount, protein amount etc would have ItemDataRole as (Qt::UserRole + 0), (Qt::UserRole + 1)

Edit:
Wait I think QListWidgetItem already supports multiple user data roles internally, I have not tested/used them, just give it a try.

giblit
27th March 2013, 05:50
none of these roles look like they would work though

enum Qt::ItemDataRole

Each item in the model has a set of data elements associated with it, each with its own role. The roles are used by the view to indicate to the model which type of data it needs. Custom models should return data in these types.

The general purpose roles (and the associated types) are:

Constant Value Description
Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)
Qt::DecorationRole 1 The data to be rendered as a decoration in the form of an icon. (QColor, QIcon or QPixmap)
Qt::EditRole 2 The data in a form suitable for editing in an editor. (QString)
Qt::ToolTipRole 3 The data displayed in the item's tooltip. (QString)
Qt::StatusTipRole 4 The data displayed in the status bar. (QString)
Qt::WhatsThisRole 5 The data displayed for the item in "What's This?" mode. (QString)
Qt::SizeHintRole 13 The size hint for the item that will be supplied to views. (QSize)
Roles describing appearance and meta data (with associated types):

Constant Value Description
Qt::FontRole 6 The font used for items rendered with the default delegate. (QFont)
Qt::TextAlignmentRole 7 The alignment of the text for items rendered with the default delegate. (Qt::AlignmentFlag)
Qt::BackgroundRole 8 The background brush used for items rendered with the default delegate. (QBrush)
Qt::BackgroundColorRole 8 This role is obsolete. Use BackgroundRole instead.
Qt::ForegroundRole 9 The foreground brush (text color, typically) used for items rendered with the default delegate. (QBrush)
Qt::TextColorRole 9 This role is obsolete. Use ForegroundRole instead.
Qt::CheckStateRole 10 This role is used to obtain the checked state of an item. (Qt::CheckState)
Accessibility roles (with associated types):

Constant Value Description
Qt::AccessibleTextRole 11 The text to be used by accessibility extensions and plugins, such as screen readers. (QString)
Qt::AccessibleDescriptionRole 12 A description of the item for accessibility purposes. (QString)
User roles:

Constant Value Description
Qt::UserRole 32 The first role that can be used for application-specific purposes.

or could I just set the data as a random role and then just access that without doing what the role says?

EDIT: actually could it be the Qt::UserRole i'm a litle confused on what it means tho

Santosh Reddy
27th March 2013, 05:57
Take a look at this example, try running it and see how it works. I am storing 5 user data with in a QListWidgetItem along with its default text.



#include <QtGui>

class Object : public QObject
{
Q_OBJECT

public:
explicit Object(QObject * parent)
: QObject(parent)
{

}

public slots:
void showDetails(const QModelIndex &index)
{
QListWidget * list = new QListWidget;

list->addItem(new QListWidgetItem(index.data().toString()));
list->addItem(new QListWidgetItem(index.data(Qt::UserRole + 0).toString()));
list->addItem(new QListWidgetItem(index.data(Qt::UserRole + 1).toString()));
list->addItem(new QListWidgetItem(index.data(Qt::UserRole + 2).toString()));
list->addItem(new QListWidgetItem(index.data(Qt::UserRole + 3).toString()));
list->addItem(new QListWidgetItem(index.data(Qt::UserRole + 4).toString()));

list->show();
}
};

void addItem(QListWidget * list, int num)
{
const QString name = QString("Item-%1").arg(num);
const QString data0 = QString("Data-%1").arg(num);
const QString data1 = QString("Data-%1").arg(num);
const QString data2 = QString("Data-%1").arg(num);
const QString data3 = QString("Data-%1").arg(num);
const QString data4 = QString("Data-%1").arg(num);

QListWidgetItem * item = new QListWidgetItem(name);

item->setData(Qt::UserRole + 0, data0);
item->setData(Qt::UserRole + 1, data1);
item->setData(Qt::UserRole + 2, data2);
item->setData(Qt::UserRole + 3, data3);
item->setData(Qt::UserRole + 4, data4);

list->addItem(item);
}


int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QListWidget w;

for(int i = 0; i < 5; i++)
addItem(&w,i);

Object * object = new Object(&w);
w.connect(&w, SIGNAL(doubleClicked(QModelIndex)), object, SLOT(showDetails(QModelIndex)));
w.show();

return app.exec();
}

#include "main.moc"

giblit
27th March 2013, 06:00
Thanks alot now I see, I wasn't quite sure on the Qt::UserRole this is my first program im making =p
and do you know what I could do to fix the second error I am having with the external variables?

Santosh Reddy
27th March 2013, 06:06
Make sure the C++ file with variable declaration is included in the project (pro file)

and

Do clean build, it should solve the problem.

giblit
27th March 2013, 06:15
it is in the pro file and I did a clean build still getting the undefined.

I have the variable names(QStringList dates, foods, totalCalories, totalProteins, totalCarbs, totalFats, totalSugars, totalSodiums, totalFibers;) in c++ file one
then I have external (extern QStringList dates, foods, totalCalories, totalProteins, totalCarbs, totalFats, totalSugars, totalSodiums, totalFibers;) in c++ file two
I even tried putting the variables in c++ file one into the header and then including the header in c++ file two but then I get some more errors about multiple definitions when there is only one

EDIT:
I guess I had the extern in the wrong file I just switched that to c++ file one and it worked good thanks again

giblit
28th March 2013, 02:07
what am I doing wrong?
I made a test program before I tried adding it to my actual program here is the code that works perfectly:

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
for(int i = 0; i<50; i++){
QListWidgetItem *item = new QListWidgetItem;
QString itemName = QString("Item %1").arg(i);
//cout << "ITEM NAME: " << itemName.toStdString() << endl;
for(int j = 0; j<50; j++){
QString dataName = QString("Data %1").arg(j);
//cout << "DATA NAME: " << dataName.toStdString() << endl;
QVariant itemData(dataName);
item->setData(Qt::UserRole + j, itemData);
//cout << "Item data " << j << ": " << item->data(Qt::UserRole + j).toString().toStdString() << endl;
}
item->setText(itemName);
ui->listWidget->insertItem(i, item);
//cout << "DATA NAMES?: " << dataName.toStdString() << endl;
}
}
void MainWindow::on_listWidget_itemClicked(QListWidgetI tem *item)
{
int row = ui->listWidget->currentRow();
cout << ui->listWidget->item(row)->text().toStdString() << endl;
for(int i = 0; i < 50; i++){
cout << ui->listWidget->item(row)->data(Qt::UserRole + i).toString().toStdString() << endl;
}

}
this is a main window app and i was too lazy to add the stuff dynamically so I just threw a QListWidget.

my code on my real project that isnt working is this:
oh and it doesnt have any errors and runs fine..but if I try and click on an item...it just crashes almost instantly


QFile file(QDir::homePath() + "/caloriecounter.txt");
if (file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
in.setCodec("UTF-8");
while (!in.atEnd()) {
QListWidgetItem *item = new QListWidgetItem;
QString itemName = (in.readLine());
for(int i = 0; i<7; i++){
QString dataName = (in.readLine());
QVariant itemData(dataName);
item->setData(Qt::UserRole + i, itemData);
//cout << "Item data " << i << ": " << item->data(Qt::UserRole + i).toString().toStdString() << endl;
}
item->setText(itemName);
listWidget->insertItem(inNum,item);
inNum++;
in.readLine();
//cout << "ITEM READS: " << itemName.toStdString() << endl;

}
}
file.close();


void ListWidgetDialog::listWidgetItemClicked(QListWidge tItem *item)
{
selectedItem = item->text();
row = listWidget->currentRow();
for(int i = 0; i<7; i++){
invisWidget[i]->setCurrentRow(row);
value[i] = invisWidget[i]->currentItem()->text().toInt();
}
for(int i = 0; i < 24 ; i++){
food[i] = textEdit[i]->find(selectedItem);
QTextCursor c(textEdit[i]->textCursor());
c.movePosition(QTextCursor::Start);
textEdit[i]->setTextCursor(c);
}
cout << "ITEM NAME: " << listWidget->currentItem()->text().toStdString() << endl;
for(int i = 0; i < 7; i++){
cout << listWidget->item(row)->data(Qt::UserRole + i).toString().toStdString() << endl;
}
}


Any suggestions would be greatly appreciated

Added after 9 minutes:

Okay..sorry guys apparently I just had to remove the invis widget and it works im still not sure exactly why that was preventing it from loading. maybe its like santosh said having multiple listwidgets is a bad idea (i was going to remove but didnt get around to it)