Simple way to get all visible items in the QListView
Asked Answered
N

5

5

I am trying to develop an image gallery application using Qt Framework. The application loads all the images from the selected folder and those images are displayed using QListView control. But now i want to reduce the memory consumption by loading only the images that are visible to user. Since there is no direct function to get all the visible items in the view, i am not able to achieve this.

Naara answered 22/3, 2012 at 7:48 Comment(0)
W
5

You can get the visible items of a list view using the indexAt function. For more details and an example you can check the following article:

http://qt-project.org/faq/answer/how_can_i_get_hold_of_all_of_the_visible_items_in_my_qlistview

Wildfire answered 22/3, 2012 at 8:2 Comment(0)
M
2

I found it! You have to connect the vertical scrollbar of the listwidget to a signal:

connect(ui->listWidget->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(launch_timer()));

Every time the user scrolls, the valuechanged(int) signal is being omitted! The thing is that you shouldn't run the code provided by webclectic in this question every time the value of the vertical scrollbar of the listwidget changes, because the program will be unresponsive with so much code to run in so little time.

So, you have to have a singleshot timer and point it to the function that webclectic posted above. When launch_timer() is called, you do something like this:

  if(timer->isActive()){
     timer->stop();
     timer->start(300);
   }
   else
      timer->start(300);

and the timeout() signal of timer will be connected to the slot webclectic talked about. This way, if the user scrolls quickly all the way down only the last items will be updated. Generally, it will be updated anything visible for more than 300 milliseconds!

Movable answered 19/8, 2012 at 8:44 Comment(0)
F
0

I think what you need is to implement your own model (take a look to the QAbstractListModel documentation) so that way you could decide when you have to load more images to show and maybe free some of the images that became non-visible.

Feuillant answered 19/8, 2012 at 7:56 Comment(0)
R
0

although this is not so simple in Qt 4 but it is always simple to copy below:

#include <private/qlistview_p.h>

class QListViewHelper : public QListView
{
    typedef QListView super;
    inline QListViewHelper() {} //not intended to be constructed
public:
    inline static QVector<QModelIndex> indexFromRect(const QListView *view,
                                                                 const QRect &rect)
    {
        const QListViewPrivate *d = static_cast<const QListViewPrivate *>(QObjectPrivate::get(view)); //to access "QListViewPrivate::intersectingSet(...)"
        const QListViewHelper *helper = static_cast<const QListViewHelper *>(view); //to access "QListView::horizontalOffset()"
        return d->intersectingSet(rect.translated(helper->horizontalOffset(), helper->verticalOffset()), false);
    }
    inline static QVector<QModelIndex> visibleItems(const QListView *view)
        { return indexFromRect(view, view->rect()); }

    inline static QModelIndex firstVisible(const QListView *view)
        { return visibleItems(view).value(0); }
    inline static QModelIndex lastVisible(const QListView *view) {
        const QVector<QModelIndex> &items = visibleItems(view);
        return items.value(items.count() - 1);
    }
};

void ourTest(const QListView *view) {
    QModelIndex &index = QListViewHelper::firstVisible(view);
    qDebug("QListViewHelper: first visible row is %d", index.row());

    index = QListViewHelper::lastVisible(view);
    qDebug("QListViewHelper: last visible row is %d", index.row());
}

usage: QModelIndex &index = QListViewHelper::firstVisible(listViewPointerHere)

note: since it does use Qt 4.8 private-headers it may no longer work in latter versions and will need some changes.

Recriminate answered 14/11, 2018 at 11:3 Comment(0)
C
0

You can keep track of all the elements that are drawn per paint event. I used a delegate and overloaded the paint event.

I also overloaded the paint event in the view. During this call, all the visible delegates will get a paint event.

If you just need to know if an item is visible, you can increment a frame count in view->paintEvent and set that number in the delegate item. The item is visible of the item matches the current frame number.

If you need a list of all visible items, clear the visible item list in view->paintEvent and add each item in the int the delegate->paintEvent to the visible items list.

Cornell answered 27/1, 2022 at 0:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.