简体   繁体   English

调整 QListView 的高度以适应内容

[英]Adjust the height of QListView to fit the content

I want the height of a QListView based on an QAbstractListModel to fit the contents, if the amount of the items is smaller a given number N. If there are more than N items, it should show only N items.我想要一个基于QAbstractListModelQListView的高度来适应内容,如果项目的数量小于给定的数字 N。如果有超过 N 个项目,它应该只显示 N 个项目。 I read a lot of curious tips in the web, but most of them look like hacks.我在网上阅读了很多奇怪的技巧,但其中大多数看起来像黑客。 I guess this has something to do with sizeHint() but in the model view approach there is no ItemWidget in which I could override the sizeHint() .我想这与sizeHint()但在模型视图方法中,没有 ItemWidget 可以覆盖sizeHint() What is the correct way to achieve this behaviour?实现这种行为的正确方法是什么?

Further, how does this correlate to the size policy of the parent app?此外,这与父应用程序的大小策略有何关联? This is a second constraint: The contents should not try to use the space they have in the parent widget, but the parent widget should resize to fit the QListView .这是第二个约束:内容不应尝试使用它们在父小部件中的空间,但父小部件应调整大小以适合QListView

This is not a duplicate to this question , since I can't use QCompleter .这不是这个问题的重复,因为我不能使用QCompleter

sizeHint() has to be overridden in the QListView (respectively your subclass of it). sizeHint() 必须在 QListView (分别是它的子类)中被覆盖。 The mentioned special behaviour can be implemented there.提到的特殊行为可以在那里实现。 eg like this:例如像这样:

QSize ProposalListView::sizeHint() const
{
    if (model()->rowCount() == 0) return QSize(width(), 0);
    int nToShow = _nItemsToShow < model()->rowCount() ? _nItemsToShow : model()->rowCount();
    return QSize(width(), nToShow*sizeHintForRow(0));
}

This requires the size hint of the item delegate to be reasonable.这就要求项目委托的大小提示要合理。 In my case:就我而言:

inline QSize sizeHint ( const QStyleOptionViewItem&, const QModelIndex& ) const  override { return QSize(200, 48); }

Now I just have to call updateGeometry() after changing the model.现在我只需要在更改模型后调用 updateGeometry() 即可。

For those who use ListView in QML with QtQuick Controls.对于那些在 QML 中使用 ListView 和 QtQuick 控件的人。 I made the content fit with property anchors.bottomMargin.我使内容适合属性 anchors.bottomMargin。

anchors.bottomMargin: 20

There is no good way to do this.没有好的方法可以做到这一点。 I use the following code.我使用以下代码。

Header:标题:

class List_view_auto_height : public QObject {
  Q_OBJECT
public:
  explicit List_view_auto_height(QListView * target_list);
  void set_max_auto_height(int value);
  void set_min_height(int value);

private:
  QListView* list;
  QTimer timer;
  int _min_height;
  int _max_height;

  bool eventFilter(QObject* object, QEvent* event);

private slots:
  void update_height();
};

Source:来源:

List_view_auto_height::List_view_auto_height(QListView *target_list) :
  QObject(target_list)
, list(target_list)
{
  _min_height = 0;
  _max_height = 250;
  connect(list->model(), &QAbstractItemModel::rowsInserted,
          this, &List_view_auto_height::update_height);
  connect(list->model(), &QAbstractItemModel::rowsRemoved,
          this, &List_view_auto_height::update_height);
  connect(list->model(), &QAbstractItemModel::layoutChanged,
          this, &List_view_auto_height::update_height);
  list->installEventFilter(this);
  update_height();
  connect(&timer, &QTimer::timeout, this, &List_view_auto_height::update_height);
  timer.start(500);
}

void List_view_auto_height::set_max_auto_height(int value) {
  _max_height = value;
  update_height();

}

void List_view_auto_height::set_min_height(int value) {
  _min_height = value;
  update_height();
}

bool List_view_auto_height::eventFilter(QObject *object, QEvent *event) {
  if (event->type() == QEvent::Show) {
    update_height();
  }
  return false;
}

void List_view_auto_height::update_height() {
  if (!list->isVisible()) { return; }
  int height = 0;
  if (list->model()->rowCount() > 0) {
    height = list->visualRect(list->model()->index(list->model()->rowCount() - 1, 0)).bottom() + 1;
    height -= list->visualRect(list->model()->index(0, 0)).top();
  }
  if (list->horizontalScrollBar()->isVisible()) {
    height += list->horizontalScrollBar()->height();
  }
  bool scrollbar_enabled = false;
  if (_max_height != 0 && height > _max_height) {
    height = _max_height;
    scrollbar_enabled = true;
  }
  if (height < _min_height) {
    height = _min_height;
  }
  list->setFixedHeight(height + 6);
}

Usage:用法:

new List_widget_auto_height(list);

It's full of hacks and can work incorrectly in some cases.它充满了黑客,在某些情况下可能无法正常工作。 Feel free to improve it.随意改进它。

It sets height using setFixedHeight .它使用setFixedHeight设置高度。 This should provide correct behavior for parent widget's size hint.这应该为父小部件的大小提示提供正确的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM