QListView максимальное количество элементов в поле зрения

Мне нужно рассчитать максимальное количество элементов в текущем представлении QListView. Я написал такой код:

void MyListView::resizeEvent(QResizeEvent *event)
{
    QListView::resizeEvent(event);

    QFontMetrics fm (this->font());
    int fontHeight = fm.lineSpacing();

    QRect cr = contentsRect();
    int windowHeight = cr.bottom() - cr.top();

    int maxItemsCount = windowHeight / fontHeight;
    qDebug()<<"max items in view: "<< maxItemsCount;

}

но рассчитанное максимальное количество элементов неверно. Например. в случае моей высоты окна и высоты шрифта я получаю 32 максимальных элемента в поле зрения, тогда как на самом деле текущий вид имеет 28 элементов. Может, кто-то что-то подскажет, как правильно рассчитать?


person krusty    schedule 01.06.2020    source источник
comment
Возможно, на это влияет интервал / отступ между элементами, не так ли? Я не знаю, насколько хорошо вы можете решить эту проблему (без прямой поддержки со стороны набора инструментов), но похоже, что это может потребовать самоанализа темы и, следовательно, в лучшем случае будет сложно.   -  person underscore_d    schedule 01.06.2020
comment
да, но я проверил интервал (), и он 0 не уверен, как получить значение заполнения   -  person krusty    schedule 01.06.2020
comment
Просто идея ... Вы можете попробовать что-нибудь еще: QListView :: indexAt () (унаследовано от QAbstractView). Применяя его к левому верхнему и левому нижнему углу, вы должны получить два индекса, по которым вы можете получить разницу. (Вероятно, есть некоторые крайние случаи, о которых вам следует позаботиться, например, если текущее представление не полностью заполнено.)   -  person Scheff's Cat    schedule 03.06.2020


Ответы (1)


Моя идея - использовать QListView :: indexAt () (унаследованный от QAbstractView), чтобы получить индекс строки для

  1. верхний левый угол
  2. нижний левый угол

окна просмотра списка и определение количества видимых элементов по их разнице.

Чтобы проверить это, я сделал MCVE testQListViewNumVisibleItems.cc:

// Qt header:
#include <QtWidgets>

class ListWidget: public QListWidget {

  public:
    ListWidget(QWidget *pQParent = nullptr): QListWidget(pQParent) { }
    virtual ~ListWidget() = default;
    ListWidget(const ListWidget&) = delete;
    ListWidget& operator=(const ListWidget&) = delete;

    int getNumVisibleItems() const
    {
      const QSize size = viewport()->size();
      const QModelIndex qMIdx0 = indexAt(QPoint(0, 0));
      const QModelIndex qMIdx1 = indexAt(QPoint(0, size.height() - 1));
      //qDebug() << "qMIdx0:" << qMIdx0 << "qMIdx1:" << qMIdx1;
      return qMIdx0.isValid()
        ? (qMIdx1.isValid() ? qMIdx1.row() : count()) - qMIdx0.row()
        : 0;
    }
};

const int MaxItems = 20;

// main application
int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // setup GUI
  ListWidget qLst;
  qLst.resize(200, 200);
  qLst.show();
  // timer to populate list view
  using namespace std::chrono_literals;
  QTimer qTimer;
  qTimer.setInterval(1000ms);
  // install signal handlers
  int n = 0;
  QObject::connect(&qTimer, &QTimer::timeout,
    [&]() {
      qLst.addItem(QString("item %0").arg(++n));
      qDebug() << "Visible items:" << qLst.getNumVisibleItems();
      if (n >= MaxItems) qTimer.stop();
    });
  // runtime loop
  qTimer.start();
  return app.exec();
}

и CMakeLists.txt:

project(QListViewNumVisibleItems)

cmake_minimum_required(VERSION 3.10.0)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Qt5Widgets CONFIG REQUIRED)

include_directories("${CMAKE_SOURCE_DIR}")

add_executable(testQListViewNumVisibleItems testQListViewNumVisibleItems.cc)

target_link_libraries(testQListViewNumVisibleItems Qt5::Widgets)

построен и протестирован в VS2017 на Windows 10:

снимок testQListViewNumVisibleItems.exe (анимированный)


Реализовав то, что пришло мне в голову, я немного погуглил, чтобы, возможно, увидеть другие подходы. (Признаюсь, я должен был это сделать раньше.)

Таким образом, я обнаружил следующий возможный дубликат:

ИТОГО: Простой способ получить все видимые элементы в QListView

Принятый ответ не содержит ничего, кроме подсказки для indexAt и ссылки на статью Qt-FAQ:

Как я могу получить все видимые элементы в моем QListView?

Чтобы получить видимые элементы в QListView, http://doc.qt.io/qt-5/qlistview.html, затем вы можете перебирать их, используя indexAt () http://doc.qt.io/qt-5/qlistview.html#indexAt. Вы можете получить первый видимый элемент с помощью indexAt (QPoint (0, 0)), затем, чтобы получить индекс в следующей позиции, используйте visualRect () http://doc.qt.io/qt-5/qlistview.html#visualRect, чтобы узнать, какой ваш следующий вызов itemAt () должно быть. Эта позиция была бы:

visualRect.y() + visualRect.height() + 1 effectively.

См. Иллюстрацию в следующем примере:

#include <QtGui>
QList <QModelIndex>myList;

class ListView : public QListView
{
  Q_OBJECT
public:
  ListView()
  {
    QStringListModel *myModel = new QStringListModel(this);
    QStringList list;
    list << "a" << "b" <<"c" <<"d" <<"e" <<"f" <<"g" <<"h" <<"i" <<"j" <<"k";
    myModel->setStringList(list);
    setModel(myModel);
    QTimer::singleShot(3000, this, SLOT(test1()));
  }
  public slots:
    void test1()
    {

      QModelIndex firstIndex = indexAt(QPoint(0, 0));
      if (firstIndex.isValid()) {
        myList << firstIndex;
      } while (viewport()->rect().contains(QPoint(0, visualRect(firstIndex).y() + visualRect(firstIndex).height() + 1 ))) {
        firstIndex = indexAt(QPoint(0, visualRect(firstIndex).y() + visualRect(firstIndex).height() + 1 ));
        myList << firstIndex;
      }
      qDebug() << myList.count() << "are visible";
    }
};

#include "main.moc"

int main(int argc, char** argv)
{
  QApplication app(argc, argv);
  ListView window;
  window.resize(100, 50);
  window.show();
  return app.exec();

}
person Scheff's Cat    schedule 03.06.2020
comment
спасибо, но мне нужно знать максимальное количество элементов в представлении, прежде чем загружать какие-либо элементы. он должен быть основан на событии resizeEvent виджета - person krusty; 10.06.2020