qml实现自定义互斥按钮

环境

Ubuntu16.04+Qt5.7

描述

qml中有一个控件RadioButton,单选按钮,即在一个按钮组中只能选中一个;如果想自定义实现按钮的样式的话,则需要使用到一个qml类型:ExclusiveGroup。

效果

如图,左上方的是使用RadioButton实现的效果,中间的则为自定义按钮互斥效果。
实现效果

实现

首先实现自定义按钮的样式,然后再寻找一种方法使这些按钮群产生互斥的效果即可。这个实现查到一种十分便捷的方法,即ExclusiveGroup。其中,Exclusive有“独家,独占的”之意。
Qt助手中,ExclusiveGroup的描述为“ExclusiveGroup可以包含多个Action项,这些项将自动获取其Action :: exclusiveGroup属性。几个控件已经支持ExclusiveGroup,例如 Action,MenuItem,Button和RadioButton。”
再看Qt助手中给出的例子:大致意思为给一个Item添加互斥属性,需要如下操作。
Qt助手的示例
疑问:注意上图的最后一句:如上图所示是向Item添加互斥属性的最少且必须的代码。遗憾的是,我试着这样做但是没有互斥效果,究其原因,是缺少了一个onCheckedChanged的处理,但是不明白为什么Qt助手中会这样描述。

例子

CheckButton.qml部分代码如下:

import QtQuick 2.1
import QtQuick.Controls 1.4

Rectangle{
    ……

    property bool checked: false
    property ExclusiveGroup exclusiveGroup: null //对外开放一个ExclusiveGroup接口,用于绑定同个组

    onExclusiveGroupChanged: {
        if (exclusiveGroup) {
            exclusiveGroup.bindCheckable(checkButton)
        }
    }

    //如果少了这个信号处理,则无法出现互斥效果
    onCheckedChanged: {
        checked ? checkPic.source = "qrc:/icon_choose.png" : checkPic.source = "qrc:/icon_choose_not.png"
    }

    Image {
        ……
    }

    Text {
        ……
    }

    MouseArea {
        ……
    }
}

用法

main.qml部分代码如下:

import QtQuick 2.5
import QtQuick.Controls 1.4

Rectangle {
    id: root
    width: 640; height: 480
    color: "#ff0099FF"
    ……
    Text{
        id: text
        anchors.bottom: buttonRow.top
        anchors.left: buttonRow.left
        anchors.margins: 5
        text: "请任意选择一项:"
        font.pixelSize: 20
        color: "white"
    }

    Row {
        id: buttonRow
        spacing: 5
        anchors.centerIn: parent

        ExclusiveGroup { id: buttonGroup } //提供一个组给按钮绑定

        CheckButton {
            id: btnA
            buttontext: "A"
            textColor: "white"
            exclusiveGroup: buttonGroup //绑定到组
        }

        CheckButton {
            id: btnB
            buttontext: "B"
            textColor: "white"
            exclusiveGroup: buttonGroup //绑定到组
        }

        CheckButton {
            id: btnC
            buttontext: "C"
            textColor: "white"
            exclusiveGroup: buttonGroup //绑定到组
        }

        CheckButton {
            id: btnD
            buttontext: "D"
            textColor: "white"
            exclusiveGroup: buttonGroup //绑定到组
        }
    }
}

完整项目代码可从此处下载。

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
可以通过自定义 QQuickItem 实现自定义分割布局。具体实现步骤如下: 1. 创建一个自定义 QQuickItem,并在其内部添加子项,用于显示布局中的内容。 2. 为自定义 QQuickItem 添加属性,用于控制布局的分割位置和方向。 3. 在自定义 QQuickItem 中实现布局算法,根据分割位置和方向,计算子项的位置和大小。 4. 在 QML 中使用自定义 QQuickItem,设置其属性,即可实现自定义分割布局。 下面是一个简单的自定义分割布局示例(仅实现横向分割): ```cpp // SplitterItem.h #include <QQuickItem> class SplitterItem : public QQuickItem { Q_OBJECT Q_PROPERTY(QQuickItem* leftItem READ leftItem WRITE setLeftItem NOTIFY leftItemChanged) Q_PROPERTY(QQuickItem* rightItem READ rightItem WRITE setRightItem NOTIFY rightItemChanged) Q_PROPERTY(int splitPos READ splitPos WRITE setSplitPos NOTIFY splitPosChanged) public: SplitterItem(QQuickItem *parent = nullptr); QQuickItem* leftItem() const; void setLeftItem(QQuickItem *item); QQuickItem* rightItem() const; void setRightItem(QQuickItem *item); int splitPos() const; void setSplitPos(int pos); signals: void leftItemChanged(); void rightItemChanged(); void splitPosChanged(); protected: QSGNode* updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override; private: QQuickItem *m_leftItem; QQuickItem *m_rightItem; int m_splitPos; }; ``` ```cpp // SplitterItem.cpp #include "SplitterItem.h" #include <QSGGeometryNode> #include <QSGGeometry> #include <QSGFlatColorMaterial> SplitterItem::SplitterItem(QQuickItem *parent) : QQuickItem(parent) , m_leftItem(nullptr) , m_rightItem(nullptr) , m_splitPos(0) { setFlag(ItemHasContents, true); } QQuickItem* SplitterItem::leftItem() const { return m_leftItem; } void SplitterItem::setLeftItem(QQuickItem *item) { if (m_leftItem != item) { m_leftItem = item; emit leftItemChanged(); } } QQuickItem* SplitterItem::rightItem() const { return m_rightItem; } void SplitterItem::setRightItem(QQuickItem *item) { if (m_rightItem != item) { m_rightItem = item; emit rightItemChanged(); } } int SplitterItem::splitPos() const { return m_splitPos; } void SplitterItem::setSplitPos(int pos) { if (m_splitPos != pos) { m_splitPos = pos; emit splitPosChanged(); update(); } } QSGNode* SplitterItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { QSGGeometryNode *node = nullptr; QSGGeometry *geometry = nullptr; QSGFlatColorMaterial *material = nullptr; if (!oldNode) { node = new QSGGeometryNode; geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); geometry->setDrawingMode(GL_TRIANGLE_STRIP); node->setGeometry(geometry); material = new QSGFlatColorMaterial; node->setMaterial(material); } else { node = static_cast<QSGGeometryNode*>(oldNode); geometry = node->geometry(); material = static_cast<QSGFlatColorMaterial*>(node->material()); } QSGGeometry::Point2D *vertices = geometry->vertexDataAsPoint2D(); QRectF rect = boundingRect(); // 计算左侧和右侧子项的宽度和高度 qreal leftWidth = m_splitPos; qreal rightWidth = rect.width() - m_splitPos; qreal height = rect.height(); // 更新左侧子项的位置和大小 if (m_leftItem) { m_leftItem->setPos(0, 0); m_leftItem->setSize(QSizeF(leftWidth, height)); } // 更新右侧子项的位置和大小 if (m_rightItem) { m_rightItem->setPos(leftWidth + 1, 0); m_rightItem->setSize(QSizeF(rightWidth, height)); } // 更新分割线的位置和大小 vertices[0].set(leftWidth, 0); vertices[1].set(leftWidth, height); vertices[2].set(leftWidth + 1, 0); vertices[3].set(leftWidth + 1, height); // 设置分割线的颜色 material->setColor(Qt::gray); node->markDirty(QSGNode::DirtyGeometry); return node; } ``` 在 QML 中使用 SplitterItem: ```qml SplitterItem { width: 400 height: 300 leftItem: Rectangle { color: "red" } rightItem: Rectangle { color: "green" } splitPos: 200 } ``` 以上代码实现了一个横向分割的布局,左侧子项为红色矩形,右侧子项为绿色矩形,分割线位置为 200。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值