[英]Time Picker in QML
從Qt 5.5開始,在Qt社區版中也將以Qt Quick Extras的名義提供所謂的Qt Quick Enterprise Controls 。 除其他外, Tumbler
似乎是滿足您要求的可行解決方案:您可以輕松設置兩列,一列用於小時,一列用於分鍾。
如果你仍然有興趣在圓形選擇(或希望實現自己的不倒翁),你可以走不同的路線,如創建自己的組件繼承QQuickItem
或QQuickPaintedItem
或利用與自定義視圖PathView
。 后者就是我將在此答案中涉及的情況。 只需參考提供的鏈接,以獲取有關自定義組件創建的示例。
引用PathView
的文檔:
該視圖具有一個模型和一個委托,該模型定義了要顯示的數據,該委托定義了如何顯示數據。 代表是為路徑上的每個項目實例化的。 物品可能會被輕拂以使它們沿着路徑移動 。
因此,路徑定義了項目在屏幕上的布局方式,即使是以圓形方式也是如此。 可以通過Path
類型(即不同種類的路徑段序列)構造Path
。 PathArc
是我們感興趣的一種,因為它提供了所需的圓形形狀。
下面的示例使用這些元素定義循環時間選擇器。 通過利用委托的currentIndex
構造每個路徑: PathView
使用一個整數作為模型-小時視圖使用12
,分鍾視圖使用6
。 代表的文本是通過利用index
附加屬性並對其進行處理以生成小時和10分鍾的間隔值而生成的(請參見代表的Text
項)。 最后,當前元素的文本(即currentItem
)綁定到窗口中心的時間標簽:隨着currentIndex
和currentItem
更改,標簽也會更新。
整體組件如下所示:
highlight
部件(藍色和綠色圓圈)被用於圖形表示的時間編輯:可見時的時間可以被編輯,即,另一Item
的路徑可以被選擇。 通過單擊中間的時間標簽,可以在普通模式和編輯模式之間切換。
在編輯模式下,用戶可以將鼠標懸停在不同的小時/分鍾值上以選擇它們。 如果單擊新選擇的小時/分鍾, PathView
禁用該特定PathView
的編輯,並且相應的高亮圓圈消失。
這段代碼顯然只是一個玩具示例,可以讓您了解PathView
用途。 可以進行一些改進,例如動畫,更好的數字定位,詳細的分鍾記錄,漂亮的背景等等。 但是,它們超出了該問題的范圍,因此未被考慮。
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls.Styles 1.3
import QtQuick.Layouts 1.1
Window {
visible: true
width: 280; height: 280
RowLayout { // centre time label
anchors.centerIn: parent
Text {
id: h
font.pixelSize: 30
font.bold: true
text: outer.currentItem.text
}
Text {
id: div
font.pixelSize: 30
font.bold: true
text: qsTr(":")
}
Text {
id: m
font.pixelSize: 30
font.bold: true
text: inner.currentItem.text
}
MouseArea {
anchors.fill: parent
onClicked: outer.choiceActive = inner.choiceActive = !outer.choiceActive
}
}
PathView { // hours path
id: outer
property bool pressed: false
model: 12
interactive: false
highlightRangeMode: PathView.NoHighlightRange
property bool choiceActive: false
highlight: Rectangle {
id: rect
width: 30 * 1.5
height: width
radius: width / 2
border.color: "darkgray"
color: "steelblue"
visible: outer.choiceActive
}
delegate: Item {
id: del
width: 30
height: 30
property bool currentItem: PathView.view.currentIndex == index
property alias text : textHou.text
Text {
id: textHou
anchors.centerIn: parent
font.pixelSize: 24
font.bold: currentItem
text: index + 1
color: currentItem ? "black" : "gray"
}
MouseArea {
anchors.fill: parent
enabled: outer.choiceActive
onClicked: outer.choiceActive = false
hoverEnabled: true
onEntered: outer.currentIndex = index
}
}
path: Path {
startX: 200; startY: 40
PathArc {
x: 80; y: 240
radiusX: 110; radiusY: 110
useLargeArc: false
}
PathArc {
x: 200; y: 40
radiusX: 110; radiusY: 110
useLargeArc: false
}
}
}
PathView { // minutes path
id: inner
property bool pressed: false
model: 6
interactive: false
highlightRangeMode: PathView.NoHighlightRange
property bool choiceActive: false
highlight: Rectangle {
width: 30 * 1.5
height: width
radius: width / 2
border.color: "darkgray"
color: "lightgreen"
visible: inner.choiceActive
}
delegate: Item {
width: 30
height: 30
property bool currentItem: PathView.view.currentIndex == index
property alias text : textMin.text
Text {
id: textMin
anchors.centerIn: parent
font.pixelSize: 24
font.bold: currentItem
text: index * 10
color: currentItem ? "black" : "gray"
}
MouseArea {
anchors.fill: parent
enabled: inner.choiceActive
onClicked: inner.choiceActive = false
hoverEnabled: true
onEntered: inner.currentIndex = index
}
}
path: Path {
startX: 140; startY: 60
PathArc {
x: 140; y: 220
radiusX: 40; radiusY: 40
useLargeArc: false
}
PathArc {
x: 140; y: 60
radiusX: 40; radiusY: 40
useLargeArc: false
}
}
}
// to set current time!
onVisibleChanged: {
var d = new Date();
outer.currentIndex = d.getUTCHours() % 12
inner.currentIndex = d.getMinutes() / 10
}
}
這是用於時間選擇的iPhone風格
Rectangle {
id:clockid
width: frame.implicitWidth + 10
height: frame.implicitHeight + 10
anchors.centerIn: parent
color: "cornsilk"
function formatText(count, modelData) {
var data = count === 12 ? modelData + 1 : modelData;
return data.toString().length < 2 ? "0" + data : data;
}
FontMetrics {
id: fontMetrics
font.pixelSize: 10
}
Component {
id: delegateComponent
Label {
text: clockid.formatText(Tumbler.tumbler.count, modelData)
opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: fontMetrics.font.pixelSize * 1.25
}
}
Frame {
id: frame
padding: 0
anchors.centerIn: parent
Row {
id: row_clock
Tumbler {
id: hoursTumbler
model: 12
delegate: delegateComponent
visibleItemCount: 5
}
Tumbler {
id: minutesTumbler
model: 60
delegate: delegateComponent
visibleItemCount: 5
}
Tumbler {
id: amPmTumbler
model: ["AM", "PM"]
delegate: delegateComponent
}
}
}
}
我認為我自己的時間選擇器很好,您可以擴展它,就像您喜歡它在波斯的方向上一樣,您需要在周圍交換一些內容或使用一些布局鏡像:
UButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Controls.Universal 2.4
Button {
id:root
Universal.accent: Universal.Cobalt
Universal.foreground: "white"
highlighted: true
font.family: "B Nazanin"
font.pointSize: 12
}
UCard.qml
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Controls.Universal 2.4
import QtGraphicalEffects 1.0
Item{
property alias radius : morakhasiRect.radius
property alias color : morakhasiRect.color
implicitWidth: 150
implicitHeight: 150
Rectangle{
anchors.rightMargin: 1
anchors.leftMargin: 1
anchors.bottomMargin: 1
anchors.topMargin: 1
id:morakhasiRect
anchors.fill: parent
color: "#f5f5f5"
}
DropShadow {
anchors.fill: morakhasiRect
radius: 9.0
samples: 17
color: "#80000000"
source: morakhasiRect
}
}
URect.qml
Rectangle{
color: "transparent"
border.color: Universal.color(Universal.Cobalt)
border.width: 1
}
UTumbler.qml
import QtQuick 2.0
import QtQuick.Controls.Universal 2.4
import QtQuick.Controls 2.4
Tumbler{
id:hourSpin
wrap: false
delegate: Text{
font.pointSize: 12
text: modelData
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
opacity: 1.0 - Math.abs(Tumbler.displacement) / (hourSpin.visibleItemCount / 2)
}
Rectangle {
anchors.horizontalCenter: hourSpin.horizontalCenter
y: hourSpin.height * 0.4
width: 40
height: 1
color: Universal.color(Universal.Cobalt)
}
Rectangle {
anchors.horizontalCenter: hourSpin.horizontalCenter
y: hourSpin.height * 0.6
width: 40
height: 1
color: Universal.color(Universal.Cobalt)
}
}
UTime對話
import QtQuick 2.0
import QtQuick.Controls 2.4
import QtQuick.Controls.Universal 2.4
Item{
id:root
property alias hour : hourSpin.currentIndex
property alias minute : minuteSpin.currentIndex
signal open
signal close
signal accepted
signal rejected
visible: element.opened
onOpen: element.open()
onClose: element.close()
implicitWidth: 200
implicitHeight: 200
Dialog {
id: element
modal: true
width: parent.width
height: parent.height
padding: 5
margins: 5
background: Item{
}
onAccepted: {
root.accepted()
}
onRejected: {
root.rejected()
}
contentItem: UCard{
anchors.fill: parent
radius: 10
}
Column{
id: column
spacing: 30
anchors.centerIn: parent
Row{
id: row
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
Column{
id: column1
spacing: 15
height: 80
width: 50
clip:true
UTumbler{
id:hourSpin
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
model: 24
}
}
Text{
text: ":"
font.pointSize: 12
anchors.verticalCenter: parent.verticalCenter
font.family: "B Nazanin"
}
Column{
id: column2
spacing: 15
height: 80
width: 50
clip:true
UTumbler{
id:minuteSpin
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
model: 60
}
}
}
Row{
anchors.horizontalCenter: parent.horizontalCenter
spacing: 40
UButton{
text:"select"
onClicked: {
element.reject()
}
}
UButton{
text: "cancel"
onClicked: {
element.accept()
}
}
}
}
}
}
UIcoButton.qml
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Controls.Universal 2.4
import QtGraphicalEffects 1.0
FocusScope{
id:focusScope
signal clicked
property alias font : icoText.font.family
property alias icon : icoText.text
property alias size : icoText.font.pixelSize
property alias caption : captionTxt.text
property alias spacing : row.spacing
property string colorEnter :Universal.color(Universal.Cobalt)
property string colorExit :"#00171f"
property alias state: root.state
implicitWidth: captionTxt.text!= "" ? 100 : 35
implicitHeight: 40
Rectangle {
id: root
radius: 0
anchors.fill: parent
color: colorExit
state: "default"
focus: true
onFocusChanged: {
if(focus){
root.border.width = 1
root.border.color = Universal.color( Universal.Cobalt)
}
else{
root.border.width = 0
root.border.color = "transparent"
}
}
Row{
id: row
anchors.rightMargin: 5
anchors.leftMargin: 5
anchors.bottomMargin: 5
anchors.topMargin: 5
anchors.fill: parent
layoutDirection: Qt.RightToLeft
spacing: 15
Text {
id: icoText
text: ""
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 25
font.family: "fontawesome"
color: "white"
}
Text{
id:captionTxt
text: ""
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: icoText.font.pixelSize * 55 /100
font.family: "B Nazanin"
color: "white"
visible: text!= ""
}
}
InnerShadow {
id:shadow
anchors.fill: row
radius: 1.0
samples: 17
horizontalOffset: 1
color: colorExit
source: row
visible: false
}
// Glow {
// id:shadow
// anchors.fill: row
// radius: 6
// samples: 25
// color: "white"
// source: row
// visible: false
// }
MouseArea{
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: {
if(root.state == "default")
root.color = colorEnter
else{
icoText.color = colorEnter
captionTxt.color = colorEnter
}
}
onExited: {
if(root.state == "default")
root.color = colorExit
else{
icoText.color = colorExit
captionTxt.color = colorExit
}
}
onPressed: {
shadow.visible = true
}
onReleased: {
shadow.visible = false
}
onClicked: {
focusScope.clicked()
}
}
states: [
State {
name: "transparent"
PropertyChanges {
target: root
color:"transparent"
}
PropertyChanges {
target: icoText
color:colorExit
}
PropertyChanges {
target: captionTxt
color:colorExit
}
},
State{
name: "default"
PropertyChanges {
target: root
color:"#00171f"
}
PropertyChanges {
target: icoText
color:"white"
}
PropertyChanges {
target: captionTxt
color:"white"
}
}
]
}
}
UTimePicker
import QtQuick 2.4
import QtQuick.Controls 2.4
import QtQuick.Controls.Universal 2.4
Item {
id: scope
clip: true
QtObject{
id:variables
property var time: ({hour: 0, minute: 0})
onTimeChanged: {
refreshDialogTime()
}
}
signal changed
property alias caption : captionTxt.text
property size size : Qt.size(30,70)
property string splitter : ":"
property alias spacing : row.spacing
Component.onCompleted: {
var q = new Date()
var curtime = q.toLocaleTimeString().substring(0,5);
if(splitter != ":"){
curtime.replace(':',splitter)
}
var vars = curtime.split(':')
setTime(vars[0],vars[1])
refreshDialogTime()
}
function refreshDialogTime(){
dialog.hour = variables.time.hour
dialog.minute = variables.time.minute
}
function getTime(){
return variables.time;
}
function setTimeString(time){
textArea.text= time
}
function setTime(hour,minute){
var _hour = hour
if(_hour<10){
_hour = "0"+hour.toString()
}
else{
_hour = hour.toString()
}
var _minute = minute
if(_minute <10){
_minute = "0"+minute.toString()
}
else{
_minute = minute.toString()
}
var time = _hour+":"+_minute
textArea.text = time
}
implicitHeight: 50
implicitWidth: 200
Row{
id: row
width: parent.width
height: parent.height
spacing: 25
layoutDirection: Qt.RightToLeft
Text{
font.bold: true
id: captionTxt
font.pointSize: 12
horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter
width: scope.size.width * scope.width /100 - scope.spacing/2
verticalAlignment: Text.AlignVCenter
font.family: "B Nazanin"
}
Item{
id: element
anchors.verticalCenter: parent.verticalCenter
height: parent.height
width: scope.size.height * scope.width /100 - scope.spacing/2
Rectangle{
id:backrec
height: parent.height
anchors.verticalCenter: parent.verticalCenter
width: parent.width
border.width: 1
border.color: "black"
TextField{
id:textArea
selectByMouse: true
anchors.verticalCenter: parent.verticalCenter
height: parent.height
rightPadding: 5
bottomPadding: 5
topPadding: 5
padding: 5
verticalAlignment: Text.AlignVCenter
onFocusChanged: {
if(focus){
captionTxt.color = Universal.color( Universal.Cobalt)
backrec.border.color = Universal.color( Universal.Cobalt)
}
else{
captionTxt.color = "black"
backrec.border.color = "black"
}
}
background: URect{
color: "transparent"
border.color: "black"
border.width: 0
}
onTextChanged: {
var _temp = text.split(splitter)
if(_temp.length>0){
variables.time.hour =_temp[0]==""?0: _temp[0]
variables.time.minute = _temp[1]==""?0:_temp[1]
}
changed()
}
placeholderText : "HH:mm"
anchors.right: parent.right
anchors.left: iconBtn.right
font.family: "B Nazanin"
font.pointSize: 12
inputMask: "99:99"
validator: RegExpValidator { regExp: /^([0-1\s]?[0-9\s]|2[0-3\s]):([0-5\s][0-9\s])$ / }
}
IcoButton{
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: 2
id:iconBtn
caption: ""
size: 30
icon: "\uf017"
state: "transparent"
onClicked: {
textArea.focus = true
dialog.open()
}
}
}
}
}
UTimeDialog{
id:dialog
x:iconBtn.x
y:iconBtn.y+ scope.height
onAccepted: {
setTime(hour,minute)
}
}
}
例
UTimePicker{
x: 285
width: 200
spacing: 15
size: Qt.size(35,65)
caption: "time"
onChanged: {
var i = getTime()
console.log(i.hour)
console.log(i.minute)
}
}
用於鏡像:
LayoutMirroring.enabled: true
LayoutMirroring.childrenInherit: true
如果有人感興趣,我可以為此共享圖書館
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.