Qt/Qml加载侧带有文本字段并打开虚拟键盘(vkb)



目前,我正在为嵌入式Linux设备编程UI应用程序。我想在这个应用程序中使用vkb。有时,当显示vkb时,它会覆盖调用vkb的项,因此您看不到调用项。为了解决这个问题,我想制作一个输入屏幕,用户可以在其中插入他的文本。因此,屏幕上应该只有文本字段和键盘。

问题是,我找不到一种方法,如何用一个打开的键盘加载屏幕,其中键盘连接到文本字段。

当我使用打开的键盘加载屏幕时:inputPanel.state="visible";显示了vkb,但没有写入文本字段,它说";未设置输入法";

有人知道用打开的vkb加载屏幕的方法吗?

main.c

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLocale>
#include <QTranslator>
int main(int argc, char *argv[])
{
qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard"));
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "test_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
app.installTranslator(&translator);
break;
}
}
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);
return app.exec();
}

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.VirtualKeyboard 2.4
import QtQuick.VirtualKeyboard.Settings 2.13
import QtQuick.Controls 2.13
Window {
id: window
width: 640
height: 480
visible: true
title: qsTr("Hello World")

StackView {
id: pageStack
z:1
objectName: "mainStackView"
initialItem: "qrc:/KeyInputMask.qml"
anchors.fill: parent
replaceEnter: Transition {}
replaceExit: Transition {}
}
InputPanel {
id: inputPanel
z: 99
x: 0
y: window.height
width: window.width
states: State {
name: "visible"
when: inputPanel.active
PropertyChanges {
target: inputPanel
y: window.height - inputPanel.height
}
}
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 250
easing.type: Easing.InOutQuad
}
}
}
}
}

KeyInputMask.qml

import QtQuick.VirtualKeyboard 2.4
import QtQuick.VirtualKeyboard.Settings 2.13
Item {
id: keyInsertScreen
objectName: "KeyInsertScreen"
signal inputFinished(string editedReturn)
Rectangle{
id: bg
anchors.fill:parent
color: "grey"
}

TextField{
anchors{
top: bg.top
topMargin: (Window.height - inputPanel.height)/2 - height/2
left: bg.left
leftMargin: 80
}
height: 40
width: Window.width-(anchors.leftMargin*2)
wrapMode: Text.Wrap
font.pixelSize: 18
focus: true
}
Keys.onReleased: {
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter){
parent.inputFinished(inputField.text);
pageStack.pop();
}
}
Component.onCompleted: {
inputPanel.state="visible";
}
}

您应该将您的textedit、textfield、。。在Flickable中。当文本组件聚焦时,vkb弹出。如果vkb在项目上,请更改Flickable的contentY。

Qt给出了一个名为AutoScroller.qml 的例子

正常状态
vkb弹出

这是我的一个应用程序的代码:

虚拟键盘.qml

import QtQuick
import QtQuick.VirtualKeyboard 2.4
import QtQuick.VirtualKeyboard.Settings 2.2
import QtQml
import QmlGlobalParas
InputPanel {
id: __inputPanel
x: 0
y: QmlGlobalParas.appHeight

width: QmlGlobalParas.appWidth
states: [
State {
name: "visible"
when: __inputPanel.active
PropertyChanges {
target: __inputPanel
y: QmlGlobalParas.appHeight - __inputPanel.height - header.height
}
},
// 使用繁易ARM屏测试时,在切换为中文输入法时隐藏键盘,会出现中文输入的选择panel残留在显示器上的问题
// 增加inVisilble状态,在状态变为不可见时,将输入法切换为英文,以避免该问题 2021.12.08 by lxb
State {
name: "inVisible"
when: !__inputPanel.active
PropertyChanges {
target: VirtualKeyboardSettings
locale: "en_US"
}
}
]
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 50
easing.type: Easing.InOutQuad
}
}
}
AutoScroller {
}
Component.onCompleted: {
VirtualKeyboardSettings.activeLocales = ["en_US","zh_CN"]           // 设置允许的语言
VirtualKeyboardSettings.locale = "en_US"                            // 设置默认的语言
}

/*!
使用绑定方式也可以设置语言
Binding {
target: VirtualKeyboardSettings
property: "activeLocales"
value: ["en_US", "zh_CN"]
}
*/

}

AutoScroller.qml

我修改了一些代码:考虑一下中文输入法。无需滚动x轴。3可飞巢。。。

import QtQuick
import QtQuick.VirtualKeyboard
import QtQml
Item {
readonly property int chinesePanelHeight: 40            // 中文输入时,中文选择区域的高度,在style.qml中selectionListHeight定义
property var innerFlickable
property var outerFlickable
property var frameFlickable
property var inputItem: InputContext.priv.inputItem
property string inputLocal: InputContext.locale
readonly property int __defaultScrollMarginVertical: 20
onInputItemChanged: {        
innerFlickable = null
outerFlickable = null
frameFlickable = null
//        if (!Qt.inputMethod.visible)
{
if (inputItem) {
var parent_ = inputItem.parent
while (parent_) {
if (parent_.maximumFlickVelocity) {
if (outerFlickable) {
outerFlickable = null
innerFlickable = null
frameFlickable = parent_
break
} else if (innerFlickable) {
innerFlickable = null
outerFlickable = parent_
} else {
innerFlickable = parent_
}
}
parent_ = parent_.parent
}
delayedLoading.restart()
}
}
}
function ensureVisible(flickable) {
if (flickable && Qt.inputMethod.visible && inputItem && flickable.visible && flickable.interactive) {
var verticallyFlickable = (flickable.flickableDirection === Flickable.HorizontalAndVerticalFlick || flickable.flickableDirection === Flickable.VerticalFlick
|| (flickable.flickableDirection === Flickable.AutoFlickDirection && flickable.contentHeight > flickable.height))
/* 水平不需要滚动,屏蔽这部分代码
var horizontallyFlickable = (flickable.flickableDirection === Flickable.HorizontalAndVerticalFlick || flickable.flickableDirection === Flickable.HorizontalFlick
|| (flickable.flickableDirection === Flickable.AutoFlickDirection && flickable.contentWidth > flickable.width))
if ((!verticallyFlickable && !horizontallyFlickable) || !inputItem.hasOwnProperty("cursorRectangle"))
return
*/
if ((!verticallyFlickable) || !inputItem.hasOwnProperty("cursorRectangle"))
return
var cursorRectangle = flickable.contentItem.mapFromItem(inputItem, inputItem.cursorRectangle.x, inputItem.cursorRectangle.y)
var oldContentY = flickable.contentY
if (verticallyFlickable) {
var scrollMarginVertical = (flickable && flickable.scrollMarginVertical) ? flickable.scrollMarginVertical : __defaultScrollMarginVertical
if (flickable.contentY >= cursorRectangle.y  - scrollMarginVertical)
{
flickable.contentY = Math.max(0, cursorRectangle.y  - scrollMarginVertical)
}
else if (flickable.contentY + flickable.height <= cursorRectangle.y  + inputItem.cursorRectangle.height + scrollMarginVertical)
{
flickable.contentY = Math.max(flickable.contentHeight - flickable.height, cursorRectangle.y + inputItem.cursorRectangle.height - flickable.height + scrollMarginVertical)
}
}
/* 水平不需要滚动,屏蔽这部分代码
if (horizontallyFlickable) {
var scrollMarginHorizontal = (flickable && flickable.scrollMarginHorizontal) ? flickable.scrollMarginHorizontal : 10
if (flickable.contentX >= cursorRectangle.x - scrollMarginHorizontal)
flickable.contentX = Math.max(0, cursorRectangle.x - scrollMarginHorizontal)
else if (flickable.contentX + flickable.width <= cursorRectangle.x + inputItem.cursorRectangle.width + scrollMarginHorizontal)
flickable.contentX = Math.min(flickable.contentWidth - flickable.width, cursorRectangle.x + inputItem.cursorRectangle.width - flickable.width + scrollMarginHorizontal)
}
*/
}
}
function adjectVisible(flickable) {
if (flickable && flickable.contentY > 0)
{
if ("zh_CN" === inputLocal)
{
flickable.contentY += chinesePanelHeight
}
else
{
if (flickable.contentY >= chinesePanelHeight)
{
flickable.contentY -= chinesePanelHeight
}
}
}
}
Timer {
id: delayedLoading
interval: 100
onTriggered: {
ensureVisible(innerFlickable)
ensureVisible(outerFlickable)
ensureVisible(frameFlickable)
}
}
/* 如果输入法切换为中文,且内部高度 */
onInputLocalChanged: {
adjectVisible(frameFlickable)
adjectVisible(outerFlickable)
adjectVisible(innerFlickable)
}
Connections {
ignoreUnknownSignals: true
target: Qt.inputMethod
function onAnimatingChanged() {
if (inputItem && !Qt.inputMethod.animating)
{
delayedLoading.restart()
}
}
function onKeyboardRectangleChanged() {
if (inputItem)
{
delayedLoading.restart()
}
}
function onCursorRectangleChanged() {
if (inputItem && inputItem.activeFocus && !Qt.inputMethod.visible)
{
delayedLoading.restart()
}
}
}
}

这里有一种方法"pin";您当前输入的内容。请注意,这有点刺耳,但很快就举了一个例子。

InputPanel {
id: vkbPanel
z: 99
x: 0
y: window.height
width: window.width
states: State {
name: "visible"
when: vkbPanel.active
PropertyChanges {
target: vkbPanel
y: window.height - vkbPanel.height
}
}
transitions: Transition {
from: ""
to: "visible"
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 250
easing.type: Easing.InOutQuad
}
}
}
TextInput{
id: inputSuperclass
inputMethodHints: Qt.ImhFormattedNumbersOnly
focus: Qt.inputMethod.visible // <---!!! This line is very important
}
Label{
text: inputSuperclass.text
anchors{
bottom: vkbPanel.top
horizontalCenter: vkbPanel.horizontalCenter
}
color: '#ffffff'
}
}

确保你创建了各种各样的文本输入来满足你的需求——我只有"ImhFormattedNumbersOnly;实施。因此,如果您需要其他输入方法,则需要复制并粘贴此解决方案,但使用不同的inputMethodHint。

最新更新