在QML中,当有一个按键按下或释放时,会产生一个键盘事件,将其传递给获得有焦点的QML项目(讲focus属性设置为true,则获得焦点)。
按键处理的基本流程:
- Qt接收密钥操作并生成密钥事件。
- 如果 QQuickWindow 是活动窗口,则密钥事件将传递给它。
- 关键事件由场景传递到具有活动焦点的项目。如果没有项目具有活动焦点,则忽略关键事件。
- 如果具有活动焦点的 QQuickItem 接受密钥事件,则传播将停止。否则,事件将发送到项的父项,直到接受该事件或到达根项。
附加属性所有可视基元都支持Keys 附加属性进行键的处理。
信号属性击具有一个KeyEvent参数,参数名为event,通过event来处理键。
处理完事件后,可以设置event.accepted:true,防止事件在项目层次结构中向上传播
常用属性:
enable | 是否启动(默认true) |
forwardTo:list<item> | 将事件转发到其他列表 |
priority | 优先级 Keys.BeforeItem (默认)在正常项键处理之前处理键事件。如果事件被接受,它将不会传递给该项目。 Keys.AfterItem 在正常项键处理之后处理键事件。如果该项接受键事件,则不会由键附加属性处理程序处理它。 |
优先级处理顺序:
Keys.BeforeItem
- 中指定的项目forwaTo
- 特定的键处理程序,例如 onReturnPressed
- onPressed, onRelease的处理程序
- 项目特定的键处理,例如文本输入键处理
- 父项
如果优先级为 Keys.AfterItem 则键事件处理的顺序为:
- 项目特定的键处理,例如文本输入键处理
- 中指定的项目forwardTo
- 特定的键处理程序,例如 onReturnPressed
- onPressed, onRelease的处理程序
- 父项
信号:
asteriskPressed | * 被按下时会发出此信号 |
backPressed | 按下后退键时会发出此信号 |
backtabPressed | 当按下 Shift+Tab 组合键(后退选项卡)时,将发出此信号 |
callPressed | 按下呼叫键时会发出此信号 |
cancelPressed | 按下取消键时会发出此信号 |
context1Pressed | 按下 Context1 键时会发出此信号 |
context2Pressed | 按下 Context2 键时会发出此信号 |
context3Pressed | 按下 Context3 键时会发出此信号 |
context4Pressed | 按下 Context4 键时会发出此信号 |
deletePressed | 按下 Delete 键时会发出此信号 |
digit0Pressed | 当按下数字“0”时,会发出此信号 |
digit1Pressed | 当按下数字“1”时,会发出此信号 |
digit2Pressed | 当按下数字“2”时,会发出此信号 |
digit3-8 | |
digit9Pressed | 当按下数字“9”时,会发出此信号 |
downPressed | 按下向下箭头时会发出此信号 |
enterPressed | 按下 Enter 键时会发出此信号 |
escapePressed | 按下 Esc 键时会发出此信号 |
flipPressed | 按下翻转键时会发出此信号。 |
hangupPressed | 按下挂断键时会发出此信号 |
leftPressed | 按下向左箭头时会发出此信号 |
menuPressed | 按下菜单键时会发出此信号 |
noPressed | 按下 No 键时发出此信号 |
pressed | 按下某个键时会发出此信号 |
released | 释放密钥后会发出此信号 |
returnPressed | 按下回车键时会发出此信号 |
rightPressed | 按下向右箭头时发出此信号 |
selectPressed | 按下选择键时会发出此信号 |
shortcutOverride | 当按下可能用作快捷方式的键时 |
spacePressed | 按下空格键时会发出此信号 |
tabPressed | 按下 Tab 键时会发出此信号 |
upPressed | 按下向上箭头时会发出此信号 |
volumeDownPressed | 按下音量调低键时会发出此信号 |
volumeUpPressed | 按下音量调高键时会发出此信号 |
yesPressed | 按下“是”键时发出此信号 |
按下任意键,图像向右下角移动:
Rectangle{
id:rect1
width: 100;height: 100
x:0;y:0
color: "red"
focus: true//获取焦点
Keys.onPressed: {//按下任意键时
rect1.x+=50//x的位置+50
rect1.y+=50//y的位置+50
event.accepted=true//设置为已处理
}
}
按下不同的键执行不同的命令:
按下向上键,向上移动10
按下向下键,向下移动10
按下向左键,向左移动10
按下向右键,向右移动10
Rectangle{
id:rect1
width: 100;height: 100
x:100;y:100
color: "red"
focus: true//获取焦点
Keys.onPressed: {//按下任意键时
if(event.key==Qt.Key_Left)
rect1.x-=10;
else if(event.key==Qt.Key_Right)
rect1.x+=10
else if(event.key==Qt.Key_Up)
rect1.y-=10
else if(event.key==Qt.Key_Down)
rect1.y+=10
else{
}
event.accepted=true
}
}
KeyNavigation(按键导航)
基于键的用户界面通常允许使用箭头键在可聚焦项目之间导航。KeyNavigation 附加属性通过提供一种方便的方法来指定在按下箭头或 Tab 键时应获得焦点的项,从而实现此行为。
常见的属性:
backtab | 此属性保存按下 Shift+Tab 组合键(后退表)时要为其分配焦点的项目 |
down | 此属性保存按下向下光标键时要为其分配焦点的项 |
left | 此属性保存按下左光标键时要为其分配焦点的项目 |
right | 此属性保存按下右光标键时要为其分配焦点的项目。 |
tab | 此属性保存按下 Tab 键时要为其分配焦点的项。 |
up | 此属性保存按下向上光标键时要为其分配焦点的项 |
使用Tab键切换:
Row{
x:50;y:50
spacing: 25
Rectangle{
id:rect1
width: 100;height: 100
radius: 10
KeyNavigation.tab: rect2//按tab键,跳转到rect2
focus: true //默认rect1获取焦点
color:focus?"red":"lightgray"//获取焦点时为红色,没获取焦点时为灰色
scale: focus?1:0.8//当没获取焦点时大小为0.8倍
Text{
anchors.centerIn: parent
color: parent.focus?"black":"gray"
font.pointSize: 20
text:"矩形1"
}
}
Rectangle{
id:rect2
width: 100;height: 100
radius: 10
KeyNavigation.tab: rect3//按tab键,跳转到rect3
color:focus?"green":"lightgray"//获取焦点时为绿色,没获取焦点时为灰色
scale: focus?1:0.8//当没获取焦点时大小为0.8倍
Text{
anchors.centerIn: parent
color: parent.focus?"black":"gray"
font.pointSize: 20
text:"矩形2"
}
}
Rectangle{
id:rect3
width: 100;height: 100
radius: 10
KeyNavigation.tab: rect1//按tab键,跳转到rect1
color:focus?"blue":"lightgray"//获取焦点时为蓝色,没获取焦点时为灰色
scale: focus?1:0.8//当没获取焦点时大小为0.8倍
Text{
anchors.centerIn: parent
color: parent.focus?"black":"gray"
font.pointSize: 20
text:"矩形3"
}
}
}
Shortcut (快捷键)
快捷键类型提供了一种处理键盘快捷键的方法。快捷键可以设置为标准键盘快捷键之一,也可以使用包含激活快捷键所需的最多四次按键序列的字符串来描述。
属性:
sequence | 此属性保存快捷方式的键序列。键序列可以设置为标准键盘快捷键之一,也可以使用包含激活快捷键所需的最多四次按键序列的字符串来描述。 |
sequences:list<> | 此属性包含快捷方式的多个键序列 |
enable | 是否启动该功能 |
portableText | 此属性以“可移植”格式的字符串形式提供快捷方式的键序列 |
nativeText | 此属性将快捷方式的键序列作为特定于平台的字符串提供。这意味着它将被翻译显示 |
autoRepeat | 此属性保存快捷方式是否可以自动重复(默认true) |
context:enumeration(上下文)
Qt.WindowShortcut | 当快捷方式的父项位于活动的顶级窗口中时,快捷方式处于活动状态(默认) |
Qt.ApplicationShortcut | 当应用程序的某个窗口处于活动状态时,快捷方式处于活动状态 |
信号:
activated | 激活时 |
activatedAmbiguously | 当快捷方式被模糊地激活时,会发出此信号,这意味着它与多个快捷方式的开头匹配 |
快捷键创建格式:
- sequence: "Ctrl+E" 按下Ctrl +E
- sequence:"Ctrl+E,Ctrl+W" 先按下Ctrl+E 然后再按下Ctrl+W
- sequences:["Ctrl+E","Ctrl+W"] 按下Ctrl+E 或 Ctrl+W
简单的使用:
Rectangle{
Shortcut{
sequence: "Ctrl+E"
onActivated:
console.log("已按下Ctrl+E")
}
}
Rectangle{
Shortcut{
sequence: "Ctrl+E,Ctrl+W"
onActivated:
console.log("已按下Ctrl+E+Ctrl+W")
}
}
需要先按下Ctrl+E 再按下Ctrl+W才能触发
Rectangle{
Shortcut{
sequences: ["Ctrl+E","Ctrl+W"]
onActivated:
console.log("已按下Ctrl+E或Ctrl+W")
}
}
按下Ctrl+E或按下Ctrl+W
activated和activatedAmbiguously的区别
- activated 只能由于单个Shotcut的触发
- activatedAmbiguously 可以用于快捷键被多个Shotcut触发
当快捷键被多个Shotcut触发时,activated不触发
Rectangle{
Shortcut{
id:s1
sequence:"Ctrl+E"
onActivated:
console.log("s1已按下Ctrl+E")
}
Shortcut{
id:s2
sequence:"Ctrl+E"
onActivated:
console.log("s2已按下Ctrl+E")
}
}
当快捷键被多个Shotcut触发时,activatedAmbiguously触发
触发规则:
- 优先触发后面创建的Shortcut对象
- 一次只触发一个对象
Rectangle{
Shortcut{
id:s1
sequence:"Ctrl+E"
onActivatedAmbiguously:
console.log("s1已按下Ctrl+E")
}
Shortcut{
id:s2
sequence:"Ctrl+E"
onActivatedAmbiguously:
console.log("s2已按下Ctrl+E")
}
Shortcut{
id:s3
sequence:"Ctrl+E"
onActivatedAmbiguously:
console.log("s3已按下Ctrl+E")
}
}
按下3次Ctrl+E
Keys中的快捷键覆盖:
使用 onShortcutOverride
当没有快捷键覆盖时:
Rectangle{
id:rect1
focus:true
Keys.onEscapePressed:{
console.log("Keys.Escape")
}
}
Shortcut{
sequence: "Escape"
onActivated: {
console.log("Shortcut.Escape")
}
}
使用快捷键覆盖:
Rectangle{
id:rect1
focus:true
Keys.onShortcutOverride: event.accepted=(event.key==Qt.Key_Escape)
Keys.onEscapePressed:{
console.log("Keys.Escape")
}
}
Shortcut{
sequence: "Escape"
onActivated: {
console.log("Shortcut.Escape")
}
}
控件与焦点:
判断是否为活动焦点:
使用activeFocus来判断是否获取焦点
当有多个控件需要焦点时的处理:(Qt 5.9.9版本下)
子控件:文件名为:Mywidget.qml
import QtQuick 2.9
Rectangle{
id:rect1
color: "lightsteelblue"; width: 175; height: 25; radius: 10; antialiasing: true
Text { id: label1; anchors.centerIn: parent}
focus: true
Keys.onPressed: {
if (event.key == Qt.Key_A)
label1.text = 'Key A was pressed'
}
}
主控件: 在Window中添加
Rectangle{
width: 300;height:300;x:100;y:100;color: "lightBlue"
focus: true//设置焦点
Column{
spacing:25
Mywidget{ }
Mywidget{ }
}
}
运行的话子控件不会接收焦点
在第一个子控件中添加焦点
Rectangle{
width: 300;height:300;x:100;y:100;color: "lightBlue"
Column{
spacing:25
Mywidget{ focus: true }
Mywidget{ }
}
}
运行结果:第一个控件响应键盘事件
第二个子控件中添加焦点 :
Rectangle{
width: 300;height:300;x:100;y:100;color: "lightBlue"
Column{
spacing:25
Mywidget{ }
Mywidget{ focus: true}
}
}
运行结果为:还是第一个子控件获取键盘事件
当两个子控件都设置焦点:
Rectangle{
width: 300;height:300;x:100;y:100;color: "lightBlue"
Column{
spacing:25
Mywidget{ focus: true }
Mywidget{ focus: true }
}
}
运行结果还是第一个子控件获取键盘事件
由此可见:当有多个组件设置了焦点时,最终只有一种类型可以具有键盘焦点,系统必需决定哪种类型获取焦点。此问题是由于可见性造成的。组件希望具有焦点,但在导入或重用是无法控制焦点。同样,组件无法知道其导入的组件是否正在请求焦点。
为了解决这个问题QML引入了焦点范围的概念:
FocusScope(焦点范围)
- 在每个焦点范围内,一个对象可能已设置为 。如果设置了多个 Item 属性,则要设置的最后一个类型将具有焦点,而其他类型将未设置,类似于没有焦点范围的情况。
- 当焦点范围收到活动焦点时,包含的已设置类型(如果有)也会获取活动焦点。如果此类型也是焦点范围,则代理行为将继续。焦点范围和子焦点项都将设置属性。
- FocusScope 类型不是视觉对象类型,因此需要向 FocusScope 的父项公开其子项的属性
例子:实现使用鼠标点击切换焦点
子控件:
FocusScope {
id: scope
//公开子项的属性
property alias color: rectangle.color
x: rectangle.x; y: rectangle.y
width: rectangle.width; height: rectangle.height
Rectangle {
id: rectangle
anchors.centerIn: parent
color: "lightsteelblue"; width: 175; height: 25; radius: 10; antialiasing: true
Text { id: label; anchors.centerIn: parent }
focus: true
Keys.onPressed: {
if (event.key == Qt.Key_A)
label.text = 'Key A was pressed'
}
//鼠标点击获取焦点
MouseArea { anchors.fill: parent; onClicked: { scope.focus = true } }
}
}
主控件:
Rectangle{
width: 300;height:300;x:100;y:100;color: "lightBlue"
Column{
spacing:25
Mywidget{focus: true }
Mywidget{ }
}
}
运行结果:
1.按下A键
2.鼠标点击第二个子控件,再按下A键
使用FocusScope设计一个登录界面。
标签和输入框的设计:
import QtQuick 2.9
FocusScope{
property alias label:label.text
Row{
spacing: 10
Text{
id:label
text:"标签"
}
Rectangle{
width:100
height: 20
color: "white"
border.color: "gray"
TextInput{
id:input
anchors.fill: parent//充满整个矩形
anchors.margins: 4 //设置边距
focus: true;//获取焦点
}
}
}
}
主窗口显示:
Rectangle{
anchors.fill: parent
property alias mouseArea: mouseArea
focus: true
color: "lightgray"
MouseArea{
id:mouseArea
anchors.fill:parent//充满整个矩形
}
Mywidget{
id:widget1;x:100;y:100
label:"账号"//设置标签
KeyNavigation.tab:widget2
}
Mywidget{
x:100
y:150
id:widget2;
label: "密码"//设置标签
KeyNavigation.tab:widget1
}
}
运行效果:
参考文档:
Keyboard Focus in Qt Quick | Qt Quick 5.15.12
Keys QML Type | Qt Quick 5.15.12