C++/Qt/QLayout

Материал из C\C++ эксперт
Перейти к: навигация, поиск

extends QLayout to create border layout

<source lang="cpp"> /****************************************************************************

    • Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    • All rights reserved.
    • Contact: Nokia Corporation (qt-info@nokia.com)
    • This file is part of the examples of the Qt Toolkit.
    • $QT_BEGIN_LICENSE:LGPL$
    • Commercial Usage
    • Licensees holding valid Qt Commercial licenses may use this file in
    • accordance with the Qt Commercial License Agreement provided with the
    • Software or, alternatively, in accordance with the terms contained in
    • a written agreement between you and Nokia.
    • GNU Lesser General Public License Usage
    • Alternatively, this file may be used under the terms of the GNU Lesser
    • General Public License version 2.1 as published by the Free Software
    • Foundation and appearing in the file LICENSE.LGPL included in the
    • packaging of this file. Please review the following information to
    • ensure the GNU Lesser General Public License version 2.1 requirements
    • will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    • In addition, as a special exception, Nokia gives you certain additional
    • rights. These rights are described in the Nokia Qt LGPL Exception
    • version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    • GNU General Public License Usage
    • Alternatively, this file may be used under the terms of the GNU
    • General Public License version 3.0 as published by the Free Software
    • Foundation and appearing in the file LICENSE.GPL included in the
    • packaging of this file. Please review the following information to
    • ensure the GNU General Public License version 3.0 requirements will be
    • met: http://www.gnu.org/copyleft/gpl.html.
    • If you have questions regarding the use of this file, please contact
    • Nokia at qt-info@nokia.com.
    • $QT_END_LICENSE$
                                                                                                                                                        • /
  1. ifndef BORDERLAYOUT_H
  2. define BORDERLAYOUT_H
  3. include <QLayout>
  4. include <QRect>
  5. include <QWidgetItem>

class BorderLayout : public QLayout { public:

   enum Position { West, North, South, East, Center };
   BorderLayout(QWidget *parent, int margin = 0, int spacing = -1);
   BorderLayout(int spacing = -1);
   ~BorderLayout();
   void addItem(QLayoutItem *item);
   void addWidget(QWidget *widget, Position position);
   Qt::Orientations expandingDirections() const;
   bool hasHeightForWidth() const;
   int count() const;
   QLayoutItem *itemAt(int index) const;
   QSize minimumSize() const;
   void setGeometry(const QRect &rect);
   QSize sizeHint() const;
   QLayoutItem *takeAt(int index);
   void add(QLayoutItem *item, Position position);

private:

   struct ItemWrapper
   {
 ItemWrapper(QLayoutItem *i, Position p) {
     item = i;
     position = p;
 }
 QLayoutItem *item;
 Position position;
   };
   enum SizeType { MinimumSize, SizeHint };
   QSize calculateSize(SizeType sizeType) const;
   QList<ItemWrapper *> list;

};

  1. endif


  1. include <QtGui>
  2. include "borderlayout.h"

BorderLayout::BorderLayout(QWidget *parent, int margin, int spacing)

   : QLayout(parent)

{

   setMargin(margin);
   setSpacing(spacing);

} BorderLayout::BorderLayout(int spacing) {

   setSpacing(spacing);

}

BorderLayout::~BorderLayout() {

   QLayoutItem *l;
   while ((l = takeAt(0)))
       delete l;

} void BorderLayout::addItem(QLayoutItem *item) {

   add(item, West);

} void BorderLayout::addWidget(QWidget *widget, Position position) {

   add(new QWidgetItem(widget), position);

} Qt::Orientations BorderLayout::expandingDirections() const {

   return Qt::Horizontal | Qt::Vertical;

} bool BorderLayout::hasHeightForWidth() const {

   return false;

} int BorderLayout::count() const {

   return list.size();

} QLayoutItem *BorderLayout::itemAt(int index) const {

   ItemWrapper *wrapper = list.value(index);
   if (wrapper)
       return wrapper->item;
   else
       return 0;

} QSize BorderLayout::minimumSize() const {

   return calculateSize(MinimumSize);

} void BorderLayout::setGeometry(const QRect &rect) {

   ItemWrapper *center = 0;
   int eastWidth = 0;
   int westWidth = 0;
   int northHeight = 0;
   int southHeight = 0;
   int centerHeight = 0;
   int i;
   QLayout::setGeometry(rect);
   for (i = 0; i < list.size(); ++i) {
       ItemWrapper *wrapper = list.at(i);
       QLayoutItem *item = wrapper->item;
       Position position = wrapper->position;
       if (position == North) {
           item->setGeometry(QRect(rect.x(), northHeight, rect.width(),
                                   item->sizeHint().height()));
           northHeight += item->geometry().height() + spacing();
       } else if (position == South) {
           item->setGeometry(QRect(item->geometry().x(),
                                   item->geometry().y(), rect.width(),
                                   item->sizeHint().height()));
           southHeight += item->geometry().height() + spacing();
           item->setGeometry(QRect(rect.x(),
                             rect.y() + rect.height() - southHeight + spacing(),
                             item->geometry().width(),
                             item->geometry().height()));
       } else if (position == Center) {
           center = wrapper;
       }
   }
   centerHeight = rect.height() - northHeight - southHeight;
   for (i = 0; i < list.size(); ++i) {
       ItemWrapper *wrapper = list.at(i);
       QLayoutItem *item = wrapper->item;
       Position position = wrapper->position;
       if (position == West) {
           item->setGeometry(QRect(rect.x() + westWidth, northHeight,
                                   item->sizeHint().width(), centerHeight));
           westWidth += item->geometry().width() + spacing();
       } else if (position == East) {
           item->setGeometry(QRect(item->geometry().x(), item->geometry().y(),
                                   item->sizeHint().width(), centerHeight));
           eastWidth += item->geometry().width() + spacing();
           item->setGeometry(QRect(
                             rect.x() + rect.width() - eastWidth + spacing(),
                             northHeight, item->geometry().width(),
                             item->geometry().height()));
       }
   }
   if (center)
       center->item->setGeometry(QRect(westWidth, northHeight,
                                       rect.width() - eastWidth - westWidth,
                                       centerHeight));

} QSize BorderLayout::sizeHint() const {

   return calculateSize(SizeHint);

} QLayoutItem *BorderLayout::takeAt(int index) {

   if (index >= 0 && index < list.size()) {
       ItemWrapper *layoutStruct = list.takeAt(index);
       return layoutStruct->item;
   }
   return 0;

} void BorderLayout::add(QLayoutItem *item, Position position) {

   list.append(new ItemWrapper(item, position));

} QSize BorderLayout::calculateSize(SizeType sizeType) const {

   QSize totalSize;
   for (int i = 0; i < list.size(); ++i) {
       ItemWrapper *wrapper = list.at(i);
       Position position = wrapper->position;
       QSize itemSize;
       if (sizeType == MinimumSize)
           itemSize = wrapper->item->minimumSize();
       else // (sizeType == SizeHint)
           itemSize = wrapper->item->sizeHint();
       if (position == North || position == South || position == Center)
           totalSize.rheight() += itemSize.height();
       if (position == West || position == East || position == Center)
           totalSize.rwidth() += itemSize.width();
   }
   return totalSize;

}


  1. ifndef WINDOW_H
  2. define WINDOW_H
  3. include <QWidget>

QT_BEGIN_NAMESPACE class QLabel; QT_END_NAMESPACE class Window : public QWidget {

   Q_OBJECT

public:

   Window();

private:

   QLabel *createLabel(const QString &text);

};

  1. endif


  1. include <QtGui>
  2. include "borderlayout.h"
  3. include "window.h"

Window::Window() {

   QTextBrowser *centralWidget = new QTextBrowser;
   centralWidget->setPlainText(tr("Central widget"));
   BorderLayout *layout = new BorderLayout;
   layout->addWidget(centralWidget, BorderLayout::Center);
   layout->addWidget(createLabel("North"), BorderLayout::North);
   layout->addWidget(createLabel("West"), BorderLayout::West);
   layout->addWidget(createLabel("East 1"), BorderLayout::East);
   layout->addWidget(createLabel("East 2") , BorderLayout::East);
   layout->addWidget(createLabel("South"), BorderLayout::South);
   setLayout(layout);
   setWindowTitle(tr("Border Layout"));

} QLabel *Window::createLabel(const QString &text) {

   QLabel *label = new QLabel(text);
   label->setFrameStyle(QFrame::Box | QFrame::Raised);
   return label;

}


  1. include <QApplication>
  2. include "window.h"

int main(int argc, char *argv[]) {

   QApplication app(argc, argv);
   Window window;
   window.show();
   return app.exec();

}


 </source>


extends QLayout to create flow layout

<source lang="cpp"> /****************************************************************************

    • Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    • All rights reserved.
    • Contact: Nokia Corporation (qt-info@nokia.com)
    • This file is part of the examples of the Qt Toolkit.
    • $QT_BEGIN_LICENSE:LGPL$
    • Commercial Usage
    • Licensees holding valid Qt Commercial licenses may use this file in
    • accordance with the Qt Commercial License Agreement provided with the
    • Software or, alternatively, in accordance with the terms contained in
    • a written agreement between you and Nokia.
    • GNU Lesser General Public License Usage
    • Alternatively, this file may be used under the terms of the GNU Lesser
    • General Public License version 2.1 as published by the Free Software
    • Foundation and appearing in the file LICENSE.LGPL included in the
    • packaging of this file. Please review the following information to
    • ensure the GNU Lesser General Public License version 2.1 requirements
    • will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    • In addition, as a special exception, Nokia gives you certain additional
    • rights. These rights are described in the Nokia Qt LGPL Exception
    • version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    • GNU General Public License Usage
    • Alternatively, this file may be used under the terms of the GNU
    • General Public License version 3.0 as published by the Free Software
    • Foundation and appearing in the file LICENSE.GPL included in the
    • packaging of this file. Please review the following information to
    • ensure the GNU General Public License version 3.0 requirements will be
    • met: http://www.gnu.org/copyleft/gpl.html.
    • If you have questions regarding the use of this file, please contact
    • Nokia at qt-info@nokia.com.
    • $QT_END_LICENSE$
                                                                                                                                                        • /
  1. ifndef FLOWLAYOUT_H
  2. define FLOWLAYOUT_H
  3. include <QLayout>
  4. include <QRect>
  5. include <QWidgetItem>

class FlowLayout : public QLayout { public:

   FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1, int vSpacing = -1);
   FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
   ~FlowLayout();
   void addItem(QLayoutItem *item);
   int horizontalSpacing() const;
   int verticalSpacing() const;
   Qt::Orientations expandingDirections() const;
   bool hasHeightForWidth() const;
   int heightForWidth(int) const;
   int count() const;
   QLayoutItem *itemAt(int index) const;
   QSize minimumSize() const;
   void setGeometry(const QRect &rect);
   QSize sizeHint() const;
   QLayoutItem *takeAt(int index);

private:

   int doLayout(const QRect &rect, bool testOnly) const;
   int smartSpacing(QStyle::PixelMetric pm) const;
   QList<QLayoutItem *> itemList;
   int m_hSpace;
   int m_vSpace;

};

  1. endif


  1. include <QtGui>
  2. include "flowlayout.h"

FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)

   : QLayout(parent), m_hSpace(hSpacing), m_vSpace(vSpacing)

{

   setContentsMargins(margin, margin, margin, margin);

} FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)

   : m_hSpace(hSpacing), m_vSpace(vSpacing)

{

   setContentsMargins(margin, margin, margin, margin);

}

FlowLayout::~FlowLayout() {

   QLayoutItem *item;
   while ((item = takeAt(0)))
       delete item;

}

void FlowLayout::addItem(QLayoutItem *item) {

   itemList.append(item);

}

int FlowLayout::horizontalSpacing() const {

   if (m_hSpace >= 0) {
       return m_hSpace;
   } else {
       return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
   }

} int FlowLayout::verticalSpacing() const {

   if (m_vSpace >= 0) {
       return m_vSpace;
   } else {
       return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
   }

}

int FlowLayout::count() const {

   return itemList.size();

} QLayoutItem *FlowLayout::itemAt(int index) const {

   return itemList.value(index);

} QLayoutItem *FlowLayout::takeAt(int index) {

   if (index >= 0 && index < itemList.size())
       return itemList.takeAt(index);
   else
       return 0;

}

Qt::Orientations FlowLayout::expandingDirections() const {

   return 0;

}

bool FlowLayout::hasHeightForWidth() const {

   return true;

} int FlowLayout::heightForWidth(int width) const {

   int height = doLayout(QRect(0, 0, width, 0), true);
   return height;

}

void FlowLayout::setGeometry(const QRect &rect) {

   QLayout::setGeometry(rect);
   doLayout(rect, false);

} QSize FlowLayout::sizeHint() const {

   return minimumSize();

} QSize FlowLayout::minimumSize() const {

   QSize size;
   QLayoutItem *item;
   foreach (item, itemList)
       size = size.expandedTo(item->minimumSize());
   size += QSize(2*margin(), 2*margin());
   return size;

}

int FlowLayout::doLayout(const QRect &rect, bool testOnly) const {

   int left, top, right, bottom;
   getContentsMargins(&left, &top, &right, &bottom);
   QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
   int x = effectiveRect.x();
   int y = effectiveRect.y();
   int lineHeight = 0;
   QLayoutItem *item;
   foreach (item, itemList) {
       QWidget *wid = item->widget();
       int spaceX = horizontalSpacing();
       if (spaceX == -1)
           spaceX = wid->style()->layoutSpacing(
               QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
       int spaceY = verticalSpacing();
       if (spaceY == -1)
           spaceY = wid->style()->layoutSpacing(
               QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
       int nextX = x + item->sizeHint().width() + spaceX;
       if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
           x = effectiveRect.x();
           y = y + lineHeight + spaceY;
           nextX = x + item->sizeHint().width() + spaceX;
           lineHeight = 0;
       }
       if (!testOnly)
           item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
       x = nextX;
       lineHeight = qMax(lineHeight, item->sizeHint().height());
   }
   return y + lineHeight - rect.y() + bottom;

}

int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const {

   QObject *parent = this->parent();
   if (!parent) {
       return -1;
   } else if (parent->isWidgetType()) {
       QWidget *pw = static_cast<QWidget *>(parent);
       return pw->style()->pixelMetric(pm, 0, pw);
   } else {
       return static_cast<QLayout *>(parent)->spacing();
   }

}



  1. ifndef WINDOW_H
  2. define WINDOW_H
  3. include <QWidget>

QT_BEGIN_NAMESPACE class QLabel; QT_END_NAMESPACE class Window : public QWidget {

   Q_OBJECT

public:

   Window();

};

  1. endif


  1. include <QtGui>
  2. include "flowlayout.h"
  3. include "window.h"

Window::Window() {

   FlowLayout *flowLayout = new FlowLayout;
   flowLayout->addWidget(new QPushButton(tr("Short")));
   flowLayout->addWidget(new QPushButton(tr("Longer")));
   flowLayout->addWidget(new QPushButton(tr("Different text")));
   flowLayout->addWidget(new QPushButton(tr("More text")));
   flowLayout->addWidget(new QPushButton(tr("Even longer button text")));
   setLayout(flowLayout);
   setWindowTitle(tr("Flow Layout"));

}


  1. include <QApplication>
  2. include "window.h"

int main(int argc, char *argv[]) {

   QApplication app(argc, argv);
   Window window;
   window.show();
   return app.exec();

}


 </source>