반응형

QT qml로 현재 시간 정보를 가져와 아날로그 시계로 보여주기 

이번에는 qml로 현재시간 정보를 실시간으로 가져와 아날로그 시계로 표시하도록 구현해보겠습니다. 

 

아날로그 시계를 만들기 위한 구성요소는 아래와 같은데, 하나 하나씩 만들어 보겠습니다. 

1. 큰 원

2. 시간을 표시하는 12개의 작은 원

3. 시간을 표시하는 1~12까지의 숫자

4. 시계의 중앙에 위치한 원

5. 시침, 분침, 초침

6. 타이머를 이용한 현재 시간 정보를 가져오기

 

1. 큰 원(Rectangle)

원을 그리기 위해서는 Rectangle 을 사용합니다. 

radius 속성에 원의 반지름 값을 넣어주면 원이 만들어 집니다. 

    Rectangle{
        id: circle
        anchors.centerIn: parent
        height: Math.min(parent.width, parent.height)
        width: height
        radius: width/2
        border.color: "black"
    }

 

2. 시간을 표시하는 12개의 작은 원, 3. 시간을 표시하는 1~12까지의 숫자

12개를 반복적으로 수행하기 위해 Repeater를 사용합니다. 

x: 정중앙, y:0으로 부터 시작하는데, height는 원의 지름으로 하여 30도씩 회전하면서 작은 원과 숫자를 표시합니다. 

숫자는 0부터 시작하는데, 0이면 12를 표시하도록 하였습니다. 

그런데, Item이 30도씩 회전하면서 숫자도 그에 맞게 회전하기 때문에, 기울이지 않고 똑바로 보이게 하려면 Text에서 rotation을 이용하여, 똑바로 보이게 합니다. Item의 rotation과 Text의 rotation의 합이 360이 되면 똑바로 보이겠죠?

Repeater{
        model: 12
        Item{
            id: hourContainer

            property int hour: index
            height:circle.height
            rotation: index*30
            x: circle.width/2
            y:0

            Rectangle{
                height: circle.height*0.05
                width: height
                radius: width/2
                color: "black"
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.top: parent.top
            }

            Text{
                x: -15
                y: circle.height*0.05
                rotation: 360 - index*30
                text: hourContainer.hour == 0 ?12 : hourContainer.hour
                font.pixelSize: circle.height*0.05
            }
        }
    }

 

4. 시계의 중앙에 위치한 원

이건 간단합니다. 

height와 width는 최대한 작게 표시하도록 0.05를 곱하였고, radius에 반지름을 넣습니다. 

그리고 anchors.centerIn에 parent를 넣어, 화면의 중앙에 표시하도록 하였습니다. 

Rectangle{
        id: center_rect
        anchors.centerIn: parent
        height: circle.height*0.05
        width: height
        radius: width/2
        color: "black"
    }

 

5. 시침, 분침, 초침

시침, 분침, 초침 모두 Rectangle로 긴 막대기처럼 표시하도록 만들었습니다.

여기서 중요한건 현재 시간에 따라 시침, 분침, 초침의 rotation을 설정하여, 회전하여 보여지도록 하는 것입니다.

transform을 이용하여, 큰 원의 중앙점을 기준으로 회전하도록 하였습니다.

초침과 분침은 은 분,초마다 360/60=6도씩 회전하도록 하였고,

시침은 360/12=30도씩 회전하도록 하고,  현재 분의 상태에 조금 움직여야 하기 때문에,

30*(minutes/60)로 움직이도록 하였습니다.

 

시침은 아래 식대로 현재 시에 30도를 곱한 값에 현재 분에 따른 추가 각도를 더하였습니다.

hourItem.value * hourItem.angle_hour + 30*(minutes/60)  

Item{
        id:hourItem
        property int value: hours
        property int angle_hour : 360/12
        Rectangle{
            width:6
            x: window.height/2
            y: circle.height * 0.21
            height: window.height*0.35
            color: "blue"
            antialiasing: true
        }
        transform: Rotation
        {
          origin.x: window.height/2
          origin.y: window.height/2
          angle: hourItem.value * hourItem.angle_hour + 30*(minutes/60)
        }
        antialiasing: true
    }

    Item{
        id:minuteItem
        property int value: minutes
        property int angle_minute : 360/60
        Rectangle{
            width:4
            x: window.height/2
            y:circle.height *0.12
            height: window.height*0.45
            color: "black"
            antialiasing: true
        }
        transform: Rotation
        {
          origin.x: window.height/2
          origin.y: window.height/2
          angle: minuteItem.value * minuteItem.angle_minute
        }
        antialiasing: true
    }

    Item{
        id:secondItem
        property int value: seconds
        property int angle_second: 360/60
        Rectangle{
            width:2
            x: window.height/2
            y:circle.height *0.08
            height: window.height*0.5
            color: "red"
            antialiasing: true
        }
        transform: Rotation
        {
          origin.x: window.height/2
          origin.y: window.height/2
          angle: secondItem.value * secondItem.angle_second
        }
        antialiasing: true
    }

6. 타이머를 이용한 현재 시간 정보를 가져오기

현재 시간을 가져오기 위해 Date() 객체를 이용하였습니다.

Timer로 1초가 지날때마다 현재 시간을 가져와 갱신하도록 하고, 로그로 남기도록 하였습니다. 

이때, 시간, 분, 초에 대한 변수의 값은 시침, 분침, 초침이 보여질 부분에 대해 영향을 주게 됩니다 

property date curentTime: new Date()
property int hour: curentTime.getHours()
property int minutes: curentTime.getMinutes()
property int seconds: curentTime.getSeconds()

Timer{
        id: timer
        repeat: true
        interval: 1000
        running: true
        onTriggered: {
            curentTime = new Date()
            print(curentTime.getHours(), ":", curentTime.getMinutes(), ":", curentTime.getSeconds());
        }

    }

 

전체 코드

각각의 구성 요소들의 위치가 약간 안맞는 세세한 부분은 신경을 쓰지 않았습니다. 

그점 양해부탁 드리고 봐주시면 될 듯 합니다. 

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    id: window
    width: 500
    height: 500
    visible: true

    property date curentTime: new Date()
    property int hour: curentTime.getHours()
    property int minutes: curentTime.getMinutes()
    property int seconds: curentTime.getSeconds()


    Rectangle{
        id: circle
        anchors.centerIn: parent
        height: Math.min(parent.width, parent.height)
        width: height
        radius: width/2
        border.color: "black"
    }

    Repeater{
        model: 12
        Item{
            id: hourContainer

            property int hour: index
            height:circle.height
            rotation: index*30
            x: circle.width/2
            y:0

            Rectangle{
                height: circle.height*0.05
                width: height
                radius: width/2
                color: "black"
                anchors.horizontalCenter: parent.horizontalCenter
                anchors.top: parent.top
            }

            Text{
                x: -15
                y: circle.height*0.05
                rotation: 360 - index*30
                text: hourContainer.hour == 0 ?12 : hourContainer.hour
                font.pixelSize: circle.height*0.05
            }
        }
    }

    Rectangle{
        id: center_rect
        anchors.centerIn: parent
        height: circle.height*0.05
        width: height
        radius: width/2
        color: "black"
    }

    Item{
        id:hourItem
        property int value: hours
        property int angle_hour : 360/12
        Rectangle{
            width:6
            x: window.height/2
            y: circle.height * 0.21
            height: window.height*0.35
            color: "blue"
            antialiasing: true
        }
        transform: Rotation
        {
          origin.x: window.height/2
          origin.y: window.height/2
          angle: hourItem.value * hourItem.angle_hour + 30*(minutes/60)
        }
        antialiasing: true
    }

    Item{
        id:minuteItem
        property int value: minutes
        property int angle_minute : 360/60
        Rectangle{
            width:4
            x: window.height/2
            y:circle.height *0.12
            height: window.height*0.45
            color: "black"
            antialiasing: true
        }
        transform: Rotation
        {
          origin.x: window.height/2
          origin.y: window.height/2
          angle: minuteItem.value * minuteItem.angle_minute
        }
        antialiasing: true
    }

    Item{
        id:secondItem
        property int value: seconds
        property int angle_second: 360/60
        Rectangle{
            width:2
            x: window.height/2
            y:circle.height *0.08
            height: window.height*0.5
            color: "red"
            antialiasing: true
        }
        transform: Rotation
        {
          origin.x: window.height/2
          origin.y: window.height/2
          angle: secondItem.value * secondItem.angle_second
        }
        antialiasing: true
    }



    Timer{
        id: timer
        repeat: true
        interval: 1000
        running: true
        onTriggered: {
            curentTime = new Date()
            print(curentTime.getHours(), ":", curentTime.getMinutes(), ":", curentTime.getSeconds());
        }

    }

}
반응형
반응형

QT qml의 slider를 이용해 Rectangle 색상 변경하기

 

Vertical Slider와 Horizotal Slider를 이용하여 Rectangle의 색상을 변경해 보겠습니다. 

 

Rectangle 정의 하기

Rectangle의 정의해 보겠습니다. 

Qt.rgba의 전달 인자는 Red, Green, Blue, Alpha 값이고, 각각의 값의 범위는 0부터 1까지 입니다. 

여기에서는 Slider에 따라 Red 값과 Green값만 변경되도록 하겠습니다. 

    Rectangle{
        id: rect
        width: 300
        height: 300
        color: Qt.rgba(slider_h.value, slider_v.value, 0, 1)
    }

 

Slider 정의

Red 값을 변경시킬 Slider와 Green 값을 변경시킬 Slider를 만들어 정의하였습니다. 

두 Slider 값은 0부터 1까지 변경되도록 하였습니다. 

Slider의 Default는 가로(Qt.Horizontal)이며, 하나의 Slider는 세로(Qt.Vertical)로 정의하였습니다.

    Slider {
        id: slider_h
        y: rect.height + 10
        value: 0.5
        width: 300
        from: 0
        to : 1
    }

    Slider {
        id: slider_v
        x: rect.width + 10
        value: 0.5
        height: 300
        from: 0
        to : 1
        orientation : Qt.Vertical
    }

 

전체 코드

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    width: 640
    height: 480
    visible: true

    Rectangle{
        id: rect
        width: 300
        height: 300
        color: Qt.rgba(slider_h.value, slider_v.value, 0, 1)
    }

    Slider {
        id: slider_h
        y: rect.height + 10
        value: 0.5
        width: 300
        from: 0
        to : 1
    }

    Slider {
        id: slider_v
        x: rect.width + 10
        value: 0.5
        height: 300
        from: 0
        to : 1
        orientation : Qt.Vertical
    }
}
반응형
반응형

QT qml의 popup 표시하고 timer를 이용해 팝업 닫기

 

open 버튼을 누르면 팝업이 표시되고, 팝업이 표시되고 3초 이후 팝업이 자동적으로 닫히도록 만들어 보겠습니다. 또한 팝업에 문구 출력하고, 버튼도 추가하여, 팝업에 있는 버튼을 누르면 바로 팝업이 닫히도록 만들어 보겠습니다.

 

버튼(Button) 정의

버튼을 생성하였습니다. 

버튼을 클릭하면 팝업이 표시되고, 타이머를 시작하도록 하였습니다. 

    Button {
       id: mainButton
       text: "Open"
       onClicked:{
           popup.open()
           timer.start()
       }
    }

 

타이머(Timer) 정의

타이머를 생성하였습니다. 

타이머는 3000ms(3초) 뒤에 트리거가 발생되어 팝업이 닫히도록 하였습니다.

mainButton을 눌렀을 때, 타이머 시작되어 3초 이후 트리거가 발생됩니다. 

    Timer {
        id: timer
        interval: 3000; running: false; repeat: false
        onTriggered: popup.close()
    }

 

팝업(Popup) 정의

팝업을 생성하였는데, Label이 표시되도록 하였고, Button을 생성해 button을 누르면 팝업이 바로 닫히도록 하였습니다.

팝업이 닫힐 때에는 타이머를 정지 시킵니다. 

closePoli

팝업 표시된 부분 밖에를 눌러도 팝업이 닫히지 않게 하려면, 아래 코드를 넣습니다. 

Popup.CloseOnPressOutsideParentclosePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent

Popup {
       id: popup
       x: 100
       y: 100
       width: 200
       height: 300
       modal: true
       focus: true
       onClosed: timer.stop()
       Label {
            text:qsTr("This is popup")
       }

       Button {
          text: "Close"
          y: 200
          onClicked:{
              popup.close()
          }
       }
   }

전체 코드

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    width: 640
    height: 480
    visible: true

    Button {
       id: mainButton
       text: "Open"
       onClicked:{
           popup.open()
           timer.start()
       }
    }

    Timer {
        id: timer
        interval: 3000; running: false; repeat: false
        onTriggered: popup.close()
    }

   Popup {
       id: popup
       x: 100
       y: 100
       width: 200
       height: 300
       modal: true
       focus: true
       onClosed: timer.stop()
       Label {
            text:qsTr("This is popup")
       }

       Button {
          text: "Close"
          y: 200
          onClicked:{
              popup.close()
          }
       }
   }
}
반응형
반응형

 

QT qml의 listview을 이용하여 간단한 리스트 표시하기 - hightlight 포함

 

listview component는 리스트에 넣을 데이터(model)와 각 리스트 아이템을 어떻게 표시할지에 대한 델리게이트(Delegate)가 꼭 필요합니다. 또한 mouse 클릭한 것에 따라 focus가 변경되는 것을 구현해 봅시다. 

 

데이터(model) 정의

model은 ListModel component로 생성합니다. 

각각의 리스트 아이템은 ListElement로 정의하였고,

과일과 가격을 표시하도록 하기 위해, name과 price 변수를 생성해 값을 지정하였습니다. 

    ListModel {
         id:listmodel
         ListElement {
             name: "Apple"
             price: "1000"
         }
         ListElement {
             name: "Banana"
             price: "2000"
         }
         ListElement {
             name: "Grape"
             price: "3000"
         }

         ListElement {
             name: "Peach"
             price: "4000"
         }

         ListElement {
             name: "Lemon"
             price: "5000"
         }
     }

 

델리게이트(Delegate) 정의

델리게이트(Delegate)는 리스트의 각각의 아이템을 어떻게 표시할지를 다룹니다. 

여기에서는 각 리스트 아이템의 높이는 40으로 넣었고, 과일 이름과 가격을 표시하도록 하였습니다. 

또한, Mouse 클릭을 하면 listView의 현재 아이템이 몇번째인지에 대한 currentIndex 변수에 index를 넣도록 하였습니다.

    Component {
        id:listDelegate
        Item {
            width: parent.width
            height: 40
            Column {
                Text { text: 'Name:' + name }
                Text { text: 'Price:' + price + ' won'}
            }
            MouseArea {
                anchors.fill: parent
                onClicked: list.currentIndex = index
            }
        }
    }

 

하이라이트(Highlight) 정의

리스트의 아이템에 Focus 처리를 하기 위해, 하이라이트를 정의하였습니다. 

배경은 회색으로 표시하도록 하였고, 마우스로 클릭한 아이템의 과일 이름 문구를 표시하도록 하였습니다.

문구의 색상은 흰색으로 표시하도록 하였습니다.  

    Component{
        id : listhightlight
        Rectangle {

            color: 'grey'
            Text {
                anchors.centerIn: parent
                text: 'Hello ' + listmodel.get(list.currentIndex).name
                color: 'white'
            }
        }
    }

 

전체코드

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

Window {
    width: 640
    height: 480
    visible: true

    ListModel {
         id:listmodel
         ListElement {
             name: "Apple"
             price: "1000"
         }
         ListElement {
             name: "Banana"
             price: "2000"
         }
         ListElement {
             name: "Grape"
             price: "3000"
         }

         ListElement {
             name: "Peach"
             price: "4000"
         }

         ListElement {
             name: "Lemon"
             price: "5000"
         }
     }

    Component {
        id:listDelegate
        Item {
            width: parent.width
            height: 40
            Column {
                Text { text: 'Name:' + name }
                Text { text: 'Price:' + price + ' won'}
            }
            MouseArea {
                anchors.fill: parent
                onClicked: list.currentIndex = index
            }
        }
    }

    Component{
        id : listhightlight
        Rectangle {

            color: 'grey'
            Text {
                anchors.centerIn: parent
                text: 'Hello ' + listmodel.get(list.currentIndex).name
                color: 'white'
            }
        }
    }

    ListView {
        id: list
        anchors.fill: parent
        model: listmodel
        delegate:listDelegate
        highlight:listhightlight
        focus: true
        onCurrentItemChanged: console.log(model.get(list.currentIndex).name + ' selected')
    }
}
반응형

+ Recent posts