QML 自定义ComboBox控件

        ComboBox是填充数据模型,数据模型通常是JavaScript数组,ListModel或者是整数,但是也支持其他类型的数据模型提供的属性。

        QtQuick在Qt 5.7在Controls 2.5版本给出的ComboBox,它包括一下属性:

        acceptableInput : bool 此属性控制组合框是否包含可编辑文本字段中的可接受文本
        count : int 组合框中的项目数
        currentIndex : int 保存组合框中当前项的索引,只读
        currentText : string 组合框中当前项的文本,只读
        delegate : Component 包含一个委托,该委托在组合框弹出窗口中显示项目
        displayText : string 保存组合框按钮上显示的文本
        down : bool 保存组合框按钮是否在视觉上向下
        editText : string 指示将文本保存在可编辑组合框的文本字段中
        editable : bool 控制组合框是否可编辑
        flat : bool 控制组合框按钮是否平坦
        highlightedIndex : int 表示组合框弹出列表中突出显示项的索引,,只读
        indicator : Item 包含拖放指示器项
        inputMethodComposing : bool 表示可编辑组合框是否具有部分文本输入采用某种输入方法
        inputMethodHints : flags 为输入法提供有关组合框的预期内容及其操作方式的提示
        model : model 控制着为组合框提供数据的模型
        popup : Popup 包含弹出窗口
        pressed : bool 代表组合框按钮是否以物理的方式按下
        textRole : string 表示用于填充组合框的模型角色
        validator : Validator 包含可编辑组合框的输入文本验证程序

        每次使用ComboBox时需根据自己的需求设计这些属性,而Qt给出的默认ComboBox属性样式无法满足项目需求,具体样式如下图所示:

        怎么样是不是挺丑的,黑乎乎的。要使用好看满足项目需求样式的ComboBox,就需要设计delegate、indicator、contentItem、background、popup等,分别为组合框弹出窗口的委托、下拉框指向尖括号样式、显示字样栏、背景和弹出ListView样式。自定义ComboBox重写这些样式,在同一个项目中可重复使用,自定义完成后每次只需给出字体样式、大小、颜色等即可,具体的自定义控件见如下ComboBox.qml文件:

/*
* 自定义QML CheckBox
* Since:Qt 5.7 采用QtQuick.Controls 2.12库(2.0版)
*/

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.impl 2.12
import QtQuick.Templates 2.12 as T

T.ComboBox {
    id: control;

    implicitWidth: implicitBackgroundWidth;
    implicitHeight: implicitBackgroundHeight;
    leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing);
    rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing);

    // 可在此定义多为改变的特殊属性,在调用时直接指定此属性即可
    font.pointSize: 12;
    font.family: "Microsoft YaHei";
    property color fontColor: "#999999"; // 字体颜色
    property color backgroundColor: "#E5E5E5"; // 背景色

    // 弹出框行委托
    delegate: ItemDelegate {
        width: parent.width;
        height: 30;
        // 行字体样式
        contentItem: Text {
            text: modelData;
            font: control.font;
            color: control.fontColor;
            elide: Text.ElideRight;
            verticalAlignment: Text.AlignHCenter;
            renderType: Text.NativeRendering;
        }

        palette.text: control.palette.text;
        palette.highlightedText: control.palette.highlightedText;
        font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal;
        highlighted: control.highlightedIndex === index;
        hoverEnabled: control.hoverEnabled;
    }
    // 右侧下拉箭头
    indicator: Canvas {
        id: canvas;
        x: control.width - width - control.rightPadding;
        y: control.topPadding + (control.availableHeight - height) / 2;
        width: 10;
        height: 6;
        contextType: "2d";

        Connections {
            target: control;
            onPressedChanged: canvas.requestPaint();
        }

        onPaint: {
            context.reset();
            context.moveTo(0, 0);

            context.lineWidth = 2;
            context.lineTo(width / 2, height*0.8);
            context.lineTo(width, 0);
            context.strokeStyle = control.pressed ? "#EEEFF7" : "#999999";
            context.stroke();
        }
    }

    // ComboBox的文字位置样式
    contentItem: T.TextField {
        leftPadding: !control.mirrored ? 12 : control.editable && activeFocus ? 3 : 1;
        rightPadding: control.mirrored ? 12 : control.editable && activeFocus ? 3 : 1;
        topPadding: 6 - control.padding;
        bottomPadding: 6 - control.padding;

        text: control.editable ? control.editText : control.displayText;

        enabled: control.editable;
        autoScroll: control.editable;
        readOnly: control.down;
        inputMethodHints: control.inputMethodHints;
        validator: control.validator;

        font: control.font;
        color: control.fontColor;
        //color: control.editable ? control.palette.text : control.palette.buttonText
        selectionColor: control.palette.highlight;
        selectedTextColor: control.palette.highlightedText;
        verticalAlignment: Text.AlignVCenter;
        renderType: Text.NativeRendering;

        background: Rectangle {
            visible: control.enabled && control.editable && !control.flat;
            border.width: parent && parent.activeFocus ? 2 : 1;
            border.color: parent && parent.activeFocus ? control.palette.highlight : control.palette.button;
            color: control.palette.base;
        }
    }

    // ComboBox 的背景样式
    background: Rectangle {
        implicitWidth: 120;
        implicitHeight: 30;

        radius: 3;
        color: control.enabled ? "#FFFFFF" : control.backgroundColor;
        border.color: control.backgroundColor;
        border.width: !control.editable && control.visualFocus ? 2 : 1;
        visible: !control.flat || control.down;
    }

    // 弹出窗口样式
    popup: T.Popup {
        y: control.height;
        width: control.width;
        //height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin);
        height: contentItem.implicitHeight;
        topMargin: 3;
        bottomMargin: 3;

        contentItem: ListView {
            // 防止显示过界
            clip: true;
            //禁止滑动
            // interactive: false;
            //禁用橡皮筋效果
            boundsBehavior: Flickable.StopAtBounds;

            implicitHeight: contentHeight;
            model: control.delegateModel;
            currentIndex: control.highlightedIndex;
            highlightMoveDuration: 0;

            Rectangle {
                z: 10;
                width: parent.width;
                height: parent.height;
                color: "transparent";
                border.color: control.palette.mid;
            }

            T.ScrollIndicator.vertical: ScrollIndicator { }
        }

        background: Rectangle {
            color: control.pressed ? "#EEEFF7" : control.palette.window;
            border.width: 1;
            border.color: control.backgroundColor;
            radius: 3;
        }
    }
}

自定义控件应用:

在main.qml中引入两种控件qml路径as成My,并使用此Controls具体见代码实现:

import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.12
import "myControl" as My

Window {
    visible: true;
    width: 640;
    height: 480;
    title: qsTr("自定义Control");

    My.Label {
        anchors.top: parent.top;
        anchors.topMargin: 56;
        anchors.right: comBox1.left;
        anchors.rightMargin: 15;
        text: qsTr("无样式ComboBox");
    }

    ComboBox {
        id: comBox1;
        width: 150;
        height: 30;
        anchors.top: parent.top;
        anchors.topMargin: 50;
        anchors.left: parent.left;
        anchors.leftMargin: 150;

        model: ["测试", "bug", "开发"];

        onCurrentIndexChanged: {

        }
    }

    My.Label {
        anchors.top: comBox1.bottom;
        anchors.topMargin: 56;
        anchors.right: comBox2.left;
        anchors.rightMargin: 15;
        text: qsTr("自定义ComboBox1");
    }

    My.ComboBox {
        id: comBox2;
        width: 150;
        anchors.top: comBox1.bottom;
        anchors.topMargin: 50;
        anchors.left: parent.left;
        anchors.leftMargin: 150;
        fontColor: "green";
        backgroundColor: "blue";

        model: ["冬瓜", "白菜", "西红柿"];

        onCurrentIndexChanged: {

        }
    }

    My.Label {
        anchors.top: comBox2.bottom;
        anchors.topMargin: 56;
        anchors.right: comBox3.left;
        anchors.rightMargin: 15;
        text: qsTr("自定义ComboBox2");
    }

    My.ComboBox {
        id: comBox3;
        width: 150;
        anchors.top: comBox2.bottom;
        anchors.topMargin: 50;
        anchors.left: parent.left;
        anchors.leftMargin: 150;

        model: ["苹果", "橘子", "香蕉"];

        onCurrentIndexChanged: {

        }
    }
}

自定义控件展示:

展示作者定义的浅色系ComboBox,如下运行图第三个控件:

 给出一些需要改变的小属性展示,如字体大小颜色,背景大小等,见下图第二个控件:

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值