自定义卡片布局CardLayout,这个布局是官方用来介绍怎么实现一个自定义布局的示例。
自定义布局第一步就是要继承QLayout 然而QLayout却是个抽象类,有几个纯虚函数必须要是实现下:
virtual void addItem(QLayoutItem *item) = 0 //向布局中添加控件 virtual int count() const = 0 //布局中控件数量 virtual QLayoutItem *itemAt(int index) const = 0 //根据下标获取控件 virtual QLayoutItem *takeAt(int index) = 0 //根据下标移除控件 virtual QSize sizeHint() const = 0 //默认大小这些还都只是对布局中子控件管理的功能,真正处理控件布局位置的函数却是:
virtual void setGeometry(const QRect&) = 0CardLayout 实现
接下来进入主题,看下这些函数都是怎么实现的,类定义:
class CardLayout : public QLayout { Q_OBJECT public: CardLayout(QWidget *parent = nullptr); ~CardLayout(); void addItem(QLayoutItem *item) override; int count() const override; QLayoutItem *itemAt(int) const override; QLayoutItem *takeAt(int) override; QSize sizeHint() const override; void setGeometry(const QRect &rect) override; private: QList<QLayoutItem*> list; };对于子控件的管理用的是QList<QLayoutItem*>,简单直接。
成员函数实现:
CardLayout::CardLayout(QWidget *parent): QLayout(parent) {} CardLayout::~CardLayout() { QLayoutItem *item; while ((item = takeAt(0))) delete item; } void CardLayout::addItem(QLayoutItem *item) { list.append(item); } int CardLayout::count() const { return list.count(); } QLayoutItem *CardLayout::itemAt(int idx) const { return list.value(idx); } QLayoutItem *CardLayout::takeAt(int idx) { return idx >= 0 && idx < list.size() ? list.takeAt(idx) : 0; } QSize CardLayout::sizeHint() const { return QSize(0,0); } void CardLayout::setGeometry(const QRect &rect) { QLayout::setGeometry(rect); if(list.size() == 0) return; int w = rect.width() - (list.count() - 1)*spacing(); int h = rect.height() - (list.count() - 1)* spacing(); int i = 0; while (i < list.size()) { QLayoutItem *o = list.at(i); QRect geom(rect.x() + i*spacing(), rect.y() + i*spacing(), w, h); o->setGeometry(geom); ++i; } }sizeHint这里是直接给0,暂且也不需要它发挥作用。
看过setGeometry的实现后,这个自定义的卡片布局的就很清晰了,每个子控件就是向右下角依次做个偏移显示而已。
调用示例
CardLayout * lay = new CardLayout; for(int i=0; i<5; i++) { lay->addItem( new QWidgetItem(new QPushButton(QString::number(i+1))) ); } this->setLayout(lay);弄了5个按钮来试试这新实现的卡片布局。看下效果: