zoukankan      html  css  js  c++  java
  • Qt之四方分割器QuadSplitter

    在Qt经常会用到分割器QSplitter,可以对多个控件进行水平或者垂直分割,但有一些特殊的需求无法满足,比如:四方分割。。。QuadSplitter是qt-apps里面的一个应用,挺不错的,拿来和大家分享一下,下载地址:QuadSplitter

     
    效果如下:
     
     
    #ifndef QUADSPLITTER_H
    #define QUADSPLITTER_H
    
    #include 
    
    class QuadSplitterPrivate;
    
    class QuadSplitter : public QFrame
    {
            Q_OBJECT
    public:
            QuadSplitter(QWidget *parent);
            ~QuadSplitter();
    
            void addWidget(QWidget *, int row, int column);
    
            int spacing() const;
            void setSpacing(int spacing);
    
            int splittersSpacing() const;
            void setSplittersSpacing(int spacing);
    
            int centerPartWidth() const;
            void setCenterPartWidth(int value);
    
            int minimumWidgetSize() const;
            void setMinimumWidgetSize(int value);
    protected:
            void resizeEvent(QResizeEvent *);
    private:
            QuadSplitterPrivate * const d_ptr;
            Q_DISABLE_COPY(QuadSplitter)
            Q_DECLARE_PRIVATE(QuadSplitter);
            friend class AdvSplitter;
    };
    
    #endif // QUADSPLITTER_H
    
    
    #include "quadsplitter.h"
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    class AdvSplitter;
    
    class QuadSplitterPrivate : public QObject
    {
            Q_DECLARE_PUBLIC(QuadSplitter);
    public: 
            QuadSplitterPrivate(QuadSplitter* _q_ptr);
            void addWidget(QWidget *widget, int row, int column);
            void splitterMoveStart(AdvSplitter* splitter, bool center);
            void splitterMove(AdvSplitter* splitter, QPoint const& offset, bool center);
            void arrange();
            qreal realPercent(Qt::Orientation orientation) const;
    
            int spacing() const;
            void setSpacing(int spacing);
    
            int splittersSpacing() const;
            void setSplittersSpacing(int spacing);
    
            int centerPartWidth() const;
            void setCenterPartWidth(int value);
    
            int minimumWidgetSize() const;
            void setMinimumWidgetSize(int value);
    private:
            QuadSplitter *q_ptr;
    
            QScopedPointer _horizontalSplitter;
            QScopedPointer _verticalSplitter;
    
        QPointer _grid[2][2];
            int _spacing;
            int _splittersSpacing;
            QPoint _splittersMovingPos;
            int _minimumWidgetSize;
            int _centerPart;
    
            int realSpacing() const;
            int realWidth() const;
            int realHeight() const;
    };
    //////////////////////////////////////////////////////////////////////////
    class AdvSplitter : public QWidget
    {
    public:
            AdvSplitter(QWidget* parent, QuadSplitterPrivate* priv, Qt::Orientation orientation)
                    : QWidget(parent), _percent(0.5), _orientation(orientation), 
                    _mouse(false), _center(false), _private(priv)
            {
                    setMouseTracking(true);
                    if (orientation == Qt::Horizontal)
                            setCursor(Qt::SplitHCursor);
                    else if (orientation == Qt::Vertical)
                            setCursor(Qt::SplitVCursor);
            }
            
            qreal percent() const
            {
                    return _percent;
            }
    
            void setPercent(qreal val)  
            {
                    _percent = val;
            }
    protected:
            void paintEvent (QPaintEvent *event)
            {
                    QStylePainter painter(this);
                    QStyleOption opt1, opt2;
                    opt1.init(this);
                    opt2.init(this);
                    opt1.state = opt2.state = QStyle::State_None;
                    if (_orientation == Qt::Horizontal)
                    {
                            opt1.state |= QStyle::State_Horizontal;
                            opt2.state |= QStyle::State_Horizontal;
    
                            if (_private)
                            {
                                    int hiPart = qFloor((qreal)opt1.rect.height() * _private->realPercent(Qt::Vertical) + 0.5);
                                    int loPart = opt1.rect.height() - hiPart;
                                    opt1.rect.setBottom(opt1.rect.top() + hiPart);
                                    opt2.rect.setTop(opt2.rect.bottom() - loPart);
                            }
                    }
                    else if (_private)
                    {
                            int hiPart = qFloor((qreal)opt1.rect.width() * _private->realPercent(Qt::Horizontal) + 0.5);
                            int loPart = opt1.rect.width() - hiPart;
                            opt1.rect.setRight(opt1.rect.left() + hiPart);
                            opt2.rect.setLeft(opt2.rect.right() - loPart);
                    }
    
                    painter.drawControl(QStyle::CE_Splitter, opt1);
                    if (_private)
                            painter.drawControl(QStyle::CE_Splitter, opt2);
            }
            
            void mouseMoveEvent(QMouseEvent * event)
            {
                    if (!_mouse && _private)
                    {
                            if (_orientation == Qt::Horizontal)
                            {
                                    int hiPart = qFloor((qreal)height() * _private->realPercent(Qt::Vertical) + 0.5);
                                    if (event->pos().y() > (hiPart - _private->centerPartWidth() / 2) && 
                                            event->pos().y() < (hiPart + _private->centerPartWidth() / 2))
                                            setCursor(Qt::SizeAllCursor);
                                    else
                                            setCursor(Qt::SplitHCursor);
                            }
                            else
                            {
                                    int hiPart = qFloor((qreal)width() * _private->realPercent(Qt::Horizontal) + 0.5);
                                    if (event->pos().x() > (hiPart - _private->centerPartWidth() / 2) && 
                                            event->pos().x() < (hiPart + _private->centerPartWidth() / 2))
                                            setCursor(Qt::SizeAllCursor);
                                    else
                                            setCursor(Qt::SplitVCursor);
                            }
                    }
                    else if (_center)
                    {
                            if (cursor().shape() != Qt::SizeAllCursor) 
                                    setCursor(Qt::SizeAllCursor);
                    }
                    else if (_orientation == Qt::Horizontal)
                    {
                            if (cursor().shape() != Qt::SplitHCursor)
                                    setCursor(Qt::SplitHCursor);
                    }
                    else if (cursor().shape() != Qt::SplitVCursor)
                            setCursor(Qt::SplitVCursor);
    
                    if (_mouse && (event->buttons() & Qt::LeftButton))
                    {
                            QPoint pt = mapToParent(event->pos());
    
                            if (QuadSplitter* p = qobject_cast(parent()))
                                    p->d_ptr->splitterMove(this, pt - _mousePos, _center);
                    }
            }
            
            void mousePressEvent(QMouseEvent *event)
            {
                    if (event->button() == Qt::LeftButton)
                    {
                            _mouse = true;
                            if (_private)
                            {
                                    if (_orientation == Qt::Horizontal)
                                    {
                                            int hiPart = qFloor((qreal)height() * _private->realPercent(Qt::Vertical) + 0.5);
                                            if (event->pos().y() > (hiPart - _private->centerPartWidth() / 2) && 
                                                    event->pos().y() < (hiPart + _private->centerPartWidth() / 2))
                                            {
                                                    _center = true;
                                                    setCursor(Qt::SizeAllCursor);
                                            }
                                            else
                                                    setCursor(Qt::SplitHCursor);
                                    }
                                    else
                                    {
                                            int hiPart = qFloor((qreal)width() * _private->realPercent(Qt::Horizontal) + 0.5);
                                            if (event->pos().x() > (hiPart - _private->centerPartWidth() / 2) && 
                                                    event->pos().x() < (hiPart + _private->centerPartWidth() / 2))
                                            {
                                                    _center = true;
                                                    setCursor(Qt::SizeAllCursor);
                                            }
                                            else
                                                    setCursor(Qt::SplitVCursor);
                                    }
                            }
                    }
                    _mousePos = mapToParent(event->pos());
                    if (QuadSplitter* p = qobject_cast(parent()))
                            p->d_ptr->splitterMoveStart(this, _center);
            }
            
            void mouseReleaseEvent(QMouseEvent *event)
            {
                    _mouse = false;
                    _center = false;
            }
    private:
            bool _mouse;
            QPoint _mousePos;
            Qt::Orientation _orientation;
            qreal _percent;
            QPointer _private;
            bool _center;
    };
    //////////////////////////////////////////////////////////////////////////
    QuadSplitterPrivate::QuadSplitterPrivate(QuadSplitter* _q_ptr) 
            : q_ptr(_q_ptr), _spacing(5), _splittersSpacing(5), 
            _minimumWidgetSize(30), _centerPart(30)
    {
            Q_Q(QuadSplitter);
            _horizontalSplitter.reset(new AdvSplitter(q, this, Qt::Horizontal));
            _verticalSplitter.reset(new AdvSplitter(q, this, Qt::Vertical));
    
            arrange();
    }
    
    int QuadSplitterPrivate::realSpacing() const
    {
            const Q_Q(QuadSplitter);
            return _spacing + q->frameWidth();
    }
    
    int QuadSplitterPrivate::realWidth() const
    {
            const Q_Q(QuadSplitter);
        return q->width() - (realSpacing() * 2) - _splittersSpacing;
    }
    
    int QuadSplitterPrivate::realHeight() const
    {
            const Q_Q(QuadSplitter);
        return q->height() - (realSpacing() * 2) - _splittersSpacing;
    }
    
    void QuadSplitterPrivate::arrange()
    {
            Q_Q(QuadSplitter);
    
        QPair minMaxHorizontalSizes[2] =
                    {QPair(0, QWIDGETSIZE_MAX), QPair(0, QWIDGETSIZE_MAX)};
    
        QPair minMaxVerticalSizes[2] =
                    {QPair(0, QWIDGETSIZE_MAX), QPair(0, QWIDGETSIZE_MAX)};
                    
        for (int r = 0; r < 2; ++r)
            {
            for (int c = 0; c < 2; ++c)
                    {
                            if (_grid[r][c] && _grid[r][c]->parent() == q)
                            {
                                    minMaxHorizontalSizes[c] = 
                                            QPair(
                                            qMax(_grid[r][c]->minimumWidth() < _minimumWidgetSize ? _minimumWidgetSize : _grid[r][c]->minimumWidth(),
                                                    minMaxHorizontalSizes[c].first),
                                            qMin(_grid[r][c]->maximumWidth(), minMaxHorizontalSizes[c].second));
    
                                    minMaxVerticalSizes[r] = 
                                            QPair(
                                            qMax(_grid[r][c]->minimumHeight() < _minimumWidgetSize ? _minimumWidgetSize : _grid[r][c]->minimumHeight(),
                                                    minMaxVerticalSizes[r].first),
                                            qMin(_grid[r][c]->maximumHeight(), minMaxVerticalSizes[r].second));
                            }
                            else
                                    _grid[r][c] = nullptr;
                    }
            }
    
            //columns
            int leftColumnWidth = qFloor((qreal)realWidth() * _horizontalSplitter->percent() + 0.5);
            if (leftColumnWidth < minMaxHorizontalSizes[0].first)
                    leftColumnWidth = minMaxHorizontalSizes[0].first;
            if (leftColumnWidth > minMaxHorizontalSizes[0].second)
                    leftColumnWidth = minMaxHorizontalSizes[0].second;
    
            int columnWidth = leftColumnWidth;
    
            int rightColumnWidth = realWidth() - leftColumnWidth;
            if (rightColumnWidth < minMaxHorizontalSizes[1].first)
            {
                    rightColumnWidth = minMaxHorizontalSizes[1].first;
                    columnWidth = realWidth() - rightColumnWidth;
            }
            if (rightColumnWidth > minMaxHorizontalSizes[1].second)
            {
                    rightColumnWidth = minMaxHorizontalSizes[1].second;
                    columnWidth = realWidth() - rightColumnWidth;
            }
            //rows
            int topColumnHeight = qFloor((qreal)realHeight() * _verticalSplitter->percent() + 0.5);
            if (topColumnHeight < minMaxVerticalSizes[0].first)
                    topColumnHeight = minMaxVerticalSizes[0].first;
            if (topColumnHeight > minMaxVerticalSizes[0].second)
                    topColumnHeight = minMaxVerticalSizes[0].second;
    
            int columnHeight = topColumnHeight;
    
            int bottomColumnHeight = realHeight() - topColumnHeight;
            if (bottomColumnHeight < minMaxVerticalSizes[1].first)
            {
                    bottomColumnHeight = minMaxVerticalSizes[1].first;
                    columnHeight = realHeight() - bottomColumnHeight;
            }
            if (bottomColumnHeight > minMaxVerticalSizes[1].second)
            {
                    bottomColumnHeight = minMaxVerticalSizes[1].second;
                    columnHeight = realHeight() - bottomColumnHeight;
            }
    
            _horizontalSplitter->setGeometry(realSpacing() + columnWidth, realSpacing(), _splittersSpacing, q->height() - realSpacing() * 2);
            _horizontalSplitter->raise();
    
            _verticalSplitter->setGeometry(realSpacing(), realSpacing() + columnHeight, q->width() - realSpacing() * 2, _splittersSpacing);
            _verticalSplitter->raise();
    
            if (_grid[0][0])
                    _grid[0][0]->setGeometry(realSpacing(), realSpacing(), columnWidth, columnHeight);
            if (_grid[0][1])
                    _grid[0][1]->setGeometry(realSpacing() + columnWidth + _splittersSpacing, realSpacing(), realWidth() - columnWidth, columnHeight);
    
            if (_grid[1][0])
                    _grid[1][0]->setGeometry(realSpacing(), 
                            realSpacing() + columnHeight + _splittersSpacing, columnWidth, realHeight() - columnHeight);
            if (_grid[1][1])
                    _grid[1][1]->setGeometry(realSpacing() + columnWidth + _splittersSpacing, 
                            realSpacing() + columnHeight + _splittersSpacing, realWidth() - columnWidth, realHeight() - columnHeight);
    }
    
    void QuadSplitterPrivate::addWidget(QWidget *widget, int row, int column)
    {
            Q_Q(QuadSplitter);
        if (row < 0 || column < 0 || row > 1 || column > 1) {
            qWarning("QGridLayout: Cannot add %s/%s to %s/%s at row %d column %d",
                widget->metaObject()->className(), widget->objectName().toLocal8Bit().data(),
                q->metaObject()->className(), q->objectName().toLocal8Bit().data(), row, column);
            return;
        }
    
            bool needShow = q->isVisible() &&
                    !(widget->isHidden() && widget->testAttribute(Qt::WA_WState_ExplicitShowHide));
            if (widget->parentWidget() != q)
                    widget->setParent(q);
            if (needShow)
                    widget->show();
    
            _grid[row][column] = widget;
                    
            arrange();
    }
    
    void QuadSplitterPrivate::splitterMoveStart(AdvSplitter* splitter, bool center)
    {
            _splittersMovingPos = QPoint(_horizontalSplitter->x(), _verticalSplitter->y());
    }
    
    void QuadSplitterPrivate::splitterMove(AdvSplitter* splitter, QPoint const& offset, bool center)
    {
            Q_Q(QuadSplitter);
            if (center)
            {
                    qreal newX = _splittersMovingPos.x() + offset.x() - realSpacing();
                    qreal newY = _splittersMovingPos.y() + offset.y() - realSpacing();
                    _horizontalSplitter->setPercent(newX / (qreal)realWidth());
                    _verticalSplitter->setPercent(newY / (qreal)realHeight());
            }
            else if (splitter == _horizontalSplitter.data())
            {
                    qreal newX = _splittersMovingPos.x() + offset.x() - realSpacing();
                    splitter->setPercent(newX / (qreal)realWidth());
            }
            else
            {
                    qreal newY = _splittersMovingPos.y() + offset.y() - realSpacing();
                    splitter->setPercent(newY / (qreal)realHeight());
            }
            arrange();
    }
    
    int QuadSplitterPrivate::splittersSpacing() const
    {
            return _splittersSpacing;
    }
    
    void QuadSplitterPrivate::setSplittersSpacing(int spacing)
    {
            _splittersSpacing = spacing;
    }
    
    qreal QuadSplitterPrivate::realPercent(Qt::Orientation orientation) const
    {
            if (orientation == Qt::Horizontal)
            {
                    qreal newX = _horizontalSplitter->x() - realSpacing();
                    return newX / realWidth();
            }
            
            qreal newY = _verticalSplitter->y() - realSpacing();
            return newY / realHeight();
    }
    
    int QuadSplitterPrivate::spacing() const
    {
            return _spacing;
    }
    
    void QuadSplitterPrivate::setSpacing(int spacing)
    {
            _spacing = spacing;
    }
    
    int QuadSplitterPrivate::centerPartWidth() const
    {
            return _centerPart;
    }
    
    void QuadSplitterPrivate::setCenterPartWidth(int value)
    {
            _centerPart = value;
    }
    
    int QuadSplitterPrivate::minimumWidgetSize() const
    {
            return _minimumWidgetSize;
    }
    
    void QuadSplitterPrivate::setMinimumWidgetSize(int value)
    {
            _minimumWidgetSize = value;
    }
    
    //////////////////////////////////////////////////////////////////////////
    QuadSplitter::QuadSplitter(QWidget *parent)
            : QFrame(parent), d_ptr(new QuadSplitterPrivate(this))
    {
    }
    
    QuadSplitter::~QuadSplitter()
    {
            delete d_ptr;
    }
    
    void QuadSplitter::addWidget(QWidget *widget, int row, int column)
    {
            Q_D(QuadSplitter);
            d->addWidget(widget, row, column);
    }
    
    void QuadSplitter::resizeEvent(QResizeEvent *event)
    {
            Q_D(QuadSplitter);
            d->arrange();
    }
    
    int QuadSplitter::spacing() const
    {
            const Q_D(QuadSplitter);
            return d->spacing();
    }
    
    void QuadSplitter::setSpacing(int spacing)
    {
            Q_D(QuadSplitter);
            d->setSpacing(spacing);
    }
    
    int QuadSplitter::splittersSpacing() const
    {
            const Q_D(QuadSplitter);
            return d->splittersSpacing();
    }
    
    void QuadSplitter::setSplittersSpacing(int spacing)
    {
            Q_D(QuadSplitter);
            d->setSplittersSpacing(spacing);
    }
    
    int QuadSplitter::centerPartWidth() const
    {
            const Q_D(QuadSplitter);
            return d->centerPartWidth();
    }
    
    void QuadSplitter::setCenterPartWidth(int value)
    {
            Q_D(QuadSplitter);
            d->setCenterPartWidth(value);
    }
    
    int QuadSplitter::minimumWidgetSize() const
    {
            const Q_D(QuadSplitter);
            return d->minimumWidgetSize();
    }
    
    void QuadSplitter::setMinimumWidgetSize(int value)
    {
            Q_D(QuadSplitter);
            d->setMinimumWidgetSize(value);
    }

    使用方法:(类似于QGridLayout)

        QuadSplitter *pSplitter = new QuadSplitter(this);
    
        QStringList strList;
        strList << "#990099" << "#99FFFF" << "#CC0099" << "#CCFF99";
        for (int i = 0; i < strList.count(); ++i)
        {
            QWidget *pWidget = new QWidget(this);
            pWidget->setStyleSheet(QString("background:%1").arg(strList.at(i)));
            pSplitter->addWidget(pWidget, i/2, i%2);
        }

    http://blog.sina.com.cn/s/blog_a6fb6cc90102vkr2.html

  • 相关阅读:
    Log4J日志配置详解
    Linux:ssh端口转发详解
    Android数据存储五种方式总结
    Nginx学习记录
    简单通用JDBC辅助类封装
    PBR.理论
    PBR.工作流贴图
    不设置readable,读取图片数据
    直接打开指定的目录
    Compute Shader基础
  • 原文地址:https://www.cnblogs.com/findumars/p/4912157.html
Copyright © 2011-2022 走看看