PDA

View Full Version : Add custom object to QListWidget



robzanab
17th November 2015, 17:05
Dear forum

I can add to my QListWidget label, button,radiobutton and other, and all is working.

All items appear in vertical....1 for every line....and all work ok.
Also a scrollbar compare when the number of items occupy more space than the list.

Problem start when i want for example, put in 1 line ,2 buttom (or more) and not only 1.

So, I just try to insert only 2 button in horizontal, using the class QHBoxLayout ,then
create 2 button, and put this 2 button inside,like in next code:



QHBoxLayout *HLay= new QHBoxLayout();

QPushButton *b1 = new QPushButton("B1");
QPushButton *b2 = new QPushButton("B2");

HLay->addWidget(b1);
HLay->addWidget(b2);

and now, i would like to insert this HLay in the QListWidget. So, create
the List:


QListWidget *List= new QListWidget(window);

QListWidgetItem *ListItem=new QListWidgetItem();

List->addItem(ListItem);
List->setItemWidget(ListItem,HLay); //!!!!!!!!ERROR

Last line of code is not correct because setItemWidget () accept Qwidget type
and so not the HLay.

Some help.

Thanks for your time.

Roberto

d_stranz
17th November 2015, 17:51
You will probably have to create a separate QWidget instance, insert your layout and buttons into that as children, and then insert *that* QWidget into your list widget.



QHBoxLayout *HLay= new QHBoxLayout();

QPushButton *b1 = new QPushButton("B1");
QPushButton *b2 = new QPushButton("B2");

HLay->addWidget(b1);
HLay->addWidget(b2);

QWidget * twoButtonWidget = new QWidget();
twoButtonWidget->setLayout( HLay );

QListWidget *List= new QListWidget(window);

QListWidgetItem *ListItem=new QListWidgetItem();

List->addItem(ListItem);
List->setItemWidget(ListItem, twoButtonWidget );


If you plan to do this for every item in the list widget, then it would make sense to derive a custom class from QWidget that contains the layout and buttons and create instances of that to insert instead.

Please use CODE tags when posting source code. When writing a post, click "Go Advanced" and click the "#" tool button to insert the code tags. Put your code between those tags.

robzanab
17th November 2015, 18:33
Thanks for reply

what i get is the Qlistwidget visible but empty...no button visible inside.

If i add the instruction:

twoButtonWidget->setFixedSize(200,200);

then i can see the 2 button,but in the center of the list... Like if the layout rules canged.

If i add the second couple of buttons, then they overlap.

Do i have to change the style?

Thanks

d_stranz
18th November 2015, 01:33
Try adding a horizontal stretch to the right side of the horizontal layout. QBoxLayout::addStretch().

You should understand that when you add a widget to a list item it replaces the text in the item and is not interactive (i.e. clicking the button won't do anything). You probably want to look at using a QItemDelegate instead.

robzanab
18th November 2015, 12:43
Try adding a horizontal stretch to the right side of the horizontal layout. QBoxLayout::addStretch().

You should understand that when you add a widget to a list item it replaces the text in the item and is not interactive (i.e. clicking the button won't do anything). You probably want to look at using a QItemDelegate instead.



Thanks Mr Stranz.

I will chk delegate...Now i noted that if i add a single column of button (1 button over the other ), then they react to the click
If i add a couple orizontal, and replicate in vertical, only the last 2 added reacr to the click.

Thanks

robzanab
24th November 2015, 19:35
Hello Mr Stranz

I used delegate for paint a simple rectangle in a listview..this is the more simple example i want do,whitout
event or other more complex thinks.

What i did is to redifine the paint() function like in next code:
I can see the list appear, but not the rectangle,and the paint() event is never called.

This are the more important parts of my code:




//-----------in Customdelegate .h-------------------


class Customdelegate:public QItemDelegate
{

Q_OBJECT


public:

Customdelegate(QObject *parent = 0);

virtual void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;


};


//--------------in Customdelegate.cpp----------------


Customdelegate::Customdelegate(QObject *parent):QItemDelegate(parent)
{

objState=QStyle::State_Enabled;
}


void Customdelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const

{

QPen Penn;
Penn.setWidth(5);
Penn.setColor(Qt::red);


QRect Rect;
Rect.setRect(10,10,30,20);


painter->setPen(Penn);
painter->drawRect(Rect);

}



//-----------in my main.cpp------------


QWidget *window = new QWidget;
window->setWindowTitle("Ciao");

QListView *ListW= new QListView(window);


Customdelegate *ItemDel=new Customdelegate(ListW); //------------->my class

ListW->setItemDelegate(ItemDel);

window->show();






Thanks for your help

Roberto

d_stranz
26th November 2015, 01:57
From the docs for QItemDelegate::paint():

When reimplementing this function in a subclass, you should update the area held by the option's rect variable, using the option's state variable to determine the state of the item to be displayed, and adjust the way it is painted accordingly.

So try setting your QRect to option.rect instead of (10, 10 , 30, 20).

Not quite sure what you're trying to do with this line:


objState=QStyle::State_Enabled;

robzanab
26th November 2015, 13:23
Thanks Mr stranz

yes..now i design the items using a relative position, and im able to introduce 2 line of text + design
what i want around them....It very intresting to design what i want.

The way i introduce text is the more general way, using model :




QListView *ListW= new QListView(window);

Customdelegate *ItemDel=new Customdelegate(ListW);//connect delegate to view
QStandardItemModel *Mod= new QStandardItemModel();//connect model to view


ListW->setItemDelegate(ItemDel);
ListW->setModel(Mod);



//Create and Add item1 to Mod

QStandardItem *Item1= new QStandardItem();

Item1->setData("ciao1",Qt::DisplayRole);

Mod->appendRow(Item1);


//Create and Add item2 to Mod


QStandardItem *Item2= new QStandardItem();

Item2->setData("ciao2",Qt::DisplayRole);

Mod->appendRow(Item2);




and in the delegate paint(), i get them using index & role




QString headerText = qvariant_cast<QString>(index.data(Qt::DisplayRole));
.....
......



and all what i aspect is working.....2 label in 2 line + a big rectangle around....Beautiful.

My next question is:I want add button (for now to be simple, we dont speak about signal&slot)

My idea was to add buttons to -Mod-, create a custom- role-,and identify button in paint() via my role.
But i cant introduce any button in model.

Next idea is to design button in the paint(); but this means also that in future i need to connect signal&slot
at every paint..a lot of computation.

What is your suggestion ?

Thanks

Roberto

d_stranz
27th November 2015, 21:12
but this means also that in future i need to connect signal&slot at every paint..a lot of computation.

No, no, no, don't ever do that. Paint is for painting, nothing else.

And you do not want to put anything like a button in the *model*. The model is independent of any place it is displayed. That's the whole purpose of the Model-View architecture, to separate those two things.

In your delegate, you can use QStylePainter to draw the image of a pushbutton into the delegate's QRect (or part of it). You can also reimplement QAbstractItemDelegate::editorEvent() and watch for mouse events in the rect occupied by your pushbutton image. You could use those to simulate a click on your pushbutton, and emit a custom "clicked" signal that contains the model index (sent into editorEvent()) as a parameter. That lets you handle the signal in your own slot, and you'll have the index of the list widget element that triggered it.

robzanab
2nd December 2015, 14:59
Thanks Mr Stranz....

editorEvent work good...If I press mouse on any text line i visualiza (2 line ),then i get the event and im able to understand what of the 2 i pressed.
In particolar, the first line is easy to click, the second line no so precise.


What I used for draw text is painter->drawtext(rect, text) , and rect is bad created...I have no control of it..

..This is part of code ,inside paint() event:






......
QRect headerRect=option.rect ; //<--------

headerRect.setLeft(40);


headerRect.setTop(headerRect.top()+150);
headerRect.setBottom(headerRect.top()+130);

....
painter->drawText( headerRect ,headerText);



I cant manage this headerrect....I want that next headerrect start +150 compared to previous, hight 130.
But i cant increase the distance bettwen 2 text....

So question are:

-why create a rectangle using option.rect().....Who is filling option object ?
-why distance dont work.

Slowly slowly all seems more clear...thanks
Roberto

robzanab
14th December 2015, 18:09
Hello

I dont get any reply.

Simplified question is:

-Why inside the paint event, we must create a rectangle using - option.rect -

Thanks

Roberto

Hello

I dont get any reply.

Simplified question is:

-Why inside the paint event, we must create a rectangle using - option.rect -

Thanks

Roberto