65.9K
CodeProject 正在变化。 阅读更多。
Home

一个透明时钟和工作考勤检查

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.55/5 (8投票s)

2003年12月1日

2分钟阅读

viewsIcon

289196

downloadIcon

2665

一个时钟演示,但它也可以用于考勤打卡。通过在小时块上点击几下,你就可以实现它。

Sample Image - clock.gif

引言

很长一段时间以来,我一直想为我的机器写一个时钟。我不喜欢数字时钟的感觉,日复一日,年复一年,工作工作,工作…… 也许,我是一个老古董!我只喜欢新鲜的蓝天里的自由!

一个透明的时钟?它应该看起来像一块玻璃吗?或者桌面上的某些像素块,以及时针和分针周围的透明度?秒针怎么绕着中心点转动,并且明显地保持周围的透明度呢?

好吧,我决定在 Windows 2000 下编写它,因为我可以使用透明图层属性。为了实现它,我必须完成这些

首先,在 OnCreate 部分,注册一个热键,用于在您双击时针或分针时将其打开,并强制它消失。接下来,将窗口样式更改为 WS_EX_TOOLWINDOW,这样,它就会从任务栏中消失。最后,设置 WS_EX_LAYERED 属性,它会显示结果。以下是 OnCreate 部分的代码。

int CClockDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CDialog::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    m_bHotkeyReg=RegisterHotKey(GetSafeHwnd(), 
      theApp.m_hatomHotKey,MOD_ALT|MOD_CONTROL|MOD_SHIFT,VK_F12);

    CRect rc;
    GetWindowRect(&rc);
    HDC hdc=::GetDC(GetSafeHwnd());
    CSize size(GetDeviceCaps(hdc,LOGPIXELSX),GetDeviceCaps(hdc,LOGPIXELSY));
    int w=(size.cx/size.cy)*rc.Height();
    SetWindowPos(NULL,0,0,w,rc.Height(), 
      SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOREDRAW);
    ::ReleaseDC(GetSafeHwnd(),hdc);
    m_size=CSize(w,rc.Height());

    SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,WS_EX_TOOLWINDOW);
    DWORD Style = ::GetWindowLong(GetSafeHwnd(),GWL_EXSTYLE);
    Style |= WS_EX_LAYERED;
    ::SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,Style);
    
    ::SetLayeredWindowAttributes( GetSafeHwnd(),
        m_ColorBackground,  //本颜色将删除
        (BYTE)(255.f * m_fTransPercent/100.f),LWA_ALPHA|LWA_COLORKEY);

    return 0;
}

容易吗?如果你不了解代码的注释,这是可以理解的,因为我是一个中国人,我的英语很差,但我会尽力让你清楚。

从 APP 文件中,你可以看到两个过程 SayInChinesePlayWaveSound。我在这里忽略了它们,因为我让它们在我的早期项目中工作(它可以用中文说话)。所以,你可以在下一步让它用英语说话。

第一步,在使用这些代码之前,你应该做以下事情

  1. clock.mdb 文件复制到 ./Debug 子文件夹和 ./Release 文件夹。
  2. 重新构建并运行它。

使用一个名为 CClockRSet 的类。它派生自 CDaoRecordset。我用它来记录考勤信息。使用两个过程来执行它

BOOL GetTodayID(UINT& uID)
{
    SYSTEMTIME st;
    GetLocalTime(&st);
    CString sql;
    sql.Format("select * from [KaoQin] where (YEAR(RiQi)=%d 
             and MONTH(RiQi)=%d and DAY(RiQi)=%d)",
             st.wYear,st.wMonth,st.wDay);
    CClockRSet rs;
    rs.Open(AFX_DB_USE_DEFAULT_TYPE,sql,CRecordset::readOnly);
    ASSERT(rs.IsOpen());
    if(!rs.IsOpen()) return FALSE;
    BOOL bRet=FALSE;
    if(rs.GetRecordCount()>0)
    {
        rs.MoveFirst();
        uID=rs.m_ID;
        bRet=TRUE;
    }
    if(rs.IsOpen()) rs.Close();
    return bRet;
}

它检查今天的第一个记录,并在今天打卡时返回 ID。失败时返回零。

    if(!GetTodayID(m_uTodayID))
    {
        if(FillClock(BAODAO,m_uTodayID))
        {
            VERIFY(GetTodayID(m_uTodayID));
            ASSERT(m_uTodayID!=0);
        }
    }

一个创建今天记录的条目

BOOL CClockDlg::PreTranslateMessage(MSG* pMsg) 
{
    if(pMsg->message==WM_KEYDOWN)
    {
        if(pMsg->wParam==VK_ESCAPE)
        {
            //SHORT stat1=GetKeyState(VK_LCONTROL);
            //SHORT stat2=GetKeyState(VK_LSHIFT);
            //if(stat1 & 0x0800 && stat2 & 0x0800)
            //{
                ShowWindow(SW_MINIMIZE);
                ShowWindow(SW_HIDE);
                return TRUE;
            //}
        }
        //if(pMsg->wParam==VK_F1)
        //{
        //    theApp.ShowHelp();
        //    return TRUE;
        //}
    }
    return CDialog::PreTranslateMessage(pMsg);
}

按 ESC 键执行隐藏你的时钟。

void CClockDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{
    CDialog::OnLButtonDown(nFlags, point);
    CRect rcTest;
    for(int i=1;i<=12;i++)
    {
        //test if you are clicking at the right place
        rcTest=GetHourRect(i);
        if(rcTest.PtInRect(point))
        {
            if(i==12)
            {
                if(m_uTodayID!=0)
                    FillClock(WUFAN,m_uTodayID);
            }
            else if(i==1)
            {
                if(m_uTodayID!=0)
                    FillClock(PMBAODAO,m_uTodayID);
            }
            else if(i==6)
            {
                if(m_uTodayID!=0)
                    FillClock(XIABAN,m_uTodayID);
            }
            else if(i==7)
            {
                if(m_uTodayID!=0)
                    FillClock(NIGHTBAODAO,m_uTodayID);
            }

            DWORD dwFlag=SND_RESOURCE;
            //Play the music
            ::PlaySound(MAKEINTRESOURCE(IDR_WAVE_DIDA), 
                           AfxGetResourceHandle(),dwFlag);
            if(m_uDiDaTimer!=0)
            {
                KillTimer(m_uDiDaTimer);
                m_uDiDaTimer=0;
            }
            m_uDiDaCount+=i;
            const int OKPASSWORD=1+2+3+4+5+6;
            TRACE("%d m_uDiDaCount=%d/%d\n",i,m_uDiDaCount,OKPASSWORD);
            // it is mystery!:)
            //如果密码不正确,启动Timer
            if(m_uDiDaCount!=OKPASSWORD)
            {
                //下面的输入必须在10秒钟内完成,否则输入将被清理
                m_uDiDaTimer=SetTimer(2,1000*10,NULL);
            }
            else
            {
                ::PlaySound(MAKEINTRESOURCE(IDR_WAVE_DONE), 
                              AfxGetResourceHandle(),dwFlag);
                DoLoginAction();
                m_uDiDaCount=0;
            }
            return;
        }
    }
    //Move the window while you drag it
    PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x,point.y));
}

OnTimer 过程中,它做一些事情来让它说中文。它可以说类似:“早上好,先生,现在是 XXXX 点”,但它用中文说。你可以在下一次下载中文语音 API。

        CString ss;
        if(st.wHour>=0 && st.wHour<3) ss="凌晨";
        if(st.wHour>=3 && st.wHour<6) ss="清晨";
        if(st.wHour>=6 && st.wHour<9) ss="早晨";
        if(st.wHour>=9 && st.wHour<12) ss="中午";
        if(st.wHour>=12 && st.wHour<15) ss="下午";
        if(st.wHour>=15 && st.wHour<18) ss="傍晚";
        if(st.wHour>=18 && st.wHour<21) ss="晚上";
        if(st.wHour>=21 && st.wHour<=23) ss="深夜";
        if(st.wMinute!=m_nLastMinute)
        {
            //是否允许报时
            if(st.wMinute==30)
            {
                //是否允许半小时报时
                if(theApp.GetProfileInt("settings","CanAlarmHalfHour",FALSE))
                {
                    CString sFile=theApp.GetProfileString("settings", 
                                              "HalfHourAlarmFile","");
                    if(!sFile.IsEmpty() && PathFileExists(sFile))
                    {
                        CString sExt=PathFindExtension(sFile);
                        if(sExt.CompareNoCase(".wav")==0)
                        {
                            theApp.PlayWaveSound(sFile);
                        }
                    }
                    if(theApp.GetProfileInt("settings", 
                              "UseChineseVoiceInAlarm",TRUE))
                    {
                        CString s;
                        s.Format("%s %d点%d分", 
                                         ss,st.wHour,st.wMinute);
                        theApp.SayInChinese(s);
                    }
                }
            }
        }
        if(m_nLastHour != st.wHour)
        {
            //是否允许报时
            if(theApp.GetProfileInt("settings","CanAlarmHour",TRUE))
            {
                CString sFile=theApp.GetProfileString("settings", 
                                                 "HourAlarmFile","");
                if(!sFile.IsEmpty() && PathFileExists(sFile))
                {
                    CString sExt=PathFindExtension(sFile);
                    if(sExt.CompareNoCase(".wav")==0)
                    {
                        theApp.PlayWaveSound(sFile);
                    }
                }
                if(theApp.GetProfileInt("settings",
                               "UseChineseVoiceInAlarm",TRUE))
                {
                    CString sE; 
                    sE="正";
                    if(st.wMinute!=0)
                        sE.Format("%d分",st.wMinute);
                    CString s;
                    s.Format("%s %d点%s",ss,st.wHour,sE);
                    theApp.SayInChinese(s);
                }
            }
        }

右键单击时使其更透明。

void CClockDlg::OnRButtonDown(UINT nFlags, CPoint point) 
{
    CDialog::OnRButtonDown(nFlags, point);

    ::SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,
        (LONG)(::GetWindowLong(GetSafeHwnd(),GWL_EXSTYLE) & ~WS_EX_LAYERED));

    ::SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,
        (LONG)(::GetWindowLong(GetSafeHwnd(),GWL_EXSTYLE) | WS_EX_LAYERED));

    if(m_fTransPercent>0.f) 
        m_fTransPercent-=5.f;
    if(m_fTransPercent<10.f)
        m_fTransPercent=10.f;

    ::SetLayeredWindowAttributes( GetSafeHwnd(),
        m_ColorBackground,    //本颜色将删除
        (BYTE)(255.f * m_fTransPercent/100.f),LWA_ALPHA|LWA_COLORKEY);

    BLENDFUNCTION bl={AC_SRC_OVER,0, 
         (BYTE)(255.f * m_fTransPercent/100.f),AC_SRC_ALPHA};
    ::UpdateLayeredWindow(GetSafeHwnd(),
        NULL,
        NULL,NULL,
        NULL,
        NULL,
        m_ColorBackground,
        &bl,
        ULW_ALPHA|ULW_COLORKEY);
    theApp.WriteProfileInt("Settings","ClockTransparent",(int)m_fTransPercent);
}
void CClockDlg::OnHotKey(WPARAM wParam, LPARAM lParam)
{
    WORD wL,wH;
    wL=LOWORD(lParam);
    wH=HIWORD(lParam);
    if((wL & MOD_ALT) && (wL & MOD_CONTROL) && (wL & MOD_SHIFT))
    {
        if(wH==VK_F12)
        {
            if(!::IsWindowVisible(GetSafeHwnd()))
            {
                ShowWindow(SW_RESTORE);
                ShowWindow(SW_SHOW);
            }
        }
    }
}

再次显示它的热键。

我还能说些什么呢?这对你来说很明显也很清楚,我将在下周上传中文语音 API (CSAPI)。

© . All rights reserved.