pbootcms网站模板|日韩1区2区|织梦模板||网站源码|日韩1区2区|jquery建站特效-html5模板网

如何在 Qt 中制作可展開/可折疊的部分小部件

How to make an expandable/collapsable section widget in Qt(如何在 Qt 中制作可展開/可折疊的部分小部件)
本文介紹了如何在 Qt 中制作可展開/可折疊的部分小部件的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

我想在 Qt 中創建一個具有以下功能的自定義小部件:

I would like to create a custom widget in Qt with the following features:

  • 這是一個容器
  • 它可以填充任何 Qt 布局
  • 它可以在任何 Qt 布局中
  • 按鈕允許垂直折疊/折疊內容,因此只有按鈕可見,所有包含的布局都不可見.
  • 上一個按鈕允許將其再次展開/展開到布局內容的大小.
  • 展開/折疊基于尺寸(不是顯示/隱藏)以允許動畫.
  • 可在 QDesigner 中使用

為了提供一個想法,這是一個類似小部件(不是 Qt)的圖像:

To provide an idea, here is an image of a similar widget (not Qt):

我已經有一個框架可以正常工作并在 QDesigner 中公開.我現在需要讓它展開/折疊,這看起來并不那么簡單.

I already have a frame that work correctly and is exposed in QDesigner. I need now to make it to extend/collapse, which does not seem so simple.

我嘗試使用 resize()、sizePolicy()、sizeHint() 但這不起作用:當框架折疊時,我得到以下值:

I tried to play with resize(), sizePolicy(), sizeHint() but that does not work: When the frame is collapsed I got following values:

sizeHint: (500,20)
size    : (500,20)
closestAcceptableSize: (518,150)
Painted size: (518, 150)

QLayout::closestAcceptableSize 不是小部件的一部分,因此我無法更改它.

QLayout::closestAcceptableSize is not part of the widget so I cannot change it.

任何提示或/和代碼片段來實現這一點?

這里有一個簡單的例子.除必要外,我刪除了所有內容.

EDITED: Here a simple example. I removed all except necessary.

main.cpp 示例

main.cpp example

#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>

#include "section.hpp"


using namespace myWidgets;
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);


    // Create the main Window
    QWidget window;
    window.resize(500,500);
    window.setStyleSheet("QPushButton:{background-color:rgba(128,128,128,192);}");

    // Create the main window layout
    QVBoxLayout topLayout(&window);
    QWidget *w1 = new QWidget();
    w1->setStyleSheet("background-color:rgba(128,128,128,192);");
    topLayout.addWidget(w1);

    Section section(&window);
    topLayout.addWidget(&section);

    QVBoxLayout inLayout(&section);
    QPushButton *button = new QPushButton();
    button->setMinimumHeight(100);
    inLayout.addWidget(button);

    QWidget *w2 = new QWidget();
    w2->setStyleSheet("background-color:rgba(128,128,128,192);");
    topLayout.addWidget(w2);



    window.show();

    return a.exec();
}

Section.hpp

Section.hpp

#ifndef SECTION_HPP
#define SECTION_HPP

#include <QPushButton> //for the expand/collapse button
#include <QtDesigner/QDesignerExportWidget>
#include <QLayout>
#include <QPainter>
#include <QPaintEvent>
#include <QDebug>


// Compatibility for noexcept, not supported in vsc++
#ifdef _MSC_VER
#define noexcept throw()
#endif

#if defined SECTION_BUILD
    #define SECTION_BUILD_DLL_SPEC Q_DECL_EXPORT
#elif defined SECTION_EXEC
    #define SECTION_BUILD_DLL_SPEC
#else
    #define SECTION_BUILD_DLL_SPEC Q_DECL_IMPORT
#endif

namespace myWidgets
{

class SECTION_BUILD_DLL_SPEC Section : public QWidget
{
    Q_OBJECT

    Q_PROPERTY( bool is_expanded MEMBER isExpanded)

public:
    // Constructor, standard
    explicit Section( QWidget *parent=0 ): QWidget(parent),
        expandButton(this)
    {
        expandButton.resize(20,20);
        expandButton.move(0,0);
        expandButton.connect(&expandButton, &QPushButton::clicked,
                             this, &Section::expandCollapseEvent);

        QMargins m= contentsMargins();
        m.setTop(m.top()+25);
        setContentsMargins(m);
        //setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Minimum);

    }

    virtual void expand( bool expanding ) noexcept
    {
        resize(sizeHint());
        isExpanded = expanding;
        updateGeometry();

qDebug() << (isExpanded? "expanded":"collapsed") << sizeHint() << QWidget::size() <<
            parentWidget()->layout()->closestAcceptableSize(this, size());
    }

    virtual QSize sizeHint() const noexcept override
    {
        if (isExpanded) return QSize(layout()->contentsRect().width(),
                                     layout()->contentsRect().height());
        else return QSize(layout()->contentsRect().width(), 20);
    }

    // Implement custom appearance
    virtual void paintEvent(QPaintEvent *e) noexcept override
    {
        (void) e; //TODO: remove
        QPainter p(this);
        p.setClipRect(e->rect());
        p.setRenderHint(QPainter::Antialiasing );
        p.fillRect(e->rect(), QColor(0,0,255,128));
    }

protected:

    // on click of the expandButton, collapse/expand this widget
    virtual void expandCollapseEvent() noexcept
    {
        expand(!isExpanded);
    }


    bool isExpanded = true; //whenever the section is collapsed(false) or expanded(true)
    QPushButton expandButton; //the expanding/collapsing button
};

}


#endif // SECTION_HPP

推薦答案

我偶然發現了同樣的問題,并通過將可折疊小部件實現為 QScrollArea 來解決它,其最大高度由 動畫>QPropertyAnimation.

I stumbled upon the same problem and solved it by implementing the collapsible widget as a QScrollArea whose maximum height is animated by a QPropertyAnimation.

但因為我不使用 QDesigner,所以我不能告訴你它是否在那里工作.

But since I don't use QDesigner, I can't tell you if it works there.

我仍然有一個問題:可折疊小部件不僅可以向底部方向擴展,還可以向頂部和底部擴展.如果尚未達到其最小高度,這可能會導致位于其上方的小部件縮小.但這與我們必須自己構建這個東西的事實相比確實是一個細節......

I still have one problem: Instead of only expanding towards the bottom direction, the collapsible widget can expand towards the top and bottom. This can cause widgets located above it to shrink if they haven't reached their minimum height, yet. But this is really a detail compared to the fact that we have to build this thing ourselves…

Spoiler.h

#include <QFrame>
#include <QGridLayout>
#include <QParallelAnimationGroup>
#include <QScrollArea>
#include <QToolButton>
#include <QWidget>

class Spoiler : public QWidget {
    Q_OBJECT
private:
    QGridLayout mainLayout;
    QToolButton toggleButton;
    QFrame headerLine;
    QParallelAnimationGroup toggleAnimation;
    QScrollArea contentArea;
    int animationDuration{300};
public:
    explicit Spoiler(const QString & title = "", const int animationDuration = 300, QWidget *parent = 0);
    void setContentLayout(QLayout & contentLayout);
};

Spoiler.cpp

#include <QPropertyAnimation>

#include "Spoiler.h"

Spoiler::Spoiler(const QString & title, const int animationDuration, QWidget *parent) : QWidget(parent), animationDuration(animationDuration) {
    toggleButton.setStyleSheet("QToolButton { border: none; }");
    toggleButton.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
    toggleButton.setArrowType(Qt::ArrowType::RightArrow);
    toggleButton.setText(title);
    toggleButton.setCheckable(true);
    toggleButton.setChecked(false);

    headerLine.setFrameShape(QFrame::HLine);
    headerLine.setFrameShadow(QFrame::Sunken);
    headerLine.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum);

    contentArea.setStyleSheet("QScrollArea { background-color: white; border: none; }");
    contentArea.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    // start out collapsed
    contentArea.setMaximumHeight(0);
    contentArea.setMinimumHeight(0);
    // let the entire widget grow and shrink with its content
    toggleAnimation.addAnimation(new QPropertyAnimation(this, "minimumHeight"));
    toggleAnimation.addAnimation(new QPropertyAnimation(this, "maximumHeight"));
    toggleAnimation.addAnimation(new QPropertyAnimation(&contentArea, "maximumHeight"));
    // don't waste space
    mainLayout.setVerticalSpacing(0);
    mainLayout.setContentsMargins(0, 0, 0, 0);
    int row = 0;
    mainLayout.addWidget(&toggleButton, row, 0, 1, 1, Qt::AlignLeft);
    mainLayout.addWidget(&headerLine, row++, 2, 1, 1);
    mainLayout.addWidget(&contentArea, row, 0, 1, 3);
    setLayout(&mainLayout);
    QObject::connect(&toggleButton, &QToolButton::clicked, [this](const bool checked) {
        toggleButton.setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow);
        toggleAnimation.setDirection(checked ? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
        toggleAnimation.start();
    });
}

void Spoiler::setContentLayout(QLayout & contentLayout) {
    delete contentArea.layout();
    contentArea.setLayout(&contentLayout);
    const auto collapsedHeight = sizeHint().height() - contentArea.maximumHeight();
    auto contentHeight = contentLayout.sizeHint().height();
    for (int i = 0; i < toggleAnimation.animationCount() - 1; ++i) {
        QPropertyAnimation * spoilerAnimation = static_cast<QPropertyAnimation *>(toggleAnimation.animationAt(i));
        spoilerAnimation->setDuration(animationDuration);
        spoilerAnimation->setStartValue(collapsedHeight);
        spoilerAnimation->setEndValue(collapsedHeight + contentHeight);
    }
    QPropertyAnimation * contentAnimation = static_cast<QPropertyAnimation *>(toggleAnimation.animationAt(toggleAnimation.animationCount() - 1));
    contentAnimation->setDuration(animationDuration);
    contentAnimation->setStartValue(0);
    contentAnimation->setEndValue(contentHeight);
}

如何使用:

…
auto * anyLayout = new QVBoxLayout();
anyLayout->addWidget(…);
…
Spoiler spoiler;
spoiler.setContentLayout(*anyLayout);
…

這篇關于如何在 Qt 中制作可展開/可折疊的部分小部件的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!

相關文檔推薦

How can I read and manipulate CSV file data in C++?(如何在 C++ 中讀取和操作 CSV 文件數據?)
In C++ why can#39;t I write a for() loop like this: for( int i = 1, double i2 = 0; (在 C++ 中,為什么我不能像這樣編寫 for() 循環: for( int i = 1, double i2 = 0;)
How does OpenMP handle nested loops?(OpenMP 如何處理嵌套循環?)
Reusing thread in loop c++(在循環 C++ 中重用線程)
Precise thread sleep needed. Max 1ms error(需要精確的線程睡眠.最大 1ms 誤差)
Is there ever a need for a quot;do {...} while ( )quot; loop?(是否需要“do {...} while ()?環形?)
主站蜘蛛池模板: 行星搅拌机,双行星搅拌机,动力混合机,无锡米克斯行星搅拌机生产厂家 | 垃圾清运公司_环卫保洁公司_市政道路保洁公司-华富环境 | 电动高尔夫球车|电动观光车|电动巡逻车|电动越野车厂家-绿友机械集团股份有限公司 | 上海单片机培训|重庆曙海培训分支机构—CortexM3+uC/OS培训班,北京linux培训,Windows驱动开发培训|上海IC版图设计,西安linux培训,北京汽车电子EMC培训,ARM培训,MTK培训,Android培训 | 扫地车厂家-山西洗地机-太原电动扫地车「大同朔州吕梁晋中忻州长治晋城洗地机」山西锦力环保科技有限公司 | 艾默生变频器,艾默生ct,变频器,ct驱动器,广州艾默生变频器,供水专用变频器,风机变频器,电梯变频器,艾默生变频器代理-广州市盟雄贸易有限公司官方网站-艾默生变频器应用解决方案服务商 | 冷水机-冰水机-冷冻机-冷风机-本森智能装备(深圳)有限公司 | 全自动五线打端沾锡机,全自动裁线剥皮双头沾锡机,全自动尼龙扎带机-东莞市海文能机械设备有限公司 | SRRC认证_电磁兼容_EMC测试整改_FCC认证_SDOC认证-深圳市环测威检测技术有限公司 | 三效蒸发器_多效蒸发器价格_四效三效蒸发器厂家-青岛康景辉 | 垃圾压缩设备_垃圾处理设备_智能移动式垃圾压缩设备--山东明莱环保设备有限公司 | 真丝围巾|真丝丝巾|羊绒围巾|围巾品牌|浙江越缇围巾厂家定制 | 碳纤维复合材料制品生产定制工厂订制厂家-凯夫拉凯芙拉碳纤维手机壳套-碳纤维雪茄盒外壳套-深圳市润大世纪新材料科技有限公司 | 天然气分析仪-液化气二甲醚分析仪|传昊仪器| 南溪在线-南溪招聘找工作、找房子、找对象,南溪综合生活信息门户! | 细石混凝土泵_厂家_价格-烟台九达机械有限公司 | 电气控制系统集成商-PLC控制柜变频控制柜-非标自动化定制-电气控制柜成套-NIDEC CT变频器-威肯自动化控制 | 衬氟旋塞阀-卡套旋塞阀-中升阀门首页 | 二手电脑回收_二手打印机回收_二手复印机回_硒鼓墨盒回收-广州益美二手电脑回收公司 | 工作服定制,工作服定做,工作服厂家-卡珀职业服装(苏州)有限公司 | 扫地车厂家-山西洗地机-太原电动扫地车「大同朔州吕梁晋中忻州长治晋城洗地机」山西锦力环保科技有限公司 | ETFE膜结构_PTFE膜结构_空间钢结构_膜结构_张拉膜_浙江萬豪空间结构集团有限公司 | 旗杆生产厂家_不锈钢锥形旗杆价格_铝合金电动旗杆-上海锥升金属科技有限公司 | 电脑刺绣_绣花厂家_绣花章仔_织唛厂家-[源欣刺绣]潮牌刺绣打版定制绣花加工厂家 | 上海佳武自动化科技有限公司 | 全自动过滤器_反冲洗过滤器_自清洗过滤器_量子除垢环_量子环除垢_量子除垢 - 安士睿(北京)过滤设备有限公司 | 吸音板,隔音板,吸音材料,吸音板价格,声学材料 - 佛山诺声吸音板厂家 | 水环真空泵厂家,2bv真空泵,2be真空泵-淄博真空设备厂 | 噪声治理公司-噪音治理专业隔音降噪公司 | 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 深圳装修_店面装修设计_餐厅设计_装修全包价格-尚泰装饰设计 | 测试治具|过炉治具|过锡炉治具|工装夹具|测试夹具|允睿自动化设备 | 医学模型生产厂家-显微手术模拟训练器-仿真手术模拟训练系统-北京医教科技 | 活性炭厂家-蜂窝活性炭-粉状/柱状/果壳/椰壳活性炭-大千净化-活性炭 | 建筑资质代办_工程施工资质办理_资质代办公司_北京众聚企服 | 背压阀|减压器|不锈钢减压器|减压阀|卫生级背压阀|单向阀|背压阀厂家-上海沃原自控阀门有限公司 本安接线盒-本安电路用接线盒-本安分线盒-矿用电话接线盒-JHH生产厂家-宁波龙亿电子科技有限公司 | 北京亦庄厂房出租_经开区产业园招商信息平台 | 济南品牌包装设计公司_济南VI标志设计公司_山东锐尚文化传播 | 玉米深加工设备|玉米加工机械|玉米加工设备|玉米深加工机械-河南成立粮油机械有限公司 | 葡萄酒灌装机-食用油灌装机-液体肥灌装设备厂家_青州惠联灌装机械 | 海外整合营销-独立站营销-社交媒体运营_广州甲壳虫跨境网络服务 焊管生产线_焊管机组_轧辊模具_焊管设备_焊管设备厂家_石家庄翔昱机械 |