我正在创建一个 QML ListView
支持多项选择,并将在我的应用程序中实例化其中的多个。我需要将键盘焦点赋予特定列表,处理该列表的按键,并根据焦点突出显示所选行。
但是,给予focus=true
ListView 委托(delegate)或 ListView 本身不会导致 activeFocus
出现在 ListView 上,并且不会导致按键信号被触发。
我创建了一个简单的示例应用程序来显示我的问题:
import QtQuick 2.7
import QtQuick.Window 2.0
Window {
id:window; visible:true; width:400; height:160; color:'darkgray'
Component {
id: row
Rectangle {
id: root
property int i: index
property bool current: ListView.isCurrentItem
property bool focused: ListView.view.activeFocus
width:parent.width; height:20
color: current ? ( focused ? 'pink' : 'lightblue' ) : 'lightgray'
MouseArea {
anchors.fill: parent
onClicked: {
root.ListView.view.currentIndex = i;
root.ListView.view.focus = true;
}
}
Text { anchors.fill:parent; text:modelData }
}
}
Component {
id: myList
ListView {
delegate: row
width:window.width/2-10; height:window.height; y:5
Keys.onUpPressed: decrementCurrentIndex()
Keys.onDownPressed: incrementCurrentIndex()
}
}
Loader {
sourceComponent:myList; x:5
onLoaded: item.model = ['a','b','c','d']
}
Loader {
sourceComponent:myList; x:window.width/2
onLoaded: item.model = ['1','2','3','4','5']
}
}
单击任一列表不会将所选行变成粉红色,并且按向上/向下键不会调整选择。
如何将焦点传递到特定的 ListView
这样(a)一次只有一个 ListView 持有它,(b)我可以检测到 ListView 何时持有此焦点,(c)它允许键盘信号仅在聚焦时为该 ListView 工作?
我正在使用 Qt 5.7,以防万一。
<小时/>我尝试过但不成功的事情:
- 设置
focus=true
在 Rectangle 而不是 ListView 上。 - 设置
focused
值得关注的特性ListView.view.focus
而不是activeFocus
:这允许两个列表同时变成粉红色。 通读Keyboard Focus in Qt Quick并将 Rectangle 或 ListView 包装在
FocusScope
中。 (转发所有接口(interface)是多么痛苦的事情。)在白天重读该页面并将两个包装起来
Loader
在一个FocusScope
。咒骂,因为两个 ListView 显然都可以同时获得焦点,这违反了我对文档这一部分的阅读:Within each focus scope one object may have
Item::focus
set to true. If more than one Item has thefocus
property set, the last type to set the focus will have thefocus
and the others are unset, similar to when there are no focus scopes.
将 ListView 包装在一个项目中,并将 Keys 处理程序放在该项目上,并尝试聚焦该项目。
- 设置
interactive:false
在 ListView 上。 - 设置
keyNavigationEnabled:false
在 ListView 上。 (这奇怪地产生"ListView.keyNavigationEnabled" is not available in QtQuick 2.7
,尽管帮助声明它是在 5.7 中引入的,并表明 QtQuick 2.7 是正确的导入语句。) - 推杆
focus:true
以防万一,几乎在我能找到的所有物体上。
注意:我意识到标准 ListView
使用 highlight
显示选择,并调整键盘导航currentItem
。但是,由于我的需求需要同时选择多个项目,因此我必须专门管理突出显示和键盘。
编辑:这是一个更简单的测试用例,其行为并不像我预期的那样:
import QtQuick 2.7
import QtQuick.Window 2.0
Window {
id:window; visible:true; width:400; height:160; color:'darkgray'
FocusScope {
Rectangle {
width: window.width/2-6; height:window.height-8; x:4; y:4
color: focus ? 'red' : 'gray'
MouseArea { anchors.fill:parent; onClicked:parent.focus=true }
Text { text:'focused'; visible:parent.activeFocus }
Keys.onSpacePressed: console.log('space left')
}
Rectangle {
width: window.width/2-6; height:window.height-8; x:window.width/2+2; y:4
color: focus ? 'red' : 'gray'
MouseArea { anchors.fill:parent; onClicked:parent.focus=true }
Text { text:'focused'; visible:parent.activeFocus }
Keys.onSpacePressed: console.log('space right')
}
}
}
单击每个矩形都会使其变为红色,并且在任何给定时间只允许一个矩形变为红色。 (这很好。)但是,文本“focused”没有显示,因为矩形没有 activeFocus
。此外,当其中任何一个获得焦点时,按 空格 永远不会记录消息。
编辑 2:哇哦。如果我删除 FocusScope,它会按预期工作:焦点仍然是独占的,activeFocus
被授予,并且 space 工作正常。也许我上面的问题是因为ListView
是 FocusScope
(根据文档)。
编辑 3:根据下面 Mitch 的评论,设置 focus:true
关于FocusScope
还允许一切与 FocusScope 一起正常工作。但是,根据我下面的回答(以及 Mitch 的评论),FocusScope 并不是使我的两个简化示例应用程序正常工作所必需的。
最佳答案
如果您打印出原始示例中的事件焦点项目
onActiveFocusItemChanged: print(activeFocusItem)
你可以看到没有一个加载器获得焦点;它始终是窗口的根项目。
如果您在其中一个加载器上设置focus: true
,那么它将具有 focus:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
id: window
visible: true
width: 400
height: 160
color: 'darkgray'
onActiveFocusItemChanged: print(activeFocusItem)
Component {
id: row
Rectangle {
id: root
property int i: index
property bool current: ListView.isCurrentItem
property bool focused: ListView.view.activeFocus
width: parent.width
height: 20
color: current ? (focused ? 'pink' : 'lightblue') : 'lightgray'
MouseArea {
anchors.fill: parent
onClicked: {
root.ListView.view.currentIndex = i
root.ListView.view.focus = true
}
}
Text {
anchors.fill: parent
text: modelData
}
}
}
Component {
id: myList
ListView {
delegate: row
width: window.width / 2 - 10
height: window.height
y: 5
Keys.onUpPressed: decrementCurrentIndex()
Keys.onDownPressed: incrementCurrentIndex()
}
}
Loader {
objectName: "loader1"
sourceComponent: myList
focus: true
x: 5
onLoaded: item.model = ['a', 'b', 'c', 'd']
}
Loader {
objectName: "loader2"
sourceComponent: myList
x: window.width / 2
onLoaded: item.model = ['1', '2', '3', '4', '5']
}
}
但是,现在当您单击第二个 View 的委托(delegate)时,它没有焦点。如果我们声明它们都具有焦点,那么我们就无法控制哪一个最终获得焦点。事实上,即使我们确实将它们声明为都具有焦点,单击第二个 View 的委托(delegate)也不会为该 View 提供事件焦点,因为当第一个加载器获得焦点时,它所在的加载器会失去焦点。换句话说,要使其工作,您还必须给予加载器焦点,这违背了拥有漂亮的小捆绑委托(delegate)组件的全部目的:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
id: window
visible: true
width: 400
height: 160
color: 'darkgray'
onActiveFocusItemChanged: print(activeFocusItem)
Component {
id: row
Rectangle {
id: root
property int i: index
property bool current: ListView.isCurrentItem
property bool focused: ListView.view.activeFocus
width: parent.width
height: 20
color: current ? (focused ? 'pink' : 'lightblue') : 'lightgray'
MouseArea {
anchors.fill: parent
onClicked: {
root.ListView.view.currentIndex = i
root.ListView.view.parent.focus = true
root.ListView.view.focus = true
}
}
Text {
anchors.fill: parent
text: modelData
}
}
}
Component {
id: myList
ListView {
delegate: row
width: window.width / 2 - 10
height: window.height
y: 5
Keys.onUpPressed: decrementCurrentIndex()
Keys.onDownPressed: incrementCurrentIndex()
}
}
Loader {
objectName: "loader1"
sourceComponent: myList
x: 5
onLoaded: item.model = ['a', 'b', 'c', 'd']
}
Loader {
objectName: "loader2"
sourceComponent: myList
x: window.width / 2
onLoaded: item.model = ['1', '2', '3', '4', '5']
}
}
此时我会放弃并强制主动聚焦:
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
id: window
visible: true
width: 400
height: 160
color: 'darkgray'
onActiveFocusItemChanged: print(activeFocusItem)
Component {
id: row
Rectangle {
id: root
objectName: ListView.view.objectName + "Rectangle" + index
property int i: index
property bool current: ListView.isCurrentItem
property bool focused: ListView.view.activeFocus
width: parent.width
height: 20
color: current ? (focused ? 'pink' : 'lightblue') : 'lightgray'
MouseArea {
anchors.fill: parent
onClicked: {
root.ListView.view.currentIndex = i
root.ListView.view.forceActiveFocus()
}
}
Text {
anchors.fill: parent
text: modelData
}
}
}
Component {
id: myList
ListView {
objectName: parent.objectName + "ListView"
delegate: row
width: window.width / 2 - 10
height: window.height
y: 5
Keys.onUpPressed: decrementCurrentIndex()
Keys.onDownPressed: incrementCurrentIndex()
}
}
Loader {
id: loader1
objectName: "loader1"
sourceComponent: myList
x: 5
onLoaded: item.model = ['a', 'b', 'c', 'd']
}
Loader {
objectName: "loader2"
sourceComponent: myList
x: window.width / 2
onLoaded: item.model = ['1', '2', '3', '4', '5']
}
}
我真的不喜欢对焦系统。我并不是说我可以想出更好的东西,但它只是不容易使用。
关于qt - 在 ListView 之间传递焦点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39324578/