Qt 中简单的无键盘触摸屏小部件
Simple keyboardless touchscreen widgets in Qt
我正在寻找一种简单的方法来为触摸屏制作小部件,允许用户在计算机上设置时间和 IP 地址 运行代码并提供一个简单的(大写拉丁语-字母)名称。
这个问题不是关于如何实际设置系统时间或IP地址;我只是在寻找有关如何自己制作图形小部件的信息。
我想要的是将每个可编辑的属性(时间,地址,姓名)分成"scrollable"个字段,其中"time"的字段是小时,分钟,可能是秒,AM/PM/24-hr 和 address/name 的字段是单个字符。每个字段的上方和下方都有一个箭头,触摸箭头会滚动浏览该字段的有效值。
我认为这是一种非常常见的 UX 模式,尤其是在 meatspace 中(例如在闹钟上),但以防万一我不清楚我要描述的内容,这里有一个示例用户编辑 "name" 属性:
^^^
BN
vvv
用户在 "N" 下方按下 "down":
^^^
BO
vvv
用户在空space下方按下"down":
^^^^
BOA
vvvv
...再次使用相同的向下箭头:
^^^^
BOB
vvvv
我正在使用 C++14 和 Qt 5 编写此代码。(如果最坏的情况发生,我愿意使用不同的语言 and/or 框架编写一个单独的应用程序,但我'我不是在这里征求框架建议;如果你有,请告诉我,我会在 Software Recommendations SE 上提出相应的问题。)
我在 Qt 5 小部件库中没有看到这样的东西;大多数输入小部件都是文本字段。 QSpinBox
看起来很有前途,但箭头对于我的触摸屏来说可能太小了,而且为每个字母使用单独的旋转框可能会让人感到困惑和难看。
我对 Qt 或 GUI 编程的总体了解还不够,无法自信地尝试从头开始编写自己的小部件,但是这个界面看起来很简单,我希望几行 QML 就能让我明白一路走好。
ListView
以及 PathView
可以产生预期的结果,但行为和性能略有不同。与ListView
不同的是,PathView
是循环的,即可以只使用一个选择控件来连续迭代元素。通过 PathAttribute
类型完全自定义 PathView
中路径的行为也更容易。无论如何,根据问题,路径自定义似乎不是必需的功能。
如果您通过 ListView
实施解决方案,您应该确保只显示一个元素并且处理任何模型。
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
ListView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
highlightRangeMode: ListView.StrictlyEnforceRange // <--- ensures that ListView shows current item
delegate: Text {
width: ListView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
对模型的检查确保任何类型的模型都可以传递给组件。这是一个使用三种截然不同的模型的示例:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 400
height: 300
ListModel {
id: mod
ListElement {texty: "it1"}
ListElement {texty: "it2"}
ListElement {texty: "it3"}
}
Row {
Repeater {
id: rep
model: 3
delegate: spinnnnnnnner
Component.onCompleted: {
rep.itemAt(0).model = mod // listmodel
rep.itemAt(0).textRole = "texty"
rep.itemAt(1).model = 10 // number model
//
rep.itemAt(2).model = ["foo", "bar", "baz"] // array model
}
}
}
}
PathView
实现与 ListView
没有太大区别。在这种情况下,定义一个垂直 path
并通过 pathItemCount
指定一次只有一个元素可见就足够了。最后,设置 preferredHighlightBegin
/preferredHighlightEnd
确保可见元素在视图中居中。重新访问的组件如下:
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
PathView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
pathItemCount: 1
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
path: Path {
startX: list.width / 2; startY: 0
PathLine { x: list.width / 2; y: list.height }
}
delegate: Text {
width: PathView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
我正在寻找一种简单的方法来为触摸屏制作小部件,允许用户在计算机上设置时间和 IP 地址 运行代码并提供一个简单的(大写拉丁语-字母)名称。
这个问题不是关于如何实际设置系统时间或IP地址;我只是在寻找有关如何自己制作图形小部件的信息。
我想要的是将每个可编辑的属性(时间,地址,姓名)分成"scrollable"个字段,其中"time"的字段是小时,分钟,可能是秒,AM/PM/24-hr 和 address/name 的字段是单个字符。每个字段的上方和下方都有一个箭头,触摸箭头会滚动浏览该字段的有效值。
我认为这是一种非常常见的 UX 模式,尤其是在 meatspace 中(例如在闹钟上),但以防万一我不清楚我要描述的内容,这里有一个示例用户编辑 "name" 属性:
^^^
BN
vvv
用户在 "N" 下方按下 "down": ^^^ BO vvv
用户在空space下方按下"down":
^^^^
BOA
vvvv
...再次使用相同的向下箭头:
^^^^
BOB
vvvv
我正在使用 C++14 和 Qt 5 编写此代码。(如果最坏的情况发生,我愿意使用不同的语言 and/or 框架编写一个单独的应用程序,但我'我不是在这里征求框架建议;如果你有,请告诉我,我会在 Software Recommendations SE 上提出相应的问题。)
我在 Qt 5 小部件库中没有看到这样的东西;大多数输入小部件都是文本字段。 QSpinBox
看起来很有前途,但箭头对于我的触摸屏来说可能太小了,而且为每个字母使用单独的旋转框可能会让人感到困惑和难看。
我对 Qt 或 GUI 编程的总体了解还不够,无法自信地尝试从头开始编写自己的小部件,但是这个界面看起来很简单,我希望几行 QML 就能让我明白一路走好。
ListView
以及 PathView
可以产生预期的结果,但行为和性能略有不同。与ListView
不同的是,PathView
是循环的,即可以只使用一个选择控件来连续迭代元素。通过 PathAttribute
类型完全自定义 PathView
中路径的行为也更容易。无论如何,根据问题,路径自定义似乎不是必需的功能。
如果您通过 ListView
实施解决方案,您应该确保只显示一个元素并且处理任何模型。
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
ListView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
highlightRangeMode: ListView.StrictlyEnforceRange // <--- ensures that ListView shows current item
delegate: Text {
width: ListView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}
对模型的检查确保任何类型的模型都可以传递给组件。这是一个使用三种截然不同的模型的示例:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 400
height: 300
ListModel {
id: mod
ListElement {texty: "it1"}
ListElement {texty: "it2"}
ListElement {texty: "it3"}
}
Row {
Repeater {
id: rep
model: 3
delegate: spinnnnnnnner
Component.onCompleted: {
rep.itemAt(0).model = mod // listmodel
rep.itemAt(0).textRole = "texty"
rep.itemAt(1).model = 10 // number model
//
rep.itemAt(2).model = ["foo", "bar", "baz"] // array model
}
}
}
}
PathView
实现与 ListView
没有太大区别。在这种情况下,定义一个垂直 path
并通过 pathItemCount
指定一次只有一个元素可见就足够了。最后,设置 preferredHighlightBegin
/preferredHighlightEnd
确保可见元素在视图中居中。重新访问的组件如下:
Component {
id: spinnnnnnnner
Column {
width: 100
height: 110
property alias model: list.model
property string textRole: ''
spacing: 10
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "-"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.decrementCurrentIndex() }
}
PathView {
id: list
clip: true
width: 100
height: 55
enabled: false // <--- remove to activate mouse/touch grab
pathItemCount: 1
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
path: Path {
startX: list.width / 2; startY: 0
PathLine { x: list.width / 2; y: list.height }
}
delegate: Text {
width: PathView.view.width
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 50
font.bold: true
text: textRole === "" ? modelData :
((list.model.constructor === Array ? modelData[textRole] : model[textRole]) || "")
}
}
Item {
width: 100
height: 25
Text { anchors.centerIn: parent; text: "+"; font.pixelSize: 25; font.bold: true }
MouseArea {anchors.fill: parent; onClicked: list.incrementCurrentIndex() }
}
}
}