ユーザ用ツール

QMLで7セグメント風表示

SevenSeg.qml
import QtQuick
 
Canvas {
    id: canvas
    width: 100; height: 160
 
    // 入力プロパティ
    property int value: 0
    property bool showDot: false
    property real reading: 0    // 現在のセンサー数値
    property real threshold1: 0 // アンバーになる値
    property real threshold2: 0 // 赤になる値
 
    // デザイン設定
    property real skewAngle: 8
    property real gap: 4
    property real thickness: 16
 
    // 状態に基づいた色の自動判定
    readonly property color activeColor: {
        if (reading >= threshold2) return "#CC0000"; // やや暗めの赤
        if (reading >= threshold1) return "#FFBF00"; // アンバー
        return "#006622"; // 通常時の暗めの緑
    }
    readonly property color inactiveColor: "#051505" // 消灯時(背景に馴染ませる)
 
    // 再描画トリガー
    onActiveColorChanged: requestPaint()
    onValueChanged: requestPaint()
    onShowDotChanged: requestPaint()
 
    antialiasing: true
 
    onPaint: {
        var ctx = getContext("2d");
        ctx.reset();
        ctx.clearRect(0, 0, width, height);
 
        var angleRad = skewAngle * Math.PI / 180;
        ctx.transform(1, 0, -Math.tan(angleRad), 1, height * Math.tan(angleRad), 0);
 
        var p = [
            0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x6F
        ][value % 10] || 0;
 
        function drawShape(points, on) {
            ctx.beginPath();
            ctx.moveTo(points[0].x, points[0].y);
            for (var i = 1; i < points.length; i++) ctx.lineTo(points[i].x, points[i].y);
            ctx.closePath();
            ctx.fillStyle = on ? activeColor : inactiveColor;
            // 閾値を超えた時だけ少し光らせる演出
            ctx.shadowBlur = (on && reading >= threshold1) ? 10 : 0;
            ctx.shadowColor = activeColor;
            ctx.fill();
        }
 
        var w = width * 0.75;
        var h = height;
        var t = thickness;
        var g = gap;
 
        // セグメント座標計算 (六角形)
        drawShape([{x:t+g, y:0}, {x:w-t-g, y:0}, {x:w-t*1.5-g, y:t}, {x:t*1.5+g, y:t}], p & 0x01); // A
        drawShape([{x:w-t, y:t+g}, {x:w, y:t*1.5+g}, {x:w, y:h/2-t/2-g}, {x:w-t, y:h/2-g}], p & 0x02); // B
        drawShape([{x:w-t, y:h/2+g}, {x:w, y:h/2+t/2+g}, {x:w, y:h-t*1.5-g}, {x:w-t, y:h-t-g}], p & 0x04); // C
        drawShape([{x:t*1.5+g, y:h-t}, {x:w-t*1.5-g, y:h-t}, {x:w-t-g, y:h}, {x:t+g, y:h}], p & 0x08); // D
        drawShape([{x:0, y:h/2+t/2+g}, {x:t, y:h/2+g}, {x:t, y:h-t-g}, {x:0, y:h-t*1.5-g}], p & 0x10); // E
        drawShape([{x:0, y:t*1.5+g}, {x:t, y:t+g}, {x:t, y:h/2-g}, {x:0, y:h/2-t/2-g}], p & 0x20); // F
        drawShape([{x:t+g, y:h/2}, {x:t*1.5+g, y:h/2-t/2}, {x:w-t*1.5-g, y:h/2-t/2}, {x:w-t-g, y:h/2}, {x:w-t*1.5-g, y:h/2+t/2}, {x:t*1.5+g, y:h/2+t/2}], p & 0x40); // G
 
        // ドット
        ctx.beginPath();
        ctx.arc(w + t/2, h - t/2, t/2.5, 0, Math.PI * 2);
        ctx.fillStyle = showDot ? activeColor : inactiveColor;
        ctx.fill();
    }
}
SevenSegMulti.qml
import QtQuick
 
Row {
    id: root
    spacing: 10
 
    // 入力プロパティ
    property real reading: 0
    property int digits: 4      // 表示する桁数
    property int decimalPlaces: 0 // 小数点以下の桁数(0なら整数)
    property real threshold1: 0
    property real threshold2: 0
 
    // デザイン設定(SevenSegに引き継ぐ)
    property color activeColor: "green" // 基本色(SevenSeg側で上書きも可)
    property real skewAngle: 8
    property real thickness: 16
 
    Repeater {
        model: root.digits
 
        SevenSeg {
            // 左から数えて何番目の桁かを計算
            // index 0 が一番左(大きい桁)
            readonly property int power: root.digits - index - 1 - root.decimalPlaces
 
            value: Math.floor(Math.abs(root.reading) / Math.pow(10, power)) % 10
 
            // 小数点の位置判定
            showDot: (root.decimalPlaces > 0 && power === 0)
 
            // 共通プロパティの流し込み
            reading: root.reading
            threshold1: root.threshold1
            threshold2: root.threshold2
            skewAngle: root.skewAngle
            thickness: root.thickness
 
            // 桁が足りない場合にゼロを暗くするか消すロジック(オプション)
            opacity: (power > 0 && Math.pow(10, power) > Math.abs(root.reading) && index < root.digits - root.decimalPlaces - 1) ? 0.2 : 1.0
        }
    }
}
Main.qml
import QtQuick
 
Window {
    visible: true
    width: 600; height: 400
    color: "black"
 
    Column {
        anchors.centerIn: parent
        spacing: 40
 
        // CO2濃度 (4桁整数)
        SevenSegMulti {
            reading: 1250
            digits: 4
            threshold1: 1000
            threshold2: 2000
        }
 
        // 温度 (3桁、小数点1位固定)
        SevenSegMulti {
            reading: 28.5
            digits: 3
            decimalPlaces: 1
            threshold1: 30
            threshold2: 35
        }
 
        // 湿度 (2桁整数)
        SevenSegMulti {
            reading: 55
            digits: 2
            threshold1: 70
            threshold2: 80
        }
    }
}
TitleBar.qml
TitleBar {
	id: root
 
	property string text: "タイトル"
	property string font: "Noto Serif JP"
	property string fontSize: 24
	property string backgroundColor: "#000000"
	property string foregroundColor: "#FF7F00"
	Item {
		Rectangle {
			anchors.fill: parent
			gradient: Gradient {
				orientation: Gradient.Horizontal
				GradientStop { position: 0.0; color: "#FF0000" }
				GradientStop { position: 0.5; color: "#00FF00" }
				GradientStop { position: 1.0; color: "#0000FF" }
			}
			padding: 0
 
			Canvas {
				id: canvas
				anchors.fill: parent
				property real labelHeight: label.contentHeight
				property real labelWidth: label.contentWidth
 
				onPaint: {
					var ctx = getContext("2d")
					ctx.reset()
					ctx.clearRect(0, 0, width, height)
					ctx.beginPath()
					ctx.moveTo(0, 0)
					ctx.lineTo(labelWidth + 20, 0)
					ctx.lineTo(labelWidth + 20 + height / 4, height / 2)
					ctx.lineTo(width - 1, height / 2)
					ctx.lineTo(width - 1, height - 1)
					ctx.lineTo(0, height - 1)
					ctx.closePath()
					ctx.fillStyle = "#000000"
					ctx.fill()
				}
 
				Text {
					id: label
					text: root.text
					color: root.foregroundColor
					font.family: root.font
					font.pixelSize: root.fontSize
					horizontalAlignment: Text.AlignLeft
					verticalAlignment: Text.AlignTop
					padding: 10
				}
			}
		}
	}
}

This website uses cookies. By using the website, you agree with storing cookies on your computer. Also, you acknowledge that you have read and understand our Privacy Policy. If you do not agree, please leave the website.

More information