PDA

View Full Version : Circular wrapping of QListWidget items - how to?



slscripters
21st May 2010, 13:58
Hi,

Is a QListWidget capable of a somewhat circular wrapping of items? When selection is at the end of the list and down key is pressed selection will immediately be set to the first item, and vice versa?

I'm a Qt newbie and I can't find a function with this behavior (if there's any) in any Qt documentation :(. If there's none, can you please suggest some ideas? Thank you in advance! :)

JD2000
21st May 2010, 14:40
I think that the closest QT has to offer out of the box is QLinkedList

You can use the hasNext() and hasPrevious() to test if you have reached the end of the list
and first() or last() to traverse it accordingly.

slscripters
24th May 2010, 03:50
Hi,


I think that the closest QT has to offer out of the box is QLinkedList

I think QLinkedList is just a container and doesn't draw something on the screen? Or can this be embedded in the QListWidget? Please guide me on your idea.

One way I've thought about is to catch a signal that can be emitted when down/up key is pressed to change the current row of the QListWidget. However, when the current row is at the first/last item of the list, current row doesn't change anymore even if down/up key is pressed.

Please help.:confused:

aamer4yu
24th May 2010, 06:31
You can do 2 things - either install an event filter on the QListWidget or subclass it and override the keyPressEvent.
When you get a key press event for down arrow key, check the index of the current item, and if its last, set current item to first index.

You can also override QListView::moveCursor and call the base class moveCursor first, then check if its first or last, and then modify the index to return as you wish .

Hope you get the idea :)

slscripters
25th May 2010, 15:32
Hi,


subclass it and override the keyPressEvent

I've chose this method. My implementation iis somewhat like a hack but it makes sense though.

If somebody wants to know the idea of my implementation just infrom me and I'll give you the idea. The implementation is not as straightforward as you think.

Thanks again aamer4yu! ;)

aamer4yu
25th May 2010, 18:39
You can anyway post the solution... you never know who can benefit from it :)

slscripters
26th May 2010, 03:00
Yeah your'e right! It's a hacky solution but it makes sense. But here it is, ;)

in the overriden keyPressEvent function,



void CustomListWidget::keyPressEvent(QKeyEvent *event)
{
// feed this to base class as a default, we may also use this for simulating a key
QKeyEvent *finalEvent = event;

switch(finalEvent->key())
{
case Qt::Key_Down:
{
// if last item reached wrap to first
if(currentRow() == (count()-1))
{
// set row to -1 so that later on doing the normal behavior it will go to row 1 which is the first item
setCurrentRow(-1);
}
break;
}
case Qt::Key_Up:
{
// if first item is reached wrap to last
if(currentRow() == 0)
{
if(count() > 1)
{
// set the current row at the top of the last row
setCurrentRow(count() - 2);
// and simulate a Key_Down event, event->key() = Key_Down
finalEvent = new QKeyEvent(copy event's values, except for key())
}//else no need to wrap first item = last
}
break;
}
default:
break;
}

if(finalEvent)
{
// perform the normal behavior
QListWidget::keyPressEvent(finalEvent);
}
}



aamer4yu,

Does Qt automatically delete the event object ? In this case it is possible that the event object is not passed to the base class, will it still be deleted somewhere? Or do I need to explicitly delete this?

At first look, the event object may not be deleted if not passed to the base class. I hope what I'm doing is safe, I need to read more on Qt about this. Deleting the event object explicitly may even be worse. Please help. :confused:

aamer4yu
26th May 2010, 06:57
Why have u done extra work for key_up ??
you could have simply done as u did for key_down -
case Key_up :
if(currentRow==0)
setCurrentRow(count() -1 );

and if your conditions are not met, you can call QListWidget::keyPressEvent.
something like -

void CustomListWidget::keyPressEvent(QKeyEvent *event)
{
bool sendEventToBaseClass = true;
switch(event->key())
{
case Qt::Key_up :
if(condition)
{
sendEventToBaseClass = false;
.... // other jobs
}

break;
case Qt::Key_Down :
if(condition)
{
sendEventToBaseClass = false;
.... // other jobs
}
break;

}

if(sendEventToBaseClass)
QListWidget::keyPressEvent(event);
}

thats it.. no need to keep duplicate pointer...

slscripters
26th May 2010, 07:35
Hi,


Why have u done extra work for key_up ??

The base class's function may be setting variables or calling functions inside it to accomplish the default behavior. So I thought it would be safer to always call the base class function, anyway what I really need is just to change the current row. I've thought of creating a flag and checking if event is necessary to be passed to base class or not, like what you've done above.

I will try this and see if it works with my code. I'll go for this if this works since this is very simple solution.

With this solution, what shall we do then with the event object? Do we need to delete it explicitly after using it or not? In general, does Qt leave the deletion of the event objects to us or is it automatically deleted somewhere?:)