QT Custom Layout Malformed Layout

About QT's custom layout

The customized layout shape is as follows

Insert picture description here

Introduction

  I used to find it difficult to customize the layout, but I found it very simple after writing it by myself. It is to subclass Layout. Realize a few virtual functions, and then calculate the position of each child item in the setGeometry() function to achieve the layout effect.

achieve

   Realize your own layout by inheriting the QLayout class. The QT framework implements these layout classes yourself and can be used: QBoxLayout, QGridLayout, QFormLayout, QStackedLayout. And BorderLayout and flowLayout (document detail description)

  If we subclass QLayout, we must implement addItem(), sizeHint(), itemAt(), setGeometry(), takeAt() these functions. The mininumSize() function should also be implemented to ensure that the minimum size of the layout is not 0. The function to determine the layout is mainly setGeometry(), which calculates the position of each sub-Item to make it what you want.

code show as below:

border.h

#include <QLayout>
#include <QList>
#include <QRect>

class Flayout : public QLayout
{
public:
    enum direction{
        TOP = 0,
        BOTTOM,
        LEFT,
        RIGHT,
        CENTER
    };

    typedef struct fitem{
        fitem(QLayoutItem *item, direction direct):
            layout_item(item),
            dir(direct){}
        QLayoutItem *layout_item;
        direction dir;
    }Fitem;

    explicit Flayout(QWidget *parent = 0);
    ~Flayout();

    void addWidget(QWidget *, direction);
    void add(QLayoutItem *, direction);

protected:
    virtual void addItem(QLayoutItem *);
    void setGeometry(const QRect &);
    QSize sizeHint() const;
    QLayoutItem * itemAt(int) const;
    QLayoutItem *takeAt(int index);
    int count() const;
    QSize minimumSize() const;

private:
    QList<Fitem *>m_item_list;
};

border.cc

Flayout::Flayout(QWidget *parent):
    QLayout(parent)
{
    setSpacing(0);
}

Flayout::~Flayout()
{
    QLayoutItem *l;
    while ((l = takeAt(0)))
        delete l;
}

void Flayout::addItem(QLayoutItem * item)
{
    add(item, TOP);
}

void Flayout::setGeometry(const QRect & rect)
{
    int left_height = 0;
    int left_width = 0;
    QLayout::setGeometry(rect);

    for (int i = 0; i < m_item_list.size(); ++i)
    {
        Fitem *wrapper = m_item_list.at(i);
        QLayoutItem *item = wrapper->layout_item;
        direction direct = wrapper->dir;

        if (direct == LEFT)
        {
            item->setGeometry(QRect(rect.x(), rect.y(), rect.width() / 4, rect.height() / 4 * 3));

            left_height += item->geometry().height();
            left_width  += item->geometry().width();
        }
    }

    for (int i = 0; i < m_item_list.size(); ++i)
    {
        Fitem *wrapper = m_item_list.at(i);
        QLayoutItem *item = wrapper->layout_item;
        direction position = wrapper->dir;

        if (position == TOP)
        {
            item->setGeometry(QRect(rect.x() + left_width, rect.y(),
                                    rect.width() / 4 * 3, rect.height() / 4));
        }
        else if (position == BOTTOM)
        {
            item->setGeometry(QRect(rect.x(), left_height + rect.y(),
                                    rect.width() / 4 * 3, rect.height() / 4));
        }
        else if(position == RIGHT)
        {
            item->setGeometry(QRect(rect.x() + rect.width() -  left_width ,  rect.y() + rect.height() - left_height,
                                   rect.width() / 4, rect.height() / 4 * 3));
        }
        else if(position == CENTER)
        {
            item->setGeometry(QRect(rect.x() + rect.width() / 4,  rect.y() + rect.height() / 4,
                                   rect.width() / 2, rect.height() / 2));
        }
    }
}

QSize Flayout::sizeHint() const
{
    return QSize(300, 300);
}

QLayoutItem *Flayout::itemAt(int index) const
{
    Fitem *item = m_item_list.value(index);
    if (item)
    {
        return item->layout_item;
    }
    else
    {
        return 0;
    }
}

QLayoutItem *Flayout::takeAt(int index)
{
    if (index >= 0 && index < m_item_list.size()) {
        Fitem *layoutStruct = m_item_list.takeAt(index);
        return layoutStruct->layout_item;
    }
    return 0;
}

int Flayout::count() const
{
    return m_item_list.count();
}

QSize Flayout::minimumSize() const
{
    return QSize(30,30);
}

void Flayout::addWidget(QWidget * widget, direction dir)
{
    add(new QWidgetItem(widget), dir);
}

void Flayout::add(QLayoutItem * item, direction dir)
{
    m_item_list.append(new Fitem(item, dir));
}

Use:
widget.cc:

    Flayout *pLayout = new Flayout(this);
    pLayout->addWidget(createWidget("Black"), Flayout::CENTER);
    pLayout->addWidget(createWidget("White"), Flayout::TOP);
    pLayout->addWidget(createWidget("Red"), Flayout::BOTTOM);
    pLayout->addWidget(createWidget("Green"), Flayout::LEFT);
    pLayout->addWidget(createWidget("Yellow") , Flayout::RIGHT);
    setLayout(pLayout);

Guess you like

Origin blog.csdn.net/Mario_z/article/details/100238411