6
votes

The QListWidgetItem contains 2 data: icon and text. And I want to store another QString in it. How can I do? Here is my test code.The ListWidget displays nothing after I call addItem.

And how can I know which item is clicked? The SLOT function is "void on_listWidget_itemClicked(QListWidgetItem* item)". Obviously the parameter item is the parent class: QListWidgetItem, NOT the subclass: ListWidgetItem

ListWidgetItem::ListWidgetItem(const QIcon &icon, const QString &text,QString &ip, QListWidget *parent, int type)
{
    myip = ip;
    QListWidgetItem::QListWidgetItem(icon,text,parent,type);
}

ListWidgetItem::~ListWidgetItem()
{

}

QVariant ListWidgetItem::data(int role) const
{
    if (role==IPROLE)
    {
        return myip;
    }
    return QListWidgetItem::data(role);
}

void ListWidgetItem::setData(int role, const QVariant &value)
{
    if (role==IPROLE)
    {
        myip = value.toString();
    }
    QListWidgetItem::setData(role,value);
}
2

2 Answers

11
votes

QListWidgetItem has member functions

void QListWidgetItem::setData ( int role, const QVariant & value )

and

QVariant QListWidgetItem::data ( int role ) const

for storing arbitrary data (including QString). Set role = Qt::UserRole (or any higher value).

7
votes

For moving up and down in the class hierarchy you can use casts, in this case dynamic_cast:

dynamic_cast<QListWidgetItem*>( your_item )

You can use this as your parameter for your signals and slots. This will tell the recieving function "Hey, this used to be a pointer on a QListWidgetItem, so treat it like that!"

And for displaying more information you should consider using QTableWidget instead. I think that would fit your requirement and you would not have to go that detour over "smuggling" information like you did ;-)

Edit:

As a response to your comment:

Have a look at QTableWidgetItem. You will see, that a QTableWidgetItem can have an icon too :-) So what you need do is, split your information into several QTableWidgetItems. You have an item for the icon, on for the text, and another one for another text and what you need.

Now every row is what you had before as one item in a ListWidget. Now as soon as the user clicks somewhere, you use the signal cellClicked( int row, int column ) and row tells you which row has been clicked. Now you have the row that has been clicked and can get the information you're looking for.

Lets say the user clicked the 4th row. Each row has columns. The first column contains the icon, the second column contains the name. And now the special thing: The third column contains the IP, but is hidden. You can do so, by using hideColumn( int column ).

Row 4: [ Column 0: Icon | Column 1: Name | Column 2: (hidden) IP ]

So everytime the user clicks a row, you just look up the IP in column number 2.

Of course you can add as much cells as you want... One containing the string with the name, another one with a description... And let's just say, the last column is your hidden column with the IP.

You can also make the grid invisible by using setShowGrid( false ). Now it looks like a normal display of information, where every row is one item.

:-)

Edit 2:

To show you what I mean I implemented a small example. See the code below.

m_table_widget = new QTableWidget( 4, 4, this );

QTableWidgetItem* my_item_0 = new QTableWidgetItem( "icon 1" );
QTableWidgetItem* my_item_1 = new QTableWidgetItem( "server 1" );
QTableWidgetItem* my_item_2 = new QTableWidgetItem( "this is server 1" );
QTableWidgetItem* my_item_3 = new QTableWidgetItem( "192.0.0.1" );

QTableWidgetItem* my_item_4 = new QTableWidgetItem( "icon 2" );
QTableWidgetItem* my_item_5 = new QTableWidgetItem( "server 2" );
QTableWidgetItem* my_item_6 = new QTableWidgetItem( "this is server 2" );
QTableWidgetItem* my_item_7 = new QTableWidgetItem( "192.0.0.2" );

m_table_widget->setItem( 0, 0, my_item_0 );
m_table_widget->setItem( 0, 1, my_item_1 );
m_table_widget->setItem( 0, 2, my_item_2 );
m_table_widget->setItem( 0, 3, my_item_3 );

m_table_widget->setItem( 1, 0, my_item_4 );
m_table_widget->setItem( 1, 1, my_item_5 );
m_table_widget->setItem( 1, 2, my_item_6 );
m_table_widget->setItem( 1, 3, my_item_7 );

m_table_widget->hideColumn( 3 );
m_table_widget->setShowGrid( false );
m_table_widget->setSelectionBehavior( QAbstractItemView::SelectRows );
m_table_widget->verticalHeader()->hide();

QStringList list;
list << "Icon" << "Name" << "Description" << "IP";
m_table_widget->setHorizontalHeaderLabels( list );

connect( m_table_widget, SIGNAL(cellClicked(int,int)), this, SLOT(on_cell_clicked(int,int)) );

Now we have a table without grid with horizontal headers (which you dont need of course). When clicking on a row, the whole row is selected and the following slot is called:

void main_window::on_cell_clicked( int row, int column )
{
    QString ip = m_table_widget->item( row, 3 )->text();
    QMessageBox message( QMessageBox::Information, "Server Info", QString( "This is row %1 and the IP is: %2" ).arg( row ).arg( ip ) );

    message.exec();
}

This is just a simple example I quickly wrote... There are better ways of doing this of course, but maybe it helps to solve your problem.

Example implementation in sandbox app