c++计时器

实现思路

这里简单介绍一下我的实现思路:

1、简单版:简单版本只实现了单次计时功能,即每次开启程序后就开始计时,如果按下键盘任意键,就结束计时,计时通过Sleep(1000)延时实现,每过1秒,计数值(总秒数)cnt加1,打印时,将总秒数cnt转换成时分秒进行显示。【Sleep()函数并不准确,只能实现粗略延时】

2、高级版:实现毫秒级计时,可重复计时(暂停、清零),计时使用gettimeofday()函数,用来获取系统的秒数和毫秒数,将计时开始和计时暂停的秒数相减,即可获得计时期间的秒数。细节请看代码部分。

简易版本

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

#include <stdio.h>

#include <conio.h>              //kbhit()/_kbhit()

#include <Windows.h>            //Sleep(ms)

int main()

{

    int hour = 0, min = 0, sec = 0;

    int cnt = 0;

    printf("按任意键停止计时\n");

    while(!_kbhit())            //任意键退出循环(结束计时)

    {

        hour = cnt / 3600;      //获取计时小时数

        min = cnt / 60;          //获取计时分钟数

        sec = cnt % 60;         //获取计时秒数

        printf("  %02d:%02d:%02d\r", hour, min, sec);

        Sleep(1000);            //1s延时

        cnt++;

    }

    printf("\n程序退出\n");

    return 0;

}

运行效果:

高级版本

代码可能一般,但至少功能已经实现,仅供参考

下面给出几个注释的解释:

  • 计时初始时间指的是开始计时或继续计时时的系统时间(第一次暂停后,如果继续计时,此时的系统时间即为新的计时初始时间)
  • 当前累计计时时长指的是从开始计时到当前时刻的时间差,即真正的有效计时时长
  • 总累计计时时长指的是计时初始时间之前的计时时间,这个值只有在计时暂停时才进行更新(如第一次暂停时,总累计计时时长 = 第一次暂停的系统时间 - 开始计时时的系统时间;第二次暂停时,总累计计时长 = 总累计计时时长 + 第二次在暂停的系统时间 - 上次继续计时时的系统时间…)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

#include <stdio.h>

#include <conio.h>                 //kbhit()/_kbhit() getch()

#include <Windows.h>               //Sleep(ms)

#include <sys/time.h>              //struct timeval

#include <unistd.h>                //struct timeval

/******************************************************************************

 * @brief       获取系统当前秒数和毫秒(1970-1-1 0:0:0到现在)

 * @param tv    timeval结构体变量

 * @param tv_s  返回的秒数

 * @param tv_ms 返回的毫秒数

 ******************************************************************************/

void Get_Current_Timeval(struct timeval *tv, long *tv_s, long *tv_ms)

{

    gettimeofday(tv,NULL);      //获取1970-1-1到现在的时间保存到timeval变量

    *tv_s = tv->tv_sec;         //获取秒

    *tv_ms = tv->tv_usec / 1000;//获取毫秒

}

/******************************************************************************

 * @brief            获取两个timeval成员的差值,通过tv_s_diff和tv_ms_diff返回

 * @param tv_s_cur   当前系统时间秒数

 * @param tv_ms_cur  当前系统时间毫秒数

 * @param tv_s_old   计时初始时间(s)

 * @param tv_ms_old  计时初始时间(ms)

 * @param tv_s_diff  秒数的差值

 * @param tv_ms_diff 毫秒的差值

 ******************************************************************************/

void Get_Diff_Timeval(long tv_s_cur, long tv_ms_cur,\

                      long tv_s_old, long tv_ms_old,\

                      long *tv_s_diff, long *tv_ms_diff)

{

    if(tv_ms_cur < tv_ms_old)

    {

        *tv_ms_diff = tv_ms_cur + 1000 - tv_ms_old;  //获取这段时间的毫秒数

        *tv_s_diff = tv_s_cur - tv_s_old - 1; //获取这段时间的秒数(自上次暂停或自初始时间)

    }

    else

    {

        *tv_ms_diff = tv_ms_cur - tv_ms_old;  //获取这段时间的毫秒数(自上次暂停或自初始时间)

        *tv_s_diff = tv_s_cur - tv_s_old;     //获取这段时间的秒数(自上次暂停或自初始时间)

    }

}

/******************************************************************************

 * 主函数

 * ****************************************************************************/

int main(void)

{

    struct timeval tv;

    long tv_s_cur = 0, tv_ms_cur = 0;   //当前系统时间

    long tv_s_old = 0, tv_ms_old = 0;   //计时初始时间

    long tv_s_diff = 0, tv_ms_diff = 0; //存放时间的差值

    int sec_cnt = 0, msec_cnt = 0;      //当前累计计时时长

    int hour = 0, min = 0, sec = 0, msec = 0;

    int timer_step = 0;                 //计时步骤 0:未开始,

                                        //1:开始,2:暂停

    char key = 0;

    /**************** 菜单打印 ****************/

    printf("================================\n"); //菜单

    printf("| 空格:开始/暂停 R:清零 Q:退出 |\n");

    printf("================================\n");

    printf("\t%02d:%02d:%02d %02d\r", 0, 0, 0, 0);

    while(1)

    {

        /**************** 键盘按键扫描+操作 ****************/

        key = 0;

        if(_kbhit())                      //检测到按键按下

            key = getch();                //读取按键

        switch(key)

        {

            case ' ':                     //按空格键开始/暂停计时

                if(timer_step == 0)       //如果还未开启计时

                {

                    //获取当前秒和毫秒作为计时初始时间

                    Get_Current_Timeval(&tv, &tv_s_old, &tv_ms_old);

                    timer_step = 1;       //开始计时

                }

                else if(timer_step == 1)  //如果正在计时

                {

                    timer_step = 2;       //暂停计时

                    //获取当前秒和毫秒

                    Get_Current_Timeval(&tv, &tv_s_cur, &tv_ms_cur);

                    //获取当前系统时间与计时初始时间的差值

                    Get_Diff_Timeval(tv_s_cur, tv_ms_cur, tv_s_old,\

                                     tv_ms_old, &tv_s_diff, &tv_ms_diff);

                    msec_cnt += tv_ms_diff;       //更新总累计计时时长(ms)

                    if(msec_cnt >= 1000)

                    {

                        msec_cnt -= 1000;

                        sec_cnt += tv_s_diff + 1; //更新总累计计时时长(s)

                    }

                    else

                        sec_cnt += tv_s_diff;

                }

                else if(timer_step == 2)

                {

                    timer_step = 1;                //继续计时

                    //获取当前秒和毫秒

                    Get_Current_Timeval(&tv, &tv_s_cur, &tv_ms_cur);

                    tv_s_old = tv_s_cur;           //更新计时初始时间(s)

                    tv_ms_old = tv_ms_cur;         //更新计时初始时间(ms)

                }

                break;

            case 'r':                     //按r/R清零计时时间

            case 'R':

                sec_cnt = msec_cnt = 0;   //总累计计时值清零

                tv_s_old = tv_s_cur;      //更新计时初始时间(s)

                tv_ms_old = tv_ms_cur;    //更新计时初始时间(ms)

                timer_step = 0;           //回到步骤0(未开始计时)

                printf("\t%02d:%02d:%02d %02d\r", 0, 0, 0, 0);

                break;

            case 'q':

            case 'Q': printf("程序退出\n");return 0;

        }

        /**************** 计时操作 ****************/

        if(timer_step == 1)

        {

            //获取当前秒和毫秒

            Get_Current_Timeval(&tv, &tv_s_cur, &tv_ms_cur);

            //获取当前系统时间与计时初始时间的差值

            Get_Diff_Timeval(tv_s_cur, tv_ms_cur, tv_s_old,\

                             tv_ms_old, &tv_s_diff, &tv_ms_diff);

            tv_ms_diff += msec_cnt;          //当前累计计时时长(ms)

            if(tv_ms_diff >= 1000)

            {

                tv_ms_diff -= 1000;

                tv_s_diff += sec_cnt + 1;    //当前累计计时时长(s)

            }

            else

                tv_s_diff += sec_cnt;

            hour = tv_s_diff / 3600;         //获取计时小时数

            min = tv_s_diff /60;             //获取计时分钟数

            sec = tv_s_diff % 60;            //获取计时秒数

            msec = tv_ms_diff / 10;          //获取毫秒(单位10ms)

            //打印当前累计计时时长

            printf("\t%02d:%02d:%02d %02d\r", hour, min, sec, msec);

        }

        Sleep(10);       //10ms延时,防止打印太快导致显示效果不佳

    }

    return 0;

}

运行效果:

C++中,可以使用Windows API中的SetTimer函数来创建一个计时器,该函数的原型如下: ``` UINT_PTR SetTimer( HWND hWnd, // 窗口句柄 UINT_PTR nIDEvent, // 计时器标识符 UINT uElapse, // 计时间隔,单位为毫秒 TIMERPROC lpTimerFunc// 计时器回调函数 ); ``` 其中,hWnd参数是要接收计时器消息的窗口句柄,nIDEvent是计时器的标识符,可以用于取消计时器,uElapse是计时间隔,单位是毫秒,lpTimerFunc是计时器回调函数,当计时器到达指定时间时,系统会发送一个WM_TIMER消息给指定窗口,同时调用回调函数。 以下是一个简单的示例代码,实现了每秒钟在窗口标题中显示当前时间: ```c++ #include <Windows.h> #include <string> LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: // 创建一个每秒钟触发一次的计时器 SetTimer(hWnd, 1, 1000, NULL); break; case WM_TIMER: if (wParam == 1) { // 获取当前时间 SYSTEMTIME st; GetLocalTime(&st); std::wstring title = L"Current Time: "; title += std::to_wstring(st.wHour) + L":" + std::to_wstring(st.wMinute) + L":" + std::to_wstring(st.wSecond); // 更新窗口标题 SetWindowText(hWnd, title.c_str()); } break; case WM_DESTROY: // 销毁计时器 KillTimer(hWnd, 1); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 注册窗口类 WNDCLASS wc = { 0 }; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = L"TimerDemo"; RegisterClass(&wc); // 创建窗口 HWND hWnd = CreateWindow(L"TimerDemo", L"Timer Demo", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } // 显示窗口 ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // 消息循环 MSG msg = { 0 }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } ``` 该示例代码中,我们在窗口创建时创建了一个每秒钟触发一次的计时器,并在计时器回调函数中获取当前时间,并将其显示在窗口标题中。在窗口销毁时,我们销毁了计时器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值