DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 3020|回复: 0
打印 上一主题 下一主题

[待整理] LabWindows/CVI虚拟仪器设计技术场景与游戏设计之:时钟制作

[复制链接]
跳转到指定楼层
楼主
发表于 2014-10-12 07:21:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
4.2 时钟制作
        4.2.1 时钟制作设计方法
        模拟时钟设计相对于数字时钟要复杂很多,不但要考虑时间问题,还要考虑时针、分针、秒针的角度变化以及重新绘制等问题。与其他编程工具不同,在LabWindows/CVI 中,没有线类对象与控件,只是在Canvas 控件中存在画线属性,钟表指针绘制完成后,经过下一个时刻需要移动一个角度,则需要重新绘制一个新的指针,旧指针应当及时擦除,因此,时钟指针绘制相对于其他开发工具难度较大。
         
        类似于其他开发工具如Visual Basic 用Line 控件显示水平线、垂直线与斜线,在Canvas 控件中可以绘制各种类型的线。对于指针式钟表而言,需要设置指针坐标的起点X1、Y1 和终点X2、Y2,并且要实时改变指针(线)的长度、位置和倾斜角度,利用Timer 控件定时触发回调事件,查询系统时间并控制指针转动,实现时钟的动态模拟。由于Timer 控件在Windows 操作系统中并不是精确触发的,每次触发的时间间隔不能保证完全相同,因此,只能用它来做定时查询,而不能用作计时器。
         
        对于模拟钟表指针的绘制,则需要利用一些数学算法。实际上,指针转动可以理解为圆的轨迹与角度的关系,如图4-3 所示。
         
        经推导,设原点为(X1, Y1),半径为r,圆上任意点坐标(X2, Y2)与12 点钟方向的顺时针夹角与α角的关系为:
        X2 =X1+r×sin α
        Y2 =Y1−r×cos α
         
        绘制指针时应注意,秒针采用红色线型且细长,分针为蓝色粗细居中,时针短粗为白色,在采用Canvas 控件绘制线形时,ATTR_PEN_COLOR 与ATTR_PEN_WIDTH 为必须设置的属性。此外,指针每移动一步需要重新绘制一次,前一次绘制的图形则需要擦除,擦除方式为将前一次绘制的直线再以底色(黑色)重新再在原位置绘制一次。
         
        4.2.2 时钟制作程序设计
        (1)面板设计
        编写一个模拟时钟程序,在面板上显示表盘、秒针、分针、时针和中心轴,并在标题栏实时显示数字时钟。时钟底盘为Canvas 控件,设置为黑色,数字标签使用Text Message 控件,设置颜色为绿色,并设置控件透明背景,中心轴采用Decoration 控件,指针在运行时实时绘制,通过Timer 控件触发使其转动。面板设计如图4-4 所示,面板中主要控件属性设置如表4-4 所示。
       

        图4-3 指针转动轨迹与角度的关系         图4-4 时钟制作面板

         
        表4-4 控件属性设置表
                               
                                        常量名

                       
                               
                                        控件类型

                       
                               
                                        控件的主要属性

                       
                               
                                        PANEL

                       
                               
                                        Panel

                       
                               
                                        标题:时钟制作回调函数:PanelCB

                       
                               
                                        CANVAS

                       
                               
                                         Canvas

                       
                               
                                        ( 时钟底盘)

                       
                               
                                        TIMER

                       
                               
                                         Timer

                       
                               
                                        回调函数:timer

                       
                               
                                        TEXTMSG_1

                       
                               
                                        Text Message

                       
                               
                                        默认值:1

                       
                               
                                        TEXTMSG_2

                       
                               
                                        Text Message

                       
                               
                                        默认值:2

                       
                               
                                        TEXTMSG_3

                       
                               
                                        Text Message

                       
                               
                                        默认值:3

                       
                               
                                        TEXTMSG_4

                       
                               
                                        Text Message

                       
                               
                                        默认值:4

                       
                               
                                        TEXTMSG_5

                       
                               
                                        Text Message

                       
                               
                                        默认值:5

                       
                               
                                        TEXTMSG_6

                       
                               
                                        Text Message

                       
                               
                                        默认值:6

                       
                               
                                        TEXTMSG_7

                       
                               
                                        Text Message

                       
                               
                                        默认值:7

                       
                               
                                        TEXTMSG_8

                       
                               
                                        Text Message

                       
                               
                                        默认值:8

                       
                               
                                        TEXTMSG_9

                       
                               
                                        Text Message

                       
                               
                                        默认值:9

                       
                               
                                        TEXTMSG_10

                       
                               
                                        Text Message

                       
                               
                                        默认值:10

                       
                               
                                        TEXTMSG_11

                       
                               
                                         Text Message

                       
                               
                                        默认值:11

                       
                               
                                        TEXTMSG_12

                       
                               
                                        Text Message

                       
                               
                                        默认值:12

                       
         
        (2)程序源代码
        //头文件声明
        #include <ansi_c.h>
        #include <utility.h>
        #include <cvirte.h>
        #include <userint.h>
        #include "时钟制作.h"
        static int panelHandle;
        //主函数
        int main (int argc, char *argv[])
        {
        int i;
        if (InitCVIRTE (0, argv, 0) == 0)
        return &ndash;1;  /* out of memory */
        if ((panelHandle = LoadPanel (0, " 时钟制作.uir", PANEL)) < 0)
        return &ndash;1;
        //设置表盘数字底色透明
        for (i = 2; i < 14; i ++)
        {
        SetCtrlAttribute (panelHandle, i, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        }
        //调用定时器回调函数
        timer (panelHandle, PANEL_TIMER, EVENT_TIMER_TICK, NULL, NULL, NULL);
        DisplayPanel (panelHandle);
        RunUserInterface ();
        DiscardPanel (panelHandle);
        return 0;
        }
        //面板回调函数
        int CVICALLBACK PanelCB (int panel, int event, void *callbackData,
        int eventData1, int eventData2)
        {
        switch (event)
        {
        case EVENT_CLOSE:
        QuitUserInterface (0);
        break;
        }
        return 0;
        }
        //定时器
        int CVICALLBACK timer (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2)
        {
        char *timestr;
        char CurTime[50];
        int Seconds;
        int Minutes;
        int Hours;
        int sdeg;
        int mdeg;
        int hdeg;
        double srad;
        double mrad;
        double hrad;
        //记录表盘指针状态
        static int sx2,sy2,soldx2,soldy2;
        static int mx2,my2,moldx2,moldy2;
        static int hx2,hy2,holdx2,holdy2;
        switch (event)
        {
        case EVENT_TIMER_TICK:
        // 获得系统时间
        GetSystemTime (&Hours, &Minutes, &Seconds);
        // 转换为角度
        sdeg = Seconds * 6;
        mdeg = Minutes * 6;
        hdeg = Hours * 30 + (0.5 * Minutes);
        // 设置秒针参数
        // 设置Canvas 控件绘图笔宽度
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_WIDTH, 2);
        soldx2 = sx2;
        soldy2 = sy2;
        // 转换为弧度
        srad = (3.14 / 180) * sdeg;
        // 擦除上一次绘制图形
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_COLOR, VAL_BLACK);
        CanvasDrawLine (panelHandle, PANEL_CANVAS, MakePoint (150,150), MakePoint (soldx2,
        soldy2));
        // 计算指针末端位置
        sx2 = 150 + 100 * sin(srad);
        sy2 = 150 &ndash; 100 * cos(srad);
        // 绘制新图形
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_COLOR, VAL_RED);
        CanvasDrawLine (panelHandle, PANEL_CANVAS, MakePoint (150,150), MakePoint (sx2,sy2));
        // 设置分针参数
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_WIDTH, 4);
        moldx2 = mx2;
        moldy2 = my2;
        mrad = (3.14 / 180) * mdeg;
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_COLOR, VAL_BLACK);
        CanvasDrawLine (panelHandle, PANEL_CANVAS, MakePoint (150,150), MakePoint (moldx2,
        moldy2));
        mx2 = 150 + 80 * sin(mrad);
        my2 = 150 &ndash; 80 * cos(mrad);
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_COLOR, VAL_BLUE);
        CanvasDrawLine (panelHandle, PANEL_CANVAS, MakePoint (150,150), MakePoint (mx2,my2));
        // 设置时针参数
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_WIDTH, 6);
        holdx2 = hx2;
        holdy2 = hy2;
        hrad = (3.14 / 180) * hdeg;
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_COLOR, VAL_BLACK);
        CanvasDrawLine (panelHandle, PANEL_CANVAS, MakePoint (150,150), MakePoint (holdx2,
        holdy2));
        hx2 = 150 + 65 * sin(hrad);
        hy2 = 150 &ndash; 65 * cos(hrad);
        SetCtrlAttribute (panelHandle, PANEL_CANVAS, ATTR_PEN_COLOR, VAL_WHITE);
        CanvasDrawLine (panelHandle, PANEL_CANVAS, MakePoint (150,150), MakePoint (hx2,hy2));
        // 获得当前时间字符串
        timestr = TimeStr ();
        CurTime[0] = &#39;\0&#39;;
        strcat (CurTime, " 当前时间:");
        strcat (CurTime, timestr);
        // 标题栏显示当前时间
        SetPanelAttribute (panelHandle, ATTR_TITLE, CurTime);
        break;
        }
        return 0;
        }
       
         
         
        3:程序注释
        ①设置透明背景在程序中,采用了SetCtrlAttribute 函数的VAL_TRANSPARENT 属性将Text Message 控件的背景设置为透明。对于12 个数字标签,需要重复设置VAL_TRANSPARENT ,其代码为:
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_1, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_2, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_3, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_4, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_5, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_6, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_7, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_8, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_9, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_10, ATTR_TEXT_BGCOLOR,VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_11, ATTR_TEXT_BGCOLOR,VAL_TRANSPARENT);
        SetCtrlAttribute (panelHandle, PANEL_TEXTMSG_12, ATTR_TEXT_BGCOLOR,VAL_TRANSPARENT);
         
        但是,这种设置方式重复工作量较大,代码大量冗余,容易出现错误,可以采用循环结构优化代码设计,即主函数中使用的代码:
        for (i = 2; i < 14; i ++)
        {
        SetCtrlAttribute (panelHandle, i, ATTR_TEXT_BGCOLOR, VAL_TRANSPARENT);
        }
         
        采用此种代码方式,需要控制每个Text Message 控件的Tab Order 属性,使自动生成的“时钟制作.h”文件控件常量值遵从一定顺序,即:
        #include <userint.h>
        #ifdef __cplusplus
        extern "C" {
        #endif
        #define
        PANEL
        1
        #define
        PANEL_TEXTMSG_1
        2
        #define
        PANEL_TEXTMSG_2
        3
        #define
        PANEL_TEXTMSG_3
        4
        #define
        PANEL_TEXTMSG_4
        5
        #define
        PANEL_TEXTMSG_5
        6
        #define
        PANEL_TEXTMSG_6
        7
        #define
        PANEL_TEXTMSG_7
        8
        #define
        PANEL_TEXTMSG_8
        9
        #define
        PANEL_TEXTMSG_9
        10
        #define
        PANEL_TEXTMSG_10
        11
        #define
        PANEL_TEXTMSG_11
        12
        #define
        PANEL_TEXTMSG_12
        13
        #define
        PANEL_CANVAS
        14
        #define
        PANEL_TIMER
        15
        #define
        PANEL_DECORATION
        16
        int CVICALLBACK PanelCB(int panel, int event, void *callbackData, int eventData1, int eventData2);
        int CVICALLBACK timer(int panel, int control, int event, void *callbackData, int eventData1, int eventData2); #ifdef __cplusplus
         }
        #endif
         
        ①设置方法为,首先打开“时钟制作.uir”文件使其处于编辑状态,选择菜单Edit→Tab Order..., 弹出Edit Tabbing Order 对话框,如图4-5 所示,按顺序依次点击标签,最后点击OK 按钮完成设置,选择菜单File→Save All,保存所有改动,此时头文件中Text Message 控件将更新为以上顺序,方便程序设计。
       

        4-5 Edit Tabbing Order 对话框

         
        ② 界面显示问题
        在主函数中还调用了Timer 回调函数,其实,如果不是为了界面的美观设计,也可以将以下代码去掉:
        timer (panelHandle, PANEL_TIMER, EVENT_TIMER_TICK, NULL, NULL, NULL);
        如果不写入此代码,界面刚显示时没有指针,过一会儿指针才显示出来,这主要是由LabWindows/CVI 函数调用机制所决定的,启动面板逻辑要高于控件逻辑。
         
        ③ GetSystemTime 函数
        以数字形式获得系统时间。需要注意的是,在Windows API 中也包含GetSystemTime 函数,如果在程序中引用了windows.h 头文件而没有引用utility.h 头文件,可能会出现编译错误。函数原型为:int GetSystemTime (int *Hours, int *Minutes, int *Seconds);
         *Hours:系统时间中的小时数,取值范围为0~23。
         *Minutes :系统时间中的分钟数,取值范围为0~59。
         *Seconds:系统时间中的秒数,取值范围为0~59。
         
        ④ TimeStr 函数返回8 字节时间字符串,格式为HH:MM:SS(时分秒)。函数原型为:
        char *TimeStr (void);
        返回值:返回时间字符串指针。
         
        ⑤ CanvasDrawLine 函数
        在两个确定点之间绘制直线。绘制直线使用的属性包括:ATTR_PEN_COLOR 、ATTR_PEN_MODE 、ATTR_PEN_WIDTH 和ATTR_PEN_STYLE (当线的粗细大于1 个像素时忽略此设置),用SetCtrlAttribute 函数设置。函数原型为:
        int CanvasDrawLine (int Panel_Handle, int Control_ID, Point Start, Point End);
        Start :绘制点的起始值。Point 为结构体类型,定义为:
        typedef struct
        {
        intx;   inty;
        } Point;
        如果不想定义一个结构体变量,则可采用如下函数:
        Point MakePoint (int x, int y);
        MakePoint 函数定义一个二维点,其中参数x 和y 分别是X和Y轴坐标。
         
        (4)运行效果图
        点击工具栏中的Debug Project 按钮,程序开始运行,其效果如图4-6 所示。
       

        4-6 运行效果图

         

        相关阅读
        《虚拟仪器技术,将“软件就是仪器”进行到底!》
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2024-11-15 15:24 , 耗时 0.097306 秒, 21 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表