实现一个点击输入框可以弹出的数字软键盘控件 qt 5.12

我们将创建两个自定义组件: 1. `NumericInputField`:一个输入框,当点击时弹出数字键盘。 2. `NumericKeyboard`:一个可缩放的数字键盘。 设计思路: - `NumericInputField` 是一个常规的输入框,但点击后会弹出 `NumericKeyboard`。 - `NumericKeyboard` 是一个弹出式键盘,它的大小可以等比例缩放(通过设置宽度,高度按比例计算)。 - 键盘内部包含数字0-9、小数点、退格、取消和确定按钮。 - 键盘的尺寸和字体大小都可以通过属性设置。 步骤: 1. 创建 `NumericKeyboard` 组件。 2. 创建 `NumericInputField` 组件,它包含一个 `TextInput` 和一个弹出键盘的机制。 3. 在 `NumericInputField` 中,当点击输入框时,显示 `NumericKeyboard`,并将键盘与输入框的位置关联(例如在输入框下方弹出)。 注意:为了支持等比例缩放,键盘的宽度可以设置,高度则根据宽度按比例计算(例如高度是宽度的0.6倍)。键盘内部的按钮大小和字体大小也根据键盘的当前尺寸进行缩放。 由于要求每个自定义组件的代码,我们将分别实现: 组件一:NumericKeyboard.qml 组件二:NumericInputField.qml 然后提供一个使用示例。

可缩放弹出式数字软键盘组件

下面我将实现一个完整的可缩放弹出式数字软键盘组件,包含两个自定义组件:NumericInputField(输入框)和 NumericKeyboard(键盘)。这两个组件都支持等比例缩放。

cpp 复制代码
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
 import QtQml 2.12
 import QtQuick.Layouts 1.12
import "./image"

import QtQuick.Layouts 1.3

Window {
    width: 1200
    height: 800
    visible: true
    title: "可缩放弹出式数字键盘"
    color: "#f8fafc"

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 30
        spacing: 20

        // 标题
        Text {
            text: "可缩放弹出式数字键盘"
            font.pixelSize: 28
            font.bold: true
            color: "#1e293b"
            Layout.alignment: Qt.AlignCenter
        }

        // 示例1:基本使用
        NumericInputField {
            id: basicInput
            Layout.preferredWidth: 300
            Layout.preferredHeight: 60
            placeholder: "点击输入金额"
            Layout.alignment: Qt.AlignCenter
        }

        // 示例2:整数输入
        NumericInputField {
            id: integerInput
            Layout.preferredWidth: 250
            Layout.preferredHeight: 50
            placeholder: "点击输入数量"
            allowDecimal: false // 禁用小数点
            Layout.alignment: Qt.AlignCenter
        }

        // 示例3:自定义键盘大小
        NumericInputField {
            id: customSizeInput
            Layout.preferredWidth: 350
            Layout.preferredHeight: 70
            placeholder: "点击输入百分比"
            keyboardScale: 0.7 // 键盘缩放比例
            Layout.alignment: Qt.AlignCenter
        }

        // 控制面板
        RowLayout {
            Layout.alignment: Qt.AlignCenter
            spacing: 20

            // 键盘缩放控制
            Slider {
                id: scaleSlider
                from: 0.5
                to: 1.2
                value: 0.8
                Layout.preferredWidth: 200

                onValueChanged: {
                    basicInput.keyboardScale = value
                    integerInput.keyboardScale = value
                    customSizeInput.keyboardScale = value
                }
            }

            // 缩放值显示
            Text {
                text: "键盘缩放: " + scaleSlider.value.toFixed(2)
                font.pixelSize: 16
                color: "#64748b"
            }

            // 小数点开关
            Switch {
                id: decimalSwitch
                checked: true
                text: "允许小数点"
            }
        }

        // 结果展示
        GridLayout {
            columns: 3
            columnSpacing: 30
            rowSpacing: 10
            Layout.alignment: Qt.AlignCenter

            Text { text: "金额:"; font.bold: true; color: "#475569" }
            Text { text: basicInput.text || "0.00"; color: "#334155" }
            Text { text: "缩放: " + basicInput.keyboardScale.toFixed(2); color: "#64748b" }

            Text { text: "数量:"; font.bold: true; color: "#475569" }
            Text { text: integerInput.text || "0"; color: "#334155" }
            Text { text: "缩放: " + integerInput.keyboardScale.toFixed(2); color: "#64748b" }

            Text { text: "百分比:"; font.bold: true; color: "#475569" }
            Text { text: customSizeInput.text || "0.00"; color: "#334155" }
            Text { text: "缩放: " + customSizeInput.keyboardScale.toFixed(2); color: "#64748b" }
        }
    }

    // 应用键盘设置
    Component.onCompleted: {
        integerInput.allowDecimal = decimalSwitch.checked
    }

    // 小数点开关变化
    Connections {
        target: decimalSwitch
        function onCheckedChanged() {
            integerInput.allowDecimal = decimalSwitch.checked
        }
    }
}
cpp 复制代码
//NumericInputField
import QtQuick 2.12
import QtQuick.Controls 2.12
 import QtQml 2.12
import "../image"


Rectangle {
    id: root
    width: 300
    height: 60
    radius: 10
    color: "white"
    border.color: root.activeFocus ? "#4f46e5" : "#d1d5db"
    border.width: 2

    // ===== 公共属性 =====
    property alias text: inputField.text       // 输入文本
    property string placeholder: "点击输入"    // 占位符文本
    property real keyboardScale: 0.4          // 键盘缩放比例
    property bool allowDecimal: true          // 是否允许小数点

    // ===== 键盘实例 =====
    property NumericKeyboard keyboard: NumericKeyboard {
        id: numericKeyboard
        parent: Overlay.overlay // 确保键盘显示在最上层
        allowDecimal: root.allowDecimal
        visible: false

    }

    // ===== 输入区域 =====
    TextInput {
        id: inputField
        anchors.fill: parent
        anchors.margins: 15
        verticalAlignment: Text.AlignVCenter
        font.pixelSize: 24
        clip: true
        readOnly: true // 只能通过键盘输入

        // 占位符文本
        Text {
            text: root.placeholder
            font: inputField.font
            color: "#9ca3af"
            visible: inputField.text.length === 0 && !root.activeFocus
            anchors.verticalCenter: parent.verticalCenter
        }
    }

    // ===== 键盘图标 =====
    Rectangle {
        width: 40
        height: 40
        radius: 20
        color: "#eef2ff"
        anchors.verticalCenter: parent.verticalCenter
        anchors.right: parent.right
        anchors.rightMargin: 10

        Text {
            text: "⌨"
            font.pixelSize: 24
            anchors.centerIn: parent
        }
    }

    // ===== 点击弹出键盘 =====
    MouseArea {
        anchors.fill: parent
        onClicked: {
            // 设置键盘位置和大小
            numericKeyboard.width = root.width * 3 // 键盘比输入框宽
//            numericKeyboard.keyboardScale = keyboardScale
            numericKeyboard.text = inputField.text

            // 打开键盘
            numericKeyboard.open()

            // 连接信号
            numericKeyboard.accepted.connect(handleAccepted)
        }
    }

    // ===== 键盘接受事件处理 =====
    function handleAccepted() {
        inputField.text = numericKeyboard.text
    }

    // ===== 键盘关闭时断开连接 =====
    Connections {
        target: numericKeyboard
        function onClosed() {
            numericKeyboard.accepted.disconnect(handleAccepted)
        }
    }

    // ===== 输入框获得焦点样式 =====
    onActiveFocusChanged: {
        border.color = activeFocus ? "#4f46e5" : "#d1d5db"
    }
}
cpp 复制代码
//NumericKeyboard
import QtQuick 2.12
import QtQuick.Controls 2.12
 import QtGraphicalEffects 1.12
Popup {
    id: root
    width: Math.min(parent.width * 0.9, 600)  // 宽度自适应,最大600px
    height: width * 0.6  // 高度按比例计算
    anchors.centerIn: parent
    modal: true
    dim: true
    closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside

    // ===== 公共属性 =====
    property alias text: inputField.text      // 绑定输入文本
    property bool allowDecimal: true         // 是否允许小数点
    property real scaleFactor: width / 600   // 缩放因子(基于600px基准)
    property int baseFontSize: 24            // 基准字体大小
    property color buttonColor: "#f0f0f0"    // 按钮默认颜色

    // ===== 信号 =====
    signal accepted()  // 点击确定时触发
    signal canceled() // 点击取消时触发

    // ===== 键盘背景 =====
    background: Rectangle {
        anchors.fill: parent
        color: "blue"
        radius: 10 * scaleFactor
        border.color: "#d1d5db"
        border.width: 1 * scaleFactor

        // 键盘阴影效果
        layer.enabled: true
        layer.effect: DropShadow {
            color: "#40000000"
            radius: 10 * scaleFactor
            samples: 21
            verticalOffset: 3 * scaleFactor
        }
    }

    // ===== 输入框区域 =====
    Rectangle {
        id: inputContainer
        width: parent.width - 40 * scaleFactor
        height: 60 * scaleFactor
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: parent.top
        anchors.topMargin: 20 * scaleFactor
        color: "white"
        radius: 8 * scaleFactor
        border.color: inputField.activeFocus ? "#4f46e5" : "#d1d5db"
        border.width: 2 * scaleFactor

        // 输入框
        TextInput {
            id: inputField
            anchors.fill: parent
            anchors.margins: 15 * scaleFactor
            font.pixelSize: baseFontSize * scaleFactor + 4
            verticalAlignment: Text.AlignVCenter
            clip: true
            readOnly: true // 禁止直接编辑

            // 文本改变动画
            Behavior on text {
                SequentialAnimation {
                    PropertyAnimation {
                        target: inputContainer
                        property: "border.color"
                        to: "#4f46e5"
                        duration: 100
                    }
                    PropertyAnimation {
                        target: inputContainer
                        property: "border.color"
                        to: "#d1d5db"
                        duration: 300
                    }
                }
            }
        }

        // 清除按钮
        Rectangle {
            width: 30 * scaleFactor
            height: 30 * scaleFactor
            radius: 15 * scaleFactor
            anchors.verticalCenter: parent.verticalCenter
            anchors.right: parent.right
            anchors.rightMargin: 10 * scaleFactor
            color: clearMouseArea.containsPress ? "#fee2e2" : "#fef2f2"
            visible: inputField.text.length > 0

            Text {
                text: "×"
                font.pixelSize: baseFontSize * scaleFactor
                color: "#ef4444"
                anchors.centerIn: parent
            }

            MouseArea {
                id: clearMouseArea
                anchors.fill: parent
                onClicked: inputField.text = ""
            }
        }
    }

    // ===== 键盘网格布局 =====
    Grid {
        id: grid
        anchors.top: inputContainer.bottom
        anchors.topMargin: 20 * scaleFactor
        anchors.horizontalCenter: parent.horizontalCenter
        spacing: 10 * scaleFactor
        columns: 5

        // 数字键1-9
        Repeater {
            model: 9
            KeyButton {
                text: index + 1
                width: keyWidth
                height: keyHeight
                onClicked: inputField.insert(inputField.cursorPosition, text)
            }
        }

        // 小数点键(根据allowDecimal显示/隐藏)
        KeyButton {
            text: "."
            width: keyWidth
            height: keyHeight
            visible: root.allowDecimal
            onClicked: {
                if (!inputField.text.includes(".")) {
                    inputField.insert(inputField.cursorPosition, text)
                }
            }
        }

        // 数字0
        KeyButton {
            text: "0"
            width: keyWidth
            height: keyHeight
            onClicked: inputField.insert(inputField.cursorPosition, text)
        }

        // 退格键
        KeyButton {
            text: "⌫"
            width: keyWidth
            height: keyHeight
            bgColor: "#fecaca"
            textColor: "#b91c1c"
            onClicked: inputField.text = inputField.text.slice(0, -1)
        }

        // 取消键
        KeyButton {
            text: "取消"
            width: keyWidth
            height: keyHeight
            bgColor: "#e5e7eb"
            onClicked: {
                root.canceled()
                root.close()
            }
        }

        // 确定键
        KeyButton {
            text: "确定"
            width: keyWidth
            height: keyHeight
            bgColor: "#4f46e5"
            textColor: "white"
            onClicked: {
                root.accepted()
                root.close()
            }
        }
    }

    // ===== 计算按键尺寸 =====
    property real keyWidth: (root.width - 40 * scaleFactor - 2 * grid.spacing) / 6
    property real keyHeight: keyWidth * 0.8



    // ===== 弹出动画 =====
    enter: Transition {
        ParallelAnimation {
            NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 300 }
            NumberAnimation { property: "scale"; from: 0.8; to: 1; duration: 300; easing.type: Easing.OutBack }
        }
    }

    // ===== 关闭动画 =====
    exit: Transition {
        ParallelAnimation {
            NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 300 }
            NumberAnimation { property: "scale"; from: 1; to: 0.8; duration: 300 }
        }
    }
}
复制代码
KeyButton
cpp 复制代码
//KeyButton
import QtQuick 2.12

// ===== 自定义按钮组件 =====
Rectangle {
    id: btn
    radius: 8 * root.scaleFactor
    color: mouseArea.pressed ? Qt.darker(bgColor, 1.2) : bgColor
    border.color: mouseArea.pressed ? Qt.darker(borderColor, 1.2) : borderColor
    border.width: 1 * root.scaleFactor

    // ===== 可自定义属性 =====
    property alias text: label.text
    property color bgColor: root.buttonColor
    property color textColor: "black"
    property color borderColor: "#d1d5db"

    // 按钮文本
    Text {
        id: label
        anchors.centerIn: parent
        font.pixelSize: root.baseFontSize * root.scaleFactor
        color: btn.textColor
    }

    // 鼠标区域
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        onClicked: btn.clicked()
    }

    // 点击效果动画
    scale: mouseArea.pressed ? 0.95 : 1.0
    Behavior on scale {
        NumberAnimation { duration: 100 }
    }

    // 点击信号
    signal clicked()
}
相关推荐
nbsaas-boot41 分钟前
Java 正则表达式白皮书:语法详解、工程实践与常用表达式库
开发语言·python·mysql
chao_7891 小时前
二分查找篇——搜索旋转排序数组【LeetCode】两次二分查找
开发语言·数据结构·python·算法·leetcode
风无雨1 小时前
GO 启动 简单服务
开发语言·后端·golang
斯普信专业组1 小时前
Go语言包管理完全指南:从基础到最佳实践
开发语言·后端·golang
哈市雪花3 小时前
相机:以鼠标点为中心缩放(使用OpenGL+QT开发三维CAD)
qt·相机·opengl·cad·缩放·工业软件·渲染效果
我是苏苏3 小时前
C#基础:Winform桌面开发中窗体之间的数据传递
开发语言·c#
sun0077003 小时前
mysql索引底层原理
数据库·mysql
斐波娜娜3 小时前
Maven详解
java·开发语言·maven
小码氓4 小时前
Java填充Word模板
java·开发语言·spring·word
暮鹤筠4 小时前
[C语言初阶]操作符
c语言·开发语言