QML 列表视图和密钥导航 - 处理单个密钥事件
QML ListView and key navigation - handling of single key events
我正在使用Qt 5.6.2(Windows 10),并且有一个QObject
派生的映射器,可以将QKeyEvent
发送到当前关注的QML项目。我的基类有一个虚拟mapToKey()
函数,然后在我想使用的各种映射器中覆盖该函数。例如,下面的映射函数是我LeftArrowMapper
的一部分,并发送左箭头键事件:
void LeftArrowMapper::mapToKey()
{
// Retrieve root of QML context
QObject* root = engine->rootObjects()[0];
// Get currently focused item
QQuickItem *item = (root->property("activeFocusItem")).value<QQuickItem *>();
if (item == NULL) qDebug() << "No item";
// Create a key and a key event
Qt::Key key = Qt::Key_Left;
QKeyEvent* event = new QKeyEvent(QKeyEvent::KeyPress,
key,
Qt::NoModifier,
KeySequence(key).toString());
// Send it to the focused QML item
QCoreApplication::postEvent(item,event);
}
如果给定项目支持关键事件,它将做出相应的反应。否则,接收到的密钥事件将不会触发任何响应。我已经使用TextField
对其进行了测试,这是一个基于Text
的自定义组件(它只是使用通过 key 事件发送的文本更新text
属性)等,我没有遇到任何问题。直到我开始与ListView
合作...
我正在尝试使用键盘的左右箭头键导航ListView
键,关键事件是使用我的映射器的mapToKey()
功能人工创建的(这里的重点是:将硬件事件(如按真实按钮映射到Qt事件)。在Qt 5.6中,将focus
属性设置为true
可以使用键进行导航(在5.8和可能还有5.7中,keyNavigationEnabled
属性必须设置为true
;Qt 5.6中没有这样的属性)。
我的ListView
如下所示:
ListView {
id: list
orientation: Qt.Horizontal
width: rootWindow.width
height: 50
Keys.onPressed: {
console.log("list: " + event.key + " : " + event.text)
if (event.key == Qt.Key_Left) console.log("Moving to the left");
else if (event.key == Qt.Key_Right) console.log("Moving to the right");
}
model: ListModel {
id: items
}
delegate: Rectangle {
width: 50
height: 50
Text {
anchors.centerIn: parent
text: "[" + name + "]"
}
}
Component.onCompleted: function() {
for(var i = 1; i <= 100; i++) {
items.append({"name" : i});
}
}
onFocusChanged: {
console.log("List focus has changed");
}
}
我发现的问题是这个QML组件处理关键事件的方式很奇怪。似乎它试图模仿基于动力学的滑动(考虑加速度),您可以在滚动浏览其中的项目时用鼠标进行。这意味着以下内容:
- 如果长时间按住箭头键(约2 秒),则会触发滚动视图 - 启用后,它不会滚动单个项目,而是滚动多个项目
- 触发上述滚动后,用户可以继续按箭头键继续快速滚动。此时,也可以为每个键事件滚动单个项目,但是...
- 更改方向会导致上述行为的重置,因此用户需要执行另一个"触发滚动"事件才能向相反方向滚动 触发
- 多个单独的键事件也会触发滚动,但这次一次一个项目。此外,我上面提到的时间间隔似乎不适用于这里。用户需要按给定的箭头键 7 次(至少这是我计算的次数),然后才能选择列表中的下一个/上一个项目
似乎在内部,映射需要一定数量的按下和释放或按住 X 秒键事件才能实际触发ListView
中的某些响应。
现在我的一位同事为我们正在使用ListView
创建了一个自定义键导航,它工作正常。但是,我想知道是否没有一些秘密设置(或者我们俩都错过了文档中的备忘录)来处理这个问题。我可以看到这种与键交互的应用(即模拟加速),但对于我正在处理的场景,我真的不需要它,或者至少现在不需要。另外,如果我想在某个时候添加伪加速部分,了解事情是如何完成的将非常有用。
当您按左/右箭头键时,基于动力学的轻扫ListView
是来自ListView.highlight
的动画。为了使其可见,我们可以将一些代码添加到您的列表中:
ListView {
id: list
Keys.onPressed: {
console.log(list.currentIndex);
//...
}
delegate: Item { // so we can see highlight in background
width: 50
height: 50
Text {
anchors.centerIn: parent
text: "[" + name + "]"
}
}
highlight: Rectangle {
width: 50
height: 50
color: "pink"
}
//...
}
按向右箭头键时,currentIndex
会更改,突出显示将移动到该索引。如果像这样显式更改currentIndex
,则可以看到相同的动画:
Button {
text: "go to 45"
onClicked: list.currentIndex = 45;
}
若要自定义动画,可以更改ListView.highlightMoveDuration
和ListView.highlightMoveVelocity
属性,或将ListView.highlightFollowsCurrentItem
设置为 false 以将其关闭。您还可以按照ListView
示例代码制作自己的高光动画。
似乎在内部映射需要一定数量的按下并释放或按住 X 秒键事件才能实际触发
ListView
中的某些响应。
在处理关键事件时,ListView
没有魔力,它只是不断变化currentIndex
,QML中的动画可以完美地处理它。
- SSH通过/sbin/SSH无法读取RSA密钥文件(从控制台运行)
- 允许从 std::map 的密钥窃取资源?
- TMap::Emplace() 在应用现有密钥时会覆盖吗?
- 在没有密钥的情况下读取密文的剩余噪声预算
- 如何修复无效的API密钥,IP或操作权限错误?
- 所有可能的链接生成器与64位密钥
- 如何在unordered_map中更改密钥?
- 获取当前密钥状态?
- curl_easy_perform() 失败:SSL 对等证书或 SSH 远程密钥不正常
- 将密钥发送到非前台的游戏窗口
- 有哪些方法可以对基于 256 位密钥的矩阵进行加扰?
- 如何在精灵表上的两个不同部分之间来回切换,同时用户仍使用 SFML 持有密钥
- 如何将CNG密钥转换为OpenSSL EVP_PKEY(反之亦然)?
- 运行密钥密码解密知道密钥?
- std::unordered_map 运算符 [] 是否对非现有密钥进行零初始化?
- 封装 std::map 以允许迭代,但没有直接密钥访问?
- 如果我使用同一个密钥推送用户数据两次,会发生什么
- 如何处理插入现有密钥
- QML 列表视图和密钥导航 - 处理单个密钥事件
- C++键盘挂钩-退出程序,但也防止密钥在其他地方被处理