我們將創建兩個自定義組件: 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
(鍵盤)。這兩個組件都支持等比例縮放。
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12import QtQml 2.12import QtQuick.Layouts 1.12
import "./image"import QtQuick.Layouts 1.3Window {width: 1200height: 800visible: truetitle: "可縮放彈出式數字鍵盤"color: "#f8fafc"ColumnLayout {anchors.fill: parentanchors.margins: 30spacing: 20// 標題Text {text: "可縮放彈出式數字鍵盤"font.pixelSize: 28font.bold: truecolor: "#1e293b"Layout.alignment: Qt.AlignCenter}// 示例1:基本使用NumericInputField {id: basicInputLayout.preferredWidth: 300Layout.preferredHeight: 60placeholder: "點擊輸入金額"Layout.alignment: Qt.AlignCenter}// 示例2:整數輸入NumericInputField {id: integerInputLayout.preferredWidth: 250Layout.preferredHeight: 50placeholder: "點擊輸入數量"allowDecimal: false // 禁用小數點Layout.alignment: Qt.AlignCenter}// 示例3:自定義鍵盤大小NumericInputField {id: customSizeInputLayout.preferredWidth: 350Layout.preferredHeight: 70placeholder: "點擊輸入百分比"keyboardScale: 0.7 // 鍵盤縮放比例Layout.alignment: Qt.AlignCenter}// 控制面板RowLayout {Layout.alignment: Qt.AlignCenterspacing: 20// 鍵盤縮放控制Slider {id: scaleSliderfrom: 0.5to: 1.2value: 0.8Layout.preferredWidth: 200onValueChanged: {basicInput.keyboardScale = valueintegerInput.keyboardScale = valuecustomSizeInput.keyboardScale = value}}// 縮放值顯示Text {text: "鍵盤縮放: " + scaleSlider.value.toFixed(2)font.pixelSize: 16color: "#64748b"}// 小數點開關Switch {id: decimalSwitchchecked: truetext: "允許小數點"}}// 結果展示GridLayout {columns: 3columnSpacing: 30rowSpacing: 10Layout.alignment: Qt.AlignCenterText { 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: decimalSwitchfunction onCheckedChanged() {integerInput.allowDecimal = decimalSwitch.checked}}
}
//NumericInputField
import QtQuick 2.12
import QtQuick.Controls 2.12import QtQml 2.12
import "../image"Rectangle {id: rootwidth: 300height: 60radius: 10color: "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: numericKeyboardparent: Overlay.overlay // 確保鍵盤顯示在最上層allowDecimal: root.allowDecimalvisible: false}// ===== 輸入區域 =====TextInput {id: inputFieldanchors.fill: parentanchors.margins: 15verticalAlignment: Text.AlignVCenterfont.pixelSize: 24clip: truereadOnly: true // 只能通過鍵盤輸入// 占位符文本Text {text: root.placeholderfont: inputField.fontcolor: "#9ca3af"visible: inputField.text.length === 0 && !root.activeFocusanchors.verticalCenter: parent.verticalCenter}}// ===== 鍵盤圖標 =====Rectangle {width: 40height: 40radius: 20color: "#eef2ff"anchors.verticalCenter: parent.verticalCenteranchors.right: parent.rightanchors.rightMargin: 10Text {text: "?"font.pixelSize: 24anchors.centerIn: parent}}// ===== 點擊彈出鍵盤 =====MouseArea {anchors.fill: parentonClicked: {// 設置鍵盤位置和大小numericKeyboard.width = root.width * 3 // 鍵盤比輸入框寬
// numericKeyboard.keyboardScale = keyboardScalenumericKeyboard.text = inputField.text// 打開鍵盤numericKeyboard.open()// 連接信號numericKeyboard.accepted.connect(handleAccepted)}}// ===== 鍵盤接受事件處理 =====function handleAccepted() {inputField.text = numericKeyboard.text}// ===== 鍵盤關閉時斷開連接 =====Connections {target: numericKeyboardfunction onClosed() {numericKeyboard.accepted.disconnect(handleAccepted)}}// ===== 輸入框獲得焦點樣式 =====onActiveFocusChanged: {border.color = activeFocus ? "#4f46e5" : "#d1d5db"}
}
//NumericKeyboard
import QtQuick 2.12
import QtQuick.Controls 2.12import QtGraphicalEffects 1.12
Popup {id: rootwidth: Math.min(parent.width * 0.9, 600) // 寬度自適應,最大600pxheight: width * 0.6 // 高度按比例計算anchors.centerIn: parentmodal: truedim: trueclosePolicy: 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: parentcolor: "blue"radius: 10 * scaleFactorborder.color: "#d1d5db"border.width: 1 * scaleFactor// 鍵盤陰影效果layer.enabled: truelayer.effect: DropShadow {color: "#40000000"radius: 10 * scaleFactorsamples: 21verticalOffset: 3 * scaleFactor}}// ===== 輸入框區域 =====Rectangle {id: inputContainerwidth: parent.width - 40 * scaleFactorheight: 60 * scaleFactoranchors.horizontalCenter: parent.horizontalCenteranchors.top: parent.topanchors.topMargin: 20 * scaleFactorcolor: "white"radius: 8 * scaleFactorborder.color: inputField.activeFocus ? "#4f46e5" : "#d1d5db"border.width: 2 * scaleFactor// 輸入框TextInput {id: inputFieldanchors.fill: parentanchors.margins: 15 * scaleFactorfont.pixelSize: baseFontSize * scaleFactor + 4verticalAlignment: Text.AlignVCenterclip: truereadOnly: true // 禁止直接編輯// 文本改變動畫Behavior on text {SequentialAnimation {PropertyAnimation {target: inputContainerproperty: "border.color"to: "#4f46e5"duration: 100}PropertyAnimation {target: inputContainerproperty: "border.color"to: "#d1d5db"duration: 300}}}}// 清除按鈕Rectangle {width: 30 * scaleFactorheight: 30 * scaleFactorradius: 15 * scaleFactoranchors.verticalCenter: parent.verticalCenteranchors.right: parent.rightanchors.rightMargin: 10 * scaleFactorcolor: clearMouseArea.containsPress ? "#fee2e2" : "#fef2f2"visible: inputField.text.length > 0Text {text: "×"font.pixelSize: baseFontSize * scaleFactorcolor: "#ef4444"anchors.centerIn: parent}MouseArea {id: clearMouseAreaanchors.fill: parentonClicked: inputField.text = ""}}}// ===== 鍵盤網格布局 =====Grid {id: gridanchors.top: inputContainer.bottomanchors.topMargin: 20 * scaleFactoranchors.horizontalCenter: parent.horizontalCenterspacing: 10 * scaleFactorcolumns: 5// 數字鍵1-9Repeater {model: 9KeyButton {text: index + 1width: keyWidthheight: keyHeightonClicked: inputField.insert(inputField.cursorPosition, text)}}// 小數點鍵(根據allowDecimal顯示/隱藏)KeyButton {text: "."width: keyWidthheight: keyHeightvisible: root.allowDecimalonClicked: {if (!inputField.text.includes(".")) {inputField.insert(inputField.cursorPosition, text)}}}// 數字0KeyButton {text: "0"width: keyWidthheight: keyHeightonClicked: inputField.insert(inputField.cursorPosition, text)}// 退格鍵KeyButton {text: "?"width: keyWidthheight: keyHeightbgColor: "#fecaca"textColor: "#b91c1c"onClicked: inputField.text = inputField.text.slice(0, -1)}// 取消鍵KeyButton {text: "取消"width: keyWidthheight: keyHeightbgColor: "#e5e7eb"onClicked: {root.canceled()root.close()}}// 確定鍵KeyButton {text: "確定"width: keyWidthheight: keyHeightbgColor: "#4f46e5"textColor: "white"onClicked: {root.accepted()root.close()}}}// ===== 計算按鍵尺寸 =====property real keyWidth: (root.width - 40 * scaleFactor - 2 * grid.spacing) / 6property 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
//KeyButton
import QtQuick 2.12// ===== 自定義按鈕組件 =====
Rectangle {id: btnradius: 8 * root.scaleFactorcolor: mouseArea.pressed ? Qt.darker(bgColor, 1.2) : bgColorborder.color: mouseArea.pressed ? Qt.darker(borderColor, 1.2) : borderColorborder.width: 1 * root.scaleFactor// ===== 可自定義屬性 =====property alias text: label.textproperty color bgColor: root.buttonColorproperty color textColor: "black"property color borderColor: "#d1d5db"// 按鈕文本Text {id: labelanchors.centerIn: parentfont.pixelSize: root.baseFontSize * root.scaleFactorcolor: btn.textColor}// 鼠標區域MouseArea {id: mouseAreaanchors.fill: parentonClicked: btn.clicked()}// 點擊效果動畫scale: mouseArea.pressed ? 0.95 : 1.0Behavior on scale {NumberAnimation { duration: 100 }}// 點擊信號signal clicked()
}