WPF工控组态软件之温度计

2023-11-15

WPF以其丰富灵活的控件样式设计,相较于WinForm而言,一直是工控组态软件的宠儿。经过前两文章的学习,已经对WPF开发工控组态软件有了一个基本的了解, 今天继续学习温度计的开发,仅供学习分享使用,如有不足之处,还请指正。

415cb0a3ebba3a4230ab07c399d73653.png

涉及知识点

 在本示例中,主要知识点如下:

  • WPF阴影效果,线性渐变的设置,主要设置温度计的边框,填充等效果,形成一种金属质感。

  • WPF依赖属性设置,主要设置最大温度,最低温度,和当前温度值

  • WPF线条绘制,主要用于刻度

温度计截图

本示例主要实现功能为自定义刻度值,以及水银条随着当前温度值变化。具体如下所示:

023c88dc5785b26fe318013a94ddfe8c.png

温度计源码

示例源码分为以下2个部分:

1. Thermometer控件

Thermometer控件布局

<UserControl x:Class="WpfControl.UserControls.Thermometer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:WpfControl.UserControls"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="150">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Rectangle StrokeThickness="7" RadiusX="40" RadiusY="15" Fill="White" />
        <Rectangle StrokeThickness="7" RadiusX="40" RadiusY="15">
            <Rectangle.Effect>
                <DropShadowEffect ShadowDepth="0" Direction="0" BlurRadius="7" />
            </Rectangle.Effect>
            <Rectangle.Stroke>
                <LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
                    <LinearGradientBrush.RelativeTransform>
                        <RotateTransform Angle="40" CenterX="0.5" CenterY="0.5" />
                    </LinearGradientBrush.RelativeTransform>
                    <GradientStop Color="Black" />
                    <GradientStop Color="White" Offset="0.7" />
                </LinearGradientBrush>
            </Rectangle.Stroke>
        </Rectangle>
        <TextBlock Text="℃" HorizontalAlignment="Center" VerticalAlignment="Top" FontWeight="Bold" FontSize="20" Margin="0, 20" Foreground="#555"/>
        <Canvas Name="MainCanvas" Width="75" Margin="0,70" />
        <Border Width="10" RenderTransformOrigin="0.5,0.5" CornerRadius="5" Margin="0,50">
            <Border.Effect>
                <DropShadowEffect ShadowDepth="0" Direction="0" Color="White" />
            </Border.Effect>
            <Border.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                    <GradientStop Color="lightGray" Offset="0" />
                    <GradientStop Color="White" Offset="0.4" />
                    <GradientStop Color="lightGray" Offset="1" />
                </LinearGradientBrush>
            </Border.Background>
            <Border Height="75" VerticalAlignment="Bottom" Name="BorValue">
                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                        <GradientStop Color="#CD3333"  />
                        <GradientStop Color="#FFC0CB" Offset="0.4" />
                        <GradientStop Color="#CD3333" Offset="1" />
                    </LinearGradientBrush>
                </Border.Background>
            </Border>
        </Border>
        <Border Height="25" Width="25" CornerRadius="15" VerticalAlignment="Bottom" Margin="0 0 0 30">
            <Border.Effect>
                <DropShadowEffect Direction="0" ShadowDepth="0" />
            </Border.Effect>
            <Border.Background>
                <RadialGradientBrush Center="0.3,0.2" GradientOrigin="0.4,0.4">
                    <GradientStop Color="White" Offset="0" />
                    <GradientStop Color="#CD3333" Offset="1" />
                </RadialGradientBrush>
            </Border.Background>
        </Border>
        <TextBox Grid.Row="1" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" HorizontalContentAlignment="Center" BorderThickness="0" BorderBrush="AliceBlue" VerticalAlignment="Bottom" FontSize="20" Name="ThermometerValue" />
    </Grid>
</UserControl>

依赖属性设置及后台生成刻度源码,如下所示:

namespace WpfControl.UserControls
{
    /// <summary>
    /// Thermometer.xaml 的交互逻辑
    /// </summary>
    public partial class Thermometer : UserControl
    {
        public int Minmum
        {
            get { return (int)GetValue(MinmumProperty); }
            set { SetValue(MinmumProperty, value); }
        }

        public static readonly DependencyProperty MinmumProperty =
            DependencyProperty.Register("Minmum", typeof(int), typeof(Thermometer), new PropertyMetadata(1, new PropertyChangedCallback(OnPropertyValueChanged)));


        public int Maxmum
        {
            get { return (int)GetValue(MaxmumProperty); }
            set { SetValue(MaxmumProperty, value); }
        }

        public static readonly DependencyProperty MaxmumProperty =
            DependencyProperty.Register("Maxmum", typeof(int), typeof(Thermometer), new PropertyMetadata(10, new PropertyChangedCallback(OnPropertyValueChanged)));



        public double Value
        {
            get { return (double)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value);}
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(double), typeof(Thermometer), new PropertyMetadata(0.0, new PropertyChangedCallback(OnPropertyValueChanged)));

        /// <summary>
        /// 当属性值发生变化的时候直接更新UI内容
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as Thermometer)?.RefreshComponet();
        }

        private double step = 10;

        public Thermometer()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        /// <summary>
        /// 刷新温度计上面的内容适应定义大小
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void RefreshComponet()
        {
            // 两种方式触发:尺寸变化、区间变化
            var h = this.MainCanvas.ActualHeight;//通过这个判断界面元素是否加载
            if (h == 0) return;
            double w = 75;
            // 类型
            double stepCount = Maxmum - Minmum;// 在这个区间内多少个间隔
            step = h / (Maxmum - Minmum);// 每个间隔距离

            this.MainCanvas.Children.Clear();

            for (int i = 0; i <= stepCount; i++)
            {
                Line line = new Line();
                line.Y1 = i * step;
                line.Y2 = i * step;
                line.Stroke = Brushes.Black;
                line.StrokeThickness = 1;
                this.MainCanvas.Children.Add(line);

                if (i % 10 == 0)
                {
                    line.X1 = 15;
                    line.X2 = w - 15;

                    // 添加文字
                    TextBlock text = new TextBlock
                    {
                        Text = (Maxmum - i).ToString(),
                        Width = 20,
                        TextAlignment = TextAlignment.Center,
                        FontSize = 9,
                        Margin = new Thickness(0, -5, -4, 0)
                    };
                    Canvas.SetLeft(text, w - 15);
                    Canvas.SetTop(text, i * step);
                    this.MainCanvas.Children.Add(text);

                    // 添加文字
                    text = new TextBlock
                    {
                        Text = (Maxmum - i).ToString(),
                        Width = 20,
                        TextAlignment = TextAlignment.Center,
                        FontSize = 9,
                        Margin = new Thickness(-4, -5, 0, 0)
                    };
                    Canvas.SetLeft(text, 0);
                    Canvas.SetTop(text, i * step);
                    this.MainCanvas.Children.Add(text);
                }
                else if (i % 5 == 0)
                {
                    line.X1 = 20;
                    line.X2 = w - 20;
                }
                else
                {
                    line.X1 = 25;
                    line.X2 = w - 25;
                }
            }
            ValueChanged();
        }


        private void ValueChanged() {
            // 限定值的变化范围
            var value = this.Value;
            if (this.Value < this.Minmum)
                value = this.Minmum;
            if (this.Value > this.Maxmum)
                value = this.Maxmum;

            // 温度值与Border的高度的一个转换
            var newValue = value - this.Minmum;
            newValue *= step;
            newValue += 20;

            // 动画
            DoubleAnimation doubleAnimation = new DoubleAnimation(newValue, TimeSpan.FromMilliseconds(500));
            this.BorValue.BeginAnimation(HeightProperty, doubleAnimation);
        }

    }

}

2. 控件调用

用户控件不可以独立展示,需要以窗口为载体,作为窗口的一部分展示,页面调用如下所示:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfControl"
        xmlns:UserControls="clr-namespace:WpfControl.UserControls" x:Class="WpfControl.TestWindow3"
        mc:Ignorable="d"
        Title="工控组态软件--温度计" Height="450" Width="1000" Loaded="Window_Loaded">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <UserControls:Thermometer Grid.Column="0" Grid.Row="0" x:Name="t1" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="1" Grid.Row="0" x:Name="t2" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="2" Grid.Row="0" x:Name="t3" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="3" Grid.Row="0" x:Name="t4" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="4" Grid.Row="0" x:Name="t5" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="5" Grid.Row="0" x:Name="t6" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="6" Grid.Row="0" x:Name="t7" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
        <UserControls:Thermometer Grid.Column="7" Grid.Row="0" x:Name="t8" Width="100" Height="370" HorizontalAlignment="Center"  VerticalAlignment="Center"/>
    </Grid>
</Window>

控件赋值,在窗口加载时,为控件赋初始值,如下所示:

namespace WpfControl
{
    /// <summary>
    /// TestWindow3.xaml 的交互逻辑
    /// </summary>
    public partial class TestWindow3 : Window
    {
        public TestWindow3()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var controls = new Thermometer[8] { t1, t2 , t3, t4 , t5, t6 , t7, t8 };
            for (int i = 0; i < 8; i++) {
                controls[i].Maxmum = 100;
                controls[i].Minmum = -20;
                controls[i].Value = 10*(i+1);
            }
        }
    }
}

注意:在实际业务中,可以通过对应的传输协议【如:Modbus等】从硬件获取,并实时的显示在页面中。

源码下载

b06858748d92ac850639b039db88d25b.jpeg

备注

以上就是本篇文章的全部内容,旨在抛砖引玉,共同学习,一起进步。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF工控组态软件之温度计 的相关文章

  • WPF TextBox:如何将默认绑定模式更改为 OneWay?

    最初 我有以下代码
  • 消息框按钮文本

    我环顾四周 似乎所有内容都可以在消息框中编辑 禁止按钮上的文本 WPF http en wikipedia org wiki Windows Presentation Foundation C MessageBox Show Generic
  • 如何创建自动滚动文本框

    我有一个 WPF 应用程序 其中包含一个多行文本框 用于显示调试文本输出 如何设置文本框 以便将文本附加到框中时 它会自动滚动到文本框的底部 我正在使用 MVVM 模式 理想情况下 纯 XAML 方法会很好 TextBox 本身不一定是焦点
  • wpf 的 prism 与 mvvm light

    我们正在启动一个带有 MVVM 的 WPF 项目 并且必须决定使用 PRISM 还是 MVVM Light 我对这两个框架都是新手 我已经阅读了一些帖子 但仍然有一些问题 有人可以阐明以下几个方面吗 两个框架 性能 无论出于何种原因 其中一
  • WPF 中的屏幕分辨率问题?

    我将在 WPF 中使用以下代码检测分辨率 double height System Windows SystemParameters PrimaryScreenHeight double width System Windows Syste
  • WPF。如何从另一个窗口隐藏/显示主窗口

    我有两个窗口 MainWindow 和 Login 显示登录的按钮位于主窗口 this Hide Login li new Login li Show 登录窗口上有一个检查密码的按钮 如果密码正确 我如何显示主窗口 将参数传递给 MainW
  • 树视图上下文菜单命令未触发

    我有一个绑定到某些属性类型的 Observable 集合的树视图 有一个 HierarchicalDataTemplate 在树视图中显示数据 现在我需要显示每个 HierarchicalDataTemplate 项目的特定上下文菜单 我使
  • 创建面向鼠标和触摸的 WPF 应用程序的最佳实践[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • WPF:使用 StringFormat={}{0:F2} 进行文本框绑定。不显示零

    我使用以下 XAML 将对象绑定到 TextBox
  • 在简单注入器中解析具有自定义参数的类

    我正在使用以下命令创建 WPF MVVM 应用程序简易注射器作为 DI 容器 现在 当我尝试从简单注入器解析视图时遇到一些问题 因为我需要在构造时将参数传递到构造函数中 而不是在将视图注册到容器时 因此这不是适用的 简单注入器将值传递到构造
  • 在Linux上编译C# + WPF以便在Windows上运行

    我有一个 C 应用程序 其中某些部分是使用 WPF 编写的 Mono 不支持 可以在 Linux 上编译这个应用程序吗 最终 该应用程序将在 Windows 上运行 但它是更大框架的一部分 并且我们的整个构建过程在 Linux 上运行 因此
  • WPF 中处理系统关闭

    如何在 WPF 中重写 WndProc 当我的窗口关闭时 我尝试检查我正在使用的文件是否被修改 如果是 我必须提示用户 你想保存更改吗 消息 然后关闭正在使用的文件和窗口 但是 当我的窗口仍然打开时 我无法处理用户重新启动 关闭 注销的情况
  • 如果.Net Core可以在Windows上运行,为什么不能在.Net Framework中引用.Net Core DLL?

    我明白为什么 Net Framework 可能会在 Net Core IE 中导致问题 因为不存在特定于 Windows 平台的 API 但是为什么不能直接引用 Net Core 作为 Net Framework 中的库呢 如果 Net C
  • 如何创建向后兼容 Windows 7 的缩放和尺寸更改每显示器 DPI 感知应用程序?

    我是 WPF 和 DPI 感知 API 的新手 正在编写一个在 Windows 7 8 1 和 10 中运行的应用程序 我使用具有不同每个显示器 DPI 设置的多个显示器 并且有兴趣将我的应用程序制作为跨桌面配置尽可能兼容 我已经知道可以将
  • 在哪里可以找到 WPF 应用程序中 UI 的一些主题/演示?

    我想使用 xaml 中的 Visual Studio Designer 设计一个现代外观的 UI 它为我提供了一个很好的工具箱 我可以使用它通过拖放来直观地创建 UI 由于它几乎表现得像 HTML 我想知道它是否也有丰富的主题库 我找到了一
  • 如何在 wpf 应用程序的代码隐藏中创建集合视图源

    我有以下代码 public partial class MainWindow Window public MainWindow InitializeComponent var entities new DemoEntities var de
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • WPF画布性能-children.add调用多次

    我在长画布上绘制了很多线条 想想条形图 并对其性能进行了相当好的调整 使用低级几何类并冻结它们等 这极大地提高了性能 但仍然需要几秒钟将几千个项目加载到画布中 我对应用程序进行了性能分析 看起来每次调用都花费了很大一部分时间canvas c
  • 如何在清除排序描述后删除wpf网格排序箭头

    我单击网格标题对列进行排序 然后单击 重置 按钮以通过其集合视图清除排序描述 但排序箭头图标仍然保留在标题中 如何去除它 我在尝试弄清楚如何完全清除网格中的排序时遇到了这个问题 感谢 krishnaaditya 回答如何清除标题中的排序箭头
  • 如何将文本放在 RadioButton 的顶部

    我正在尝试实现附件中显示的效果 但没有成功 甚至有可能吗 我试图将文本框放在单选按钮内 并将其设置为水平和垂直内容对齐 但它没有按我想要的方式工作 欢迎任何建议 Resource

随机推荐

  • SpringBoot+SSM+MySQL整合项目演示(不涉及前后端交互)

    文章目录 准备工作 创建项目 图1 图2 图3 图4 工程目录 代码编写 数据库 pom文件修改 完整项目目录 User类 创建一个来接收查询出来数据的对象 UserMapper接口 UserMapper xml文件配置 Service层
  • git 常用操作总结

    记录一下经常使用到的 git 操作 目录 开发新功能 拉取远程分支 开发新功能 创建 develop 分支 git branch dev 新建功能分支 根据 develop 为基础再键新的 feature 功能分支 b 是创建并且切换到改分
  • # vue# 【九】 个人中心的制作

    Z vue个人中心的制作 个人中心的制作 在实际开发里面 经常会有一些登录页需要进行编写 例如下面这些类型 而这些版面的制作 比较讲究的是思路问题 例如我们想要制作一个登录页 点击就可以输入名字 并且修改名字 整体思路 我们可以先把整体拆分
  • AV1视频编码标准资源汇总

    AV1视频编码标准资源汇总 A Progress Report The Alliance for Open Media and the AV1 Codec http www streamingmedia com Articles Edito
  • NoPrint.js:使用JavaScript在HTML中禁用打印、截屏、复制和粘贴

    NoPrint js是一个小巧整洁的开源JS库 可禁用HTML中的打印 截图 复制和粘贴功能 它还提供启用AutoBlur选项 让鼠标离开网页后内容变得模糊 这个功能可以阻止大多数普通用户截取屏幕截图 NoPrint js可以在几乎所有的浏
  • javaweb期末课设之图书管理系统(附源码)

    一 设计目标 项目是以北京航天航空大学图书管理系统为主题的网站 包含如下功能 注册 登录 用户端 图书查询及借阅 用户端 借阅记录及归还 管理员端 添加及修改图书 管理员端 管理用户信息 用户 管理员端 更改密码 二 运用的软件技术 前端设
  • Spring Boot项目pom

    spring boot web
  • VMware Workstation 虚拟机创建客户端系统,出现此主机不支持64位客户机操作系统问题解决

    安装VMware Workstation 虚拟机 选择centos7 64位是出现此主机不支持64位客户机操作系统 由于是window10系统 我们肯定是支持64的 所以硬件和系统应该是支持的才对 那么可能是哪个系统设置影响到了 有可能有下
  • 编译安装QGLViewerPlugin

    QGLViewer 编译安装步骤 由于工作学习的需要 要用opengl绘制显示些模型动画 原来用的是Qt做UI 直接调用的是QGLWidget类 但这个只是提供了基本的框架 很多交互操作还需添加代码完成 自己偷懒也觉得繁琐 就借用了开源的工
  • linux内核源码分析之页表

    目录 页表说明 虚拟地址转换为物理地址过程 内核中的宏以及说明 页表用来把虚拟页映射到物理页 并且存放页的保护单位 即访问权限 页表说明 5级页表如下 1 页全局目录 Page Global Directory PGD 2 页四级目录 Pa
  • ​Unity的50个重要技巧

    刚开始学习Unity3D时间不长 在看各种资料 除了官方的手册以外 其他人的经验也是非常有益的 偶尔看到老外这篇文章 觉得还不错 于是翻译过来和大家共享 原文地址 50 Tips for Working with Unity Best Pr
  • 区块链系统架构图_区块链模型架构

    一般说来 区块链系统由数据层 网络层 共识层 激励层 合约层和应用层组成 其中 数据层封装了底层数据区块以及相关的数据加密和时间戳等技术 网络层则包括分布式组网机制 数据传播机制和数据验证机制等 共识层主要封装网络节点的各类共识算法 激励层
  • 如何成为一名合格的互联网大厂Python工程师?

    Python开发工程师 是一个在IT行业圈子里一直都很热门的话题 无论是像腾讯 百度这样的大型公司 还是刚刚起步的初创公司 都会招python开发工程师 python已成为越来越多开发者的开发语言选择 而python开发工程师工资基本上都高
  • 投影矩阵的推导(Deriving Projection Matrices)

    本文乃 lt 投影矩阵的推导 gt 译文 原文地址为 http www codeguru com cpp misc misc math article php c10123 1 Deriving Projection Matrices ht
  • ibmmq生产事故

    ibmmq生产事故 在代码中创建了一个没使用的mq的连接对象 也没有进行资源释放 上生产前最好确保连接队列管理器的资源在流程结束后都得到了释放 disconnect 或者进行大批量报文测试 至少需要一百笔 因为ibmmq默认通道连接数是10
  • Neo4j 5的自治图数据库集群

    原文作者 John Stegeman 图数据库产品专家 Neo4j 基于原文翻译并补充整理而成 新近发布的Neo4j 版本5推出了自治集群 Autonomous Cluster 以支持易于部署 可扩展 自容错等重要特性 下面我们就来一睹自治
  • chromedp模拟键盘回车事件

    chromedp 的 SendKeys 可以模拟各种键盘事件 并且支持组合使用 假设以下场景 有一个输入框 我们想模拟键盘输入内容并回车
  • Vuforia VirtualButtons 虚拟按键

    Vuforia VirtualButtons 虚拟按键 注意 1 不介意使用Unity自带的Vuforia 引擎 否则下载商场里的示例项目时可能会因为版本问题产生报错 推荐直接从商店下载示例的引擎使用 2 不推荐下载目前最新9 2版引擎 导
  • Matlab 函数进阶:使用匿名函数和内嵌函数处理多变量传递问题(Matlab 7.0以上)

    from http asc 2dark org node 70 Matlab 函数进阶 使用匿名函数 Anonymous Function 和内嵌函数 Nested Function 处理多变量传递问题 Matlab 7 0以上 问题 有一
  • WPF工控组态软件之温度计

    WPF以其丰富灵活的控件样式设计 相较于WinForm而言 一直是工控组态软件的宠儿 经过前两文章的学习 已经对WPF开发工控组态软件有了一个基本的了解 今天继续学习温度计的开发 仅供学习分享使用 如有不足之处 还请指正 涉及知识点 在本示