• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 3,  comments - 4,  trackbacks - 0
            由于平時(shí)很少鍛煉脖子和肩部的肌肉,上周積累的疲勞度爆發(fā)了,右鍵和右背疼的厲害。后來(lái)去醫(yī)院治療了一星期,花了幾百大洋才好。所以深刻體會(huì)到程序員的生 活即使在苦逼,也應(yīng)該注意保持適當(dāng)?shù)倪\(yùn)動(dòng)。身體恢復(fù)后,我就想找一款軟件,類似與鬧鐘的功能。但能以比較強(qiáng)烈的形式提醒自己,it's time to exercise!!!后來(lái),在小眾軟件發(fā)現(xiàn)了FadeTop,能夠每隔一段時(shí)間已覆蓋桌面的形式提醒你休息時(shí)間到了。后來(lái)想想自己,雖然寫(xiě)了幾年的代碼 了,但真的沒(méi)有寫(xiě)出什么實(shí)用的工具來(lái),好好的鄙視了自己一番。于是一時(shí)沖動(dòng),決定從模仿FadeTop開(kāi)始,于是就有了這篇文章。

            后面附有源碼,沒(méi)耐心的朋友可以到最后直接下載

            言歸正傳,我想實(shí)現(xiàn)的功能有:
            1.每隔一段時(shí)間提醒你該休息了
            2.提醒的方式為支持透明度的窗口,暫且成為遮罩層吧,遮罩層需要覆蓋當(dāng)前除任務(wù)欄之外的區(qū)域,并顯示提醒的文字
            3.遮罩層顯示一定的時(shí)間,具有一定的透明度,可以看到下面的程序。遮罩層從無(wú)到有,再到無(wú)即可
            4.相關(guān)的參數(shù):提醒間隔時(shí)間,遮罩層顯示時(shí)間可以自定義
            5.程序不需要在任務(wù)欄顯示圖標(biāo),遮罩層上也沒(méi)有任務(wù)操作,程序的圖標(biāo)在托盤(pán)中,類似QQ小圖標(biāo)。

            想要實(shí)現(xiàn)以上的功能,需要解決的問(wèn)題主要有:
            1.如何將窗口大小設(shè)置為鋪滿整個(gè)屏幕,并去除任務(wù)欄圖標(biāo)
            2.程序如何以托盤(pán)的形式顯示,托盤(pán)上的操作
            3.如何間隔一段時(shí)間提醒
            4.遮罩層顯示的時(shí)候,如何實(shí)現(xiàn)從無(wú)到有,再逐漸消失
            下面逐一分析解決以上問(wèn)題。

            首先,新建一個(gè)基于對(duì)話框的應(yīng)用程序,將dialog屬性設(shè)置為無(wú)標(biāo)題欄。

            如何將窗口大小設(shè)置為鋪滿整個(gè)屏幕
            ,并去除任務(wù)欄圖標(biāo)
            在OnInitDialog函數(shù)中,加入如下語(yǔ)句
             1 //獲得桌面大小,不包含任務(wù)欄等
             2     CRect rc;
             3     ::SystemParametersInfo(SPI_GETWORKAREA,0,(PVOID)&rc,0);
             4     SetWindowPos(NULL,rc.left,rc.top,rc.Width(),rc.Height(),SWP_NOMOVE|SWP_NOREPOSITION);
             5     
             6     //設(shè)置透明屬性
             7     LONG exstyle = GetWindowLong(m_hWnd,GWL_EXSTYLE);
             8     ::SetWindowLong(m_hWnd, GWL_EXSTYLE, exstyle|0x80000 | (~WS_EX_APPWINDOW) | WS_EX_TOOLWINDOW);
             9     
            10     
            11     //獲得設(shè)置透明度的函數(shù)指針
            12     HINSTANCE hInst = LoadLibrary("User32.DLL");
            13     if(hInst)
            14     {
            15         //取得SetLayeredWindowAttributes函數(shù)指針
            16         SetLayerOpacity=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
            17         FreeLibrary(hInst);                
            18     }
            19     
            20     //最小化到系統(tǒng)托盤(pán)
            21     m_tray.cbSize = sizeof(NOTIFYICONDATA);
            22     m_tray.hWnd = this->m_hWnd;
            23     m_tray.uID = IDR_OPTION;
            24     m_tray.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
            25     m_tray.hIcon = AfxGetApp()->LoadIcon(IDI_ICON_TIP);
            26     strcpy (m_tray.szTip, "提醒鬧鈴");
            27     m_tray.uCallbackMessage = UM_TRAYNOTIFICATION;
            28     
            29     if(!Shell_NotifyIcon(NIM_ADD, &m_tray))
            30     {
            31         MessageBox("啟動(dòng)失敗");
            32         CDialog::OnCancel();
            33     }
            34     
            35     //啟動(dòng)定時(shí)器
            36     SetTimer(1,m_timespan,NULL);
            上面的注釋雖然簡(jiǎn)單,但還算比較清晰,其中特別說(shuō)明的有下面幾點(diǎn):
            1.其中SetWindowLong函數(shù)完成了兩件事情:
                  a.去除了任務(wù)欄的圖標(biāo),通過(guò)去除屬性WS_EX_APPWINDOW,添加屬性WS_EX_TOOLWINDOW實(shí)現(xiàn);需要特別注意的是,在這里用 ShowWindow(SW_HIDE)并不能隱藏對(duì)話框,具體原因自己百度下,我采用重載OnNcPaint的方式,在初始化時(shí)隱藏對(duì)話框(為什么是兩 次,本人至今還不是很明白,希望知道的朋友msg我)
                 
            void CReminderDlg::OnNcPaint()
            {
                
            static int i=2;
                
            if(i>0)
                {
                    i
            --;
                    ShowWindow(SW_HIDE);
                }
            }
                  b.將對(duì)話框設(shè)置為遮罩層,這樣可以設(shè)置透明度,通過(guò)添加屬性0x80000實(shí)現(xiàn),在vs中,0x80000對(duì)應(yīng)的屬性是WS_EX_LAYED,但在vc中此變量似乎沒(méi)有定義。
            2.SetLayerOpacity是自定義函數(shù)指針,其定義為
            typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
            MYFUNC SetLayerOpacity 
            = NULL;
            用來(lái)獲取SetLayeredWindowAttributes函數(shù)的指針,此函數(shù)用于設(shè)置遮罩層的透明度,先保存起來(lái),以后使用
            3.Shell_NotifyIcon函數(shù)用于將自定義的圖標(biāo)加入到右下角的托盤(pán)中。
            4.SetTimer(1,m_timespan,NULL)是每隔m_timespan時(shí)間提醒一次的定時(shí)器

            托盤(pán)和程序的通信
            在這里,我們主要通過(guò)托盤(pán)實(shí)現(xiàn)程序的配置和退出。具體為:在托盤(pán)圖標(biāo)上點(diǎn)擊右鍵,出現(xiàn)彈出菜單,包含設(shè)定、退出等選項(xiàng)。點(diǎn)擊設(shè)定,彈出設(shè)定對(duì)話框,包含對(duì)與提醒間隔和遮罩層顯示時(shí)間,以及遮罩層顏色的設(shè)定,保存后立即生效。點(diǎn)擊退出菜單,則退出程序。
            托盤(pán)的操作采用自定義消息:
            在類定義中加入消息:afx_msg LRESULT OnTrayNotify(WPARAM wParm, LPARAM lParm);
            在類實(shí)現(xiàn)頭部加入:#define UM_TRAYNOTIFICATION (WM_USER+100)
            在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之間加入消息映射:ON_MESSAGE(UM_TRAYNOTIFICATION,OnTrayNotify)
            然后實(shí)現(xiàn)托盤(pán)對(duì)于郵件的響應(yīng)函數(shù):
            LRESULT CReminderDlg::OnTrayNotify(WPARAM wParm, LPARAM lParm)
            {
                
            if(wParm!=m_tray.uID || lParm!=WM_RBUTTONDOWN)
                {
                    
            return 0;
                }

                
            //加載菜單
                CMenu mu;
                
            if(!mu.LoadMenu(IDR_OPTION))
                {
                    
            return 0;
                }

                CMenu 
            *pSubMenu = mu.GetSubMenu(0);
                
            if(!pSubMenu)
                {
                    
            return 0;
                }

                
                
            //設(shè)置默認(rèn)菜單項(xiàng)
                ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);
                
                
            //獲取鼠標(biāo)位置
                CPoint mouse;
                GetCursorPos(
            &mouse);
                
                
            //設(shè)置快捷菜單
                
            //::SetForegroundWindow(m_tray.hWnd);
                ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0, m_tray.hWnd, NULL);
                

                
            return 0;
            }
            IDR_OPTION是自定義的菜單資源,其中包含了設(shè)定、退出等菜單。其對(duì)應(yīng)的消息處理函數(shù)是:
            void CReminderDlg::OnQuit()
            {
                // TODO: Add your command handler code here
                Shell_NotifyIcon(NIM_DELETE, &m_tray);
                CDialog::OnCancel();
            }

            void CReminderDlg::OnSet()
            {
                // TODO: Add your command handler code here
                
                CRSetting dlg;
                dlg.m_inteval = m_timespan/1000/60;
                dlg.m_show = m_timeshow/1000;
                dlg.m_color = m_layerColor;

                if(IDOK==dlg.DoModal())
                {
                    KillTimer(1);
                    m_timespan = dlg.m_inteval*60*1000;
                    m_timeshow = dlg.m_show*1000;
                    m_layerColor = dlg.m_color;
                    SetEnvData();
                    SetTimer(1,m_timespan,NULL);
                }    
            }
            其中需要說(shuō)明的是:在保存的時(shí)候,需要?jiǎng)h除舊的計(jì)時(shí)器,啟動(dòng)新的計(jì)時(shí)器。

            間隔一段時(shí)間提醒
            從上面的代碼可以看出,是通過(guò)計(jì)時(shí)器1來(lái)實(shí)現(xiàn)的,這個(gè)的代碼和第四個(gè)問(wèn)題的在一起,所以一會(huì)上

            遮罩層的顯示,從無(wú)到右再消失
            先看代碼
            //背景刷新的時(shí)間間隔
            #define TIME_REFRESH    100
            //最大的透明度
            #define MAX_OPACITY        200

            void CReminderDlg::OnTimer(UINT nIDEvent) 
            {
                
            // TODO: Add your message handler code here and/or call default
                if(nIDEvent==1)
                {
                    
            //時(shí)間到,提醒
                    ::SetWindowPos(m_hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_SHOWWINDOW);
                    SetLayerOpacity(m_hWnd,
            0,0,2);
                    KillTimer(
            1);
                    SetTimer(
            2,TIME_REFRESH,NULL);
                    m_timepass 
            = 0;
                }
                
            else if(nIDEvent==2)
                {
                    
            //顯示提醒層,從無(wú)到逐漸清晰再到無(wú)
                    m_timepass += TIME_REFRESH;
                    
            if(m_timepass==m_timeshow)
                    {
                        
            //顯示時(shí)間到,隱藏窗口,再次啟動(dòng)計(jì)時(shí)
                        KillTimer(2);
                        ShowWindow(SW_HIDE);
                        SetTimer(
            1,m_timespan,NULL);
                    }
                    
            else if(SetLayerOpacity!=NULL)
                    {
                        
            //更改透明度
                        ULONG half = m_timeshow/2;
                        BYTE op;
                        
            if(m_timepass<half)
                        {
                            
            //提示層從無(wú)到清晰的過(guò)程
                            op = (BYTE)(m_timepass*MAX_OPACITY / half);
                        }
                        
            else
                        {
                            op 
            = (BYTE)(MAX_OPACITY - (m_timepass-half)*MAX_OPACITY / half);
                        }
                    
                        
            if(!SetLayerOpacity(m_hWnd, 0, op,2))
                        {
                            
            //MessageBox(str);
                        }
                    }
                    
                }

                CDialog::OnTimer(nIDEvent);
            }
            如上所示,當(dāng)計(jì)時(shí)器1時(shí)間到的時(shí)候,用SetWindowPos顯示遮罩層,并取消定時(shí)器1,設(shè)置計(jì)時(shí)器2,計(jì)時(shí)器2是用來(lái)顯示遮罩層的,遮罩層2顯示的時(shí)間到達(dá)設(shè)定的顯示時(shí)間,則重新隱藏窗口,啟動(dòng)定時(shí)器1。其中兩點(diǎn)說(shuō)明:
            1.透明度是從0-200再到0的,當(dāng)為0的時(shí)候,意味著完全透明。
            2.SetLayerOpacity是函數(shù)指針,指向函數(shù)SetLayeredWindowAttributes,用來(lái)設(shè)置透明度。

            最后,在OnPaint()函數(shù)中完成遮罩層的繪制:
             1 void CReminderDlg::OnPaint() 
             2 {
             3     if (IsIconic())
             4     {
             5         CPaintDC dc(this); // device context for painting
             6 
             7         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
             8 
             9         // Center icon in client rectangle
            10         int cxIcon = GetSystemMetrics(SM_CXICON);
            11         int cyIcon = GetSystemMetrics(SM_CYICON);
            12         CRect rect;
            13         GetClientRect(&rect);
            14         int x = (rect.Width() - cxIcon + 1/ 2;
            15         int y = (rect.Height() - cyIcon + 1/ 2;
            16 
            17         // Draw the icon
            18         dc.DrawIcon(x, y, m_hIcon);
            19     }
            20     else
            21     {
            22         CPaintDC dc(this);
            23         CRect rect;
            24         GetClientRect(&rect);
            25         dc.FillSolidRect(rect,m_layerColor);
            26 
            27         //設(shè)置字體
            28         CFont font;
            29         font.CreateFont(
            30             48,                        // nHeight
            31             0,                         // nWidth
            32             0,                         // nEscapement
            33             0,                         // nOrientation
            34             FW_BOLD,                    // nWeight
            35             FALSE,                     // bItalic
            36             FALSE,                     // bUnderline
            37             0,                         // cStrikeOut
            38             GB2312_CHARSET,              // nCharSet
            39             OUT_DEFAULT_PRECIS,        // nOutPrecision
            40             CLIP_DEFAULT_PRECIS,       // nClipPrecision
            41             DEFAULT_QUALITY,           // nQuality
            42             DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
            43             "宋體");                 // lpszFacename
            44 
            45         CFont* def_font = dc.SelectObject(&font);
            46         dc.SetTextColor(RGB(
            47             abs(255-GetRValue(m_layerColor)),
            48             abs(255-GetGValue(m_layerColor)),
            49             abs(255-GetBValue(m_layerColor))
            50             ));
            51         
            52         //得到字體尺寸
            53         CSize sz = dc.GetTextExtent(m_tip); 
            54         dc.TextOut(rect.left+(rect.Width()-sz.cx)/2, rect.top+(rect.Height()-sz.cy)/2, m_tip);
            55         
            56         dc.SelectObject(def_font);
            57 
            58         CDialog::OnPaint();
            59     }
            60 }
            需要注意的是,在將提醒文字繪制在遮罩層上時(shí),使用的是相反的顏色,這樣有最大的對(duì)比度。

            另外,我將配置信息保存在注冊(cè)表中,因?yàn)橹挥?個(gè)數(shù)據(jù),啟動(dòng)時(shí)讀注冊(cè)表,函數(shù)如下所示
            //從注冊(cè)表讀出配置信息
            void CReminderDlg::GetEnvData()
            {
                HKEY hkey;
                LONG iRet;

                iRet 
            = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "software\\reminder"0, KEY_READ|KEY_QUERY_VALUE, &hkey);
                
            if(ERROR_SUCCESS != iRet)
                {
                    
            //說(shuō)明數(shù)據(jù)項(xiàng)不存在,創(chuàng)建
                    m_layerColor = RGB(0,0,255);
                    m_timespan 
            = 3600000;
                    m_timeshow 
            = 10000;
                    SetEnvData();
                    
            return;
                }
                
                
            //數(shù)據(jù)項(xiàng)存在,則讀出值
                DWORD len = sizeof(DWORD);
                iRet 
            = RegQueryValueEx(hkey,"rcolor",NULL,NULL,(BYTE*)&m_layerColor,&len);
                
            if(ERROR_SUCCESS != iRet)
                {
                    m_layerColor 
            = RGB(0,0,255);
                }

                iRet 
            = RegQueryValueEx(hkey,"timespan",NULL,NULL,(BYTE*)&m_timespan,&len);
                
            if(ERROR_SUCCESS != iRet)
                {
                    m_timespan 
            = 3600000;
                }

                iRet 
            = RegQueryValueEx(hkey,"timeshow",NULL,NULL,(BYTE*)&m_timeshow,&len);
                
            if(ERROR_SUCCESS != iRet)
                {
                    m_timeshow 
            = 10000;
                }

                RegCloseKey(hkey);
            }

            //配置信息寫(xiě)入注冊(cè)表
            void CReminderDlg::SetEnvData()
            {
                HKEY hkey;
                LONG iRet;
                iRet 
            = RegCreateKeyEx(HKEY_LOCAL_MACHINE,"software\\reminder",
                    
            0,NULL,0,KEY_ALL_ACCESS,NULL,&hkey,NULL);
                
            if(ERROR_SUCCESS != iRet)
                {
                    
            return;
                }

                
            //寫(xiě)入顏色信息
                iRet = RegSetValueEx(hkey,"rcolor",NULL,REG_DWORD,(BYTE*)&m_layerColor,sizeof(DWORD));
                
            if(ERROR_SUCCESS != iRet)
                {
                    RegCloseKey(hkey);
                    
            return;
                }

                
            //寫(xiě)入提醒時(shí)間間隔
                iRet = RegSetValueEx(hkey,"timespan",NULL,REG_DWORD,(BYTE*)&m_timespan,sizeof(DWORD));
                
            if(ERROR_SUCCESS != iRet)
                {
                    RegCloseKey(hkey);
                    
            return;
                }

                
            //寫(xiě)入提示信息顯示秒數(shù)
                iRet = RegSetValueEx(hkey,"timeshow",NULL,REG_DWORD,(BYTE*)&m_timeshow,sizeof(DWORD));
                
            if(ERROR_SUCCESS != iRet)
                {
                    RegCloseKey(hkey);
                    
            return;
                }

                RegCloseKey(hkey);

                
            return;
            }
            當(dāng)然,此程序你也可以通過(guò)注冊(cè)表,設(shè)置為開(kāi)機(jī)自動(dòng)啟動(dòng)。

            以上是一個(gè)很粗糙的程序,大家可以在此基礎(chǔ)上加上自己喜歡的功能,下面附上源碼:
            定時(shí)提醒工具

            運(yùn)行截圖:



            最后與大家共勉:無(wú)論多忙,都記得關(guān)愛(ài)自己的身體,做適當(dāng)?shù)倪\(yùn)動(dòng)。
            posted on 2011-08-14 07:14 成成 閱讀(4217) 評(píng)論(4)  編輯 收藏 引用

            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


            亚洲国产精品久久久久婷婷软件| 久久亚洲私人国产精品vA| 久久久久无码精品国产| 亚洲精品高清一二区久久| 国产香蕉97碰碰久久人人| 精品乱码久久久久久久| 色综合久久无码中文字幕| 伊人久久大香线蕉综合5g| 一本综合久久国产二区| 99久久香蕉国产线看观香| 久久99热这里只有精品66| 欧美伊人久久大香线蕉综合| 久久免费视频1| 久久精品aⅴ无码中文字字幕不卡| 无夜精品久久久久久| 四虎亚洲国产成人久久精品| 日韩欧美亚洲综合久久 | 乱亲女H秽乱长久久久| 77777亚洲午夜久久多人| 日韩精品久久久久久久电影蜜臀 | 97精品依人久久久大香线蕉97 | 亚洲中文字幕无码久久综合网| 国内精品伊人久久久久777| 熟妇人妻久久中文字幕| 国产精品久久一区二区三区| 国产精品伊人久久伊人电影| 无码人妻久久一区二区三区蜜桃| 久久久久久久波多野结衣高潮| 亚洲国产精品无码久久SM| 97久久香蕉国产线看观看| 国产精品成人久久久久久久| 欧美一区二区久久精品| 亚洲AV无码1区2区久久| 丁香久久婷婷国产午夜视频| 一本久久免费视频| 久久发布国产伦子伦精品| 久久国产精品二国产精品| 77777亚洲午夜久久多人| 99久久精品免费看国产一区二区三区 | aaa级精品久久久国产片| 久久精品这里只有精99品|