/*******************************************
* File: VirtualKeyboard.qml
* Describe: QML虚拟键盘组件
* Author: Xiangfu DING
* Time: 2025-02-26
*******************************************/
import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
/*
使用示例:
// 虚拟键盘
VirtualKeyboard {
id: virtualKeyboard
anchors.horizontalCenter: parent.horizontalCenter
y: parent.height-virtualKeyboard.height-35
z: 100
}
TextField {
id: digitsField
width: parent.width
placeholderText: "Digits only field"
focus: false
onFocusChanged: {
if (focus) {
virtualKeyboard.setFocusedItem(digitsField)
}
}
}
*/
// 自定义虚拟键盘
Rectangle {
id: virtualKeyboard
width: 720
height: 270
radius: 10
color: "black"
visible: false
// 焦点控件
property Item focusedItem: null
// 设置焦点控件的函数
function setFocusedItem(item) {
focusedItem = item;
isUpper = false
isEnglish = true
page = 1
virtualKeyboard.visible = true
}
property real keyWidth: (virtualKeyboard.width - keySpacing*11) / 10
property real keyHeight: (virtualKeyboard.height - keySpacing*5) / 4
property int keyRadius: 6
property int keySpacing: 10
property bool isUpper: false // 是否大写
property bool isEnglish: true // 是否英文
property int page: 1 // 字符页面
property int pixelSize: 16 // 字体大小
property var en_line1_lower: ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]
property var en_line1_upper: ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"]
property var en_line2_lower: ["a", "s", "d", "f", "g", "h", "j", "k", "l"]
property var en_line2_upper: ["A", "S", "D", "F", "G", "H", "J", "K", "L"]
property var en_line3_lower: ["z", "x", "c", "v", "b", "n", "m"]
property var en_line3_upper: ["Z", "X", "C", "V", "B", "N", "M"]
property var char_page1_line1: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]
property var char_page1_line2: ["~", "-", "+", ";", ":", "_", "=", "|", "\\"]
property var char_page1_line3: ["`", ",", ".", "<", ">", "/", "?"]
property var char_page2_line1: ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"]
property var char_page2_line2: ["[", "]", "{", "}", "'", "\"", "I", "II", "III"]
property var char_page2_line3: ["IV", "V", "VI", "VII", "VIII", "IX", "X"]
ColumnLayout {
anchors.fill: parent
anchors.topMargin: keySpacing
anchors.bottomMargin: keySpacing
Layout.leftMargin: keySpacing
Layout.rightMargin: keySpacing
spacing: keySpacing
// 第一行
Row {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width-keySpacing*2
Layout.preferredHeight: keyHeight
spacing: keySpacing
Repeater {
model: {
if (isEnglish) {
isUpper ? en_line1_upper : en_line1_lower
} else {
page == 1 ? char_page1_line1 : char_page2_line1
}
}
Rectangle {
width: keyWidth
height: parent.height
radius: keyRadius
color: area1.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area1.pressed ? "#5D4B37" : "#FFFFFF"
text: modelData
}
MouseArea {
id: area1
anchors.fill: parent
focus: false
onClicked: {
if (focusedItem) {
var cursorPos = focusedItem.cursorPosition
var currentText = focusedItem.text
focusedItem.text = currentText.slice(0, cursorPos) + modelData + currentText.slice(cursorPos)
focusedItem.cursorPosition = cursorPos + 1
}
}
}
}
}
}
// 第二行
Row {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width-keySpacing*3-keyWidth
Layout.preferredHeight: keyHeight
spacing: keySpacing
Repeater {
model: {
if (isEnglish) {
isUpper ? en_line2_upper : en_line2_lower
} else {
page == 1 ? char_page1_line2 : char_page2_line2
}
}
Rectangle {
width: keyWidth
height: parent.height
radius: keyRadius
color: area2.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area2.pressed ? "#5D4B37" : "#FFFFFF"
text: modelData
}
MouseArea {
id: area2
anchors.fill: parent
focus: false
onClicked: {
if (focusedItem) {
var cursorPos = focusedItem.cursorPosition
var currentText = focusedItem.text
focusedItem.text = currentText.slice(0, cursorPos) + modelData + currentText.slice(cursorPos)
focusedItem.cursorPosition = cursorPos + 1
}
}
}
}
}
}
// 第三行
Row {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width-keySpacing*2
Layout.preferredHeight: keyHeight
spacing: keySpacing
// shift
Rectangle {
width: keyWidth+keyWidth/2+keySpacing/2
height: parent.height
radius: keyRadius
color: area_shift.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area_shift.pressed ? "#5D4B37" : (isEnglish && isUpper ? "#239B56" : "#FFFFFF")
text: isEnglish ? "Shift" : (page == 1 ? "1/2" : "2/2")
}
MouseArea {
id: area_shift
anchors.fill: parent
focus: false
onClicked: {
if (isEnglish) {
isUpper = !isUpper
} else {
page == 1 ? (page = 2) : (page = 1)
}
}
}
}
Repeater {
model: {
if (isEnglish) {
isUpper ? en_line3_upper : en_line3_lower
} else {
page == 1 ? char_page1_line3 : char_page2_line3
}
}
Rectangle {
width: keyWidth
height: parent.height
radius: keyRadius
color: area3.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area3.pressed ? "#5D4B37" : "#FFFFFF"
text: modelData
}
MouseArea {
id: area3
anchors.fill: parent
focus: false
onClicked: {
if (focusedItem) {
var cursorPos = focusedItem.cursorPosition
var currentText = focusedItem.text
focusedItem.text = currentText.slice(0, cursorPos) + modelData + currentText.slice(cursorPos)
focusedItem.cursorPosition = cursorPos + 1
}
}
}
}
}
// backspace
Rectangle {
width: keyWidth+keyWidth/2+keySpacing/2
height: parent.height
radius: keyRadius
color: area_backspace.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area_backspace.pressed ? "#5D4B37" : "#FFFFFF"
text: "Backspace"
}
MouseArea {
id: area_backspace
anchors.fill: parent
focus: false
onClicked: {
if (focusedItem && focusedItem.text.length > 0) {
var currentText = focusedItem.text
var cursorPos = focusedItem.cursorPosition
if (cursorPos > 0) {
focusedItem.text = currentText.slice(0, cursorPos - 1) + currentText.slice(cursorPos)
focusedItem.cursorPosition = cursorPos - 1
}
}
}
}
}
}
// 第四行
Row {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: parent.width-keySpacing*2
Layout.preferredHeight: keyHeight
spacing: keySpacing
// switch
Rectangle {
width: keyWidth+keyWidth/2+keySpacing/2
height: parent.height
radius: keyRadius
color: area_switch.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area_switch.pressed ? "#5D4B37" : "#FFFFFF"
text: isEnglish ? "&123" : "ABC"
}
MouseArea {
id: area_switch
anchors.fill: parent
focus: false
onClicked: isEnglish = !isEnglish
}
}
// space
Rectangle {
width: keyWidth*5+keySpacing*4+keyWidth/2+keySpacing/2
height: parent.height
radius: keyRadius
color: area_space.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area_space.pressed ? "#5D4B37" : "#FFFFFF"
text: "空 格"
}
MouseArea {
id: area_space
anchors.fill: parent
focus: false
onClicked: {
if (focusedItem) {
var cursorPos = focusedItem.cursorPosition
var currentText = focusedItem.text
focusedItem.text = currentText.slice(0, cursorPos) + " " + currentText.slice(cursorPos)
focusedItem.cursorPosition = cursorPos + 1
}
}
}
}
// clear
Rectangle {
width: keyWidth+keyWidth/2+keySpacing/2
height: parent.height
radius: keyRadius
color: area_clear.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area_clear.pressed ? "#5D4B37" : "#FFFFFF"
text: "Clear"
}
MouseArea {
id: area_clear
anchors.fill: parent
focus: false
onClicked: {
focusedItem.text = ""
}
}
}
// hide
Rectangle {
width: keyWidth+keyWidth/2+keySpacing/2
height: parent.height
radius: keyRadius
color: area_hide.pressed ? "#2A2826" : "#383533"
Text {
anchors.fill: parent
font.pixelSize: pixelSize
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
color: area_hide.pressed ? "#5D4B37" : "#FFFFFF"
text: "收 起"
}
MouseArea {
id: area_hide
anchors.fill: parent
onClicked: {
if (focusedItem) {
focusedItem.focus = false;
}
virtualKeyboard.visible = false
}
}
}
}
}
}
Qt Quick - 自定义组件/虚拟键盘
于 2025-03-05 15:24:45 首次发布