天天看點

仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題

     今天,想和大家聊一下有關軟體的界面的一些知識,當一個軟體程式被設計出來時,首先展現的就是界面效果,平時見過很多軟體,早些很多商用的軟體為了追求軟體運作性能的出色,并沒有把軟體界面設計的美輪美奂,相反一些大型的桌面應用軟體界面往往比較單調,比如一些大型ERP軟體。我想原因也許有多種,究其一二,一是軟體設計者在設計軟體之初就忽略界面元素,隻是一味的追求實作系統的核心業務功能。殊不知,如今的軟體行業競争也很大,尤其在同類型的軟體中,軟體的使用者越來越要求軟體有更好的人機互動能力,更友善快捷美觀的人性化的使用者體驗。好的使用者界面必然在諸多同行軟體中占據先機,備受青睐。二是為了追求高性能的運作穩定,提高界面的響應速度,有意未将軟體界面效果納入非功能需求範疇,以節約系統資源。以我的觀點來看待這個問題,現在電腦處理器水準都比較高,3D遊戲的推動和湧現帶來了個人計算機軟硬體技術的日新月異和網絡通信技術的高速發展。性能資源消耗方面已不足為慮。很多漂亮軟體界面呼之欲出。在國内軟體中,有很多比較優秀的軟體,在軟體界面上更是做足了功夫,提供了諸多漂亮界面主題和皮膚包。比如,我們經常用的迅雷,騰訊QQ等桌面程式。每次版本的更新都帶來全新的使用者體驗。個人簡單的認為,軟體的界面猶如人的衣裝穿着,人人都有一顆愛美之心,而軟體也不例外。我在校期間利用業餘時間學習了C#、winform界面程式設計,學習固然很辛苦,都是靠自學,其中的動力就是對程式設計技術的熱衷與追求。

其中第一點就是窗體動态效果的實作:

一,  調用系統API消息函數給窗體添加動态特效

1. 導入系統user32.dll并聲明API函數AnimateWindow

//導入系統的COM元件:user32.dll  (user32.dll是Windows使用者界面相關應用程式接口,用于包括Windows處理,基本使用者界面等特性,如建立視窗和發送消息)

[System.Runtime.InteropServices.DllImport("user32")]

//聲明系統API消息函數

private static extern bool AnimateWindow(IntPtr hwnd, int dwTime, int dwFlags); 

 AnimateWindow函數裡面的3個傳參的說明如下:

 hwnd        界面上控件的句柄

 dwTime    窗體特效執行的持續時間(1=1毫秒、1000=1秒)

 dwFlags   窗體特效的值

2. dwFlags要傳的參數是一些INT類型的常量,這些常量定義了該特效具體有哪些動作。

            const int AW_HOR_POSITIVE = 0x0001;   //正面_水準方向

            const int AW_HOR_NEGATIVE = 0x0002;    //負面_水準方向

            const int AW_VER_POSITIVE = 0x0004;    //正面_垂直方向

            const int AW_VER_NEGATIVE = 0x0008;    //負面_垂直方向

            const int AW_CENTER = 0x0010;    //由中間四周展開

            const int AW_HIDE = 0x10000;   //隐藏對象

            const int AW_ACTIVATE = 0x20000;    //顯示對象

            const int AW_SLIDE = 0x40000; //拉幕滑動效果

            const int AW_BLEND = 0x80000;     //淡入淡出漸變效果

 3.在程式事件中調用AnimateWindow方法,執行窗體特效函數

AnimateWindow(this.Handle, 1000, AW_CENTER | AW_HIDE | AW_HOR_NEGATIVE);//動畫——窗體由四周向中心縮小

縱然windows消息函數很強大,但也隻能實作的窗體效果簡單的表現需求,更多的情況是需要對窗體的重繪來實作更好的界面效果。

二、winform窗體重繪

重繪技術主要是對WIN32消息函數來處理的。

在窗體的大小和位置改變時,作業系統需要重繪窗體上的圖形或控件。當窗體大小改變時都将觸發窗體的重繪事件,下面将介紹窗體的兩個重繪事件。

1. Paint事件

在一個窗體被移動或放大之後或在一個覆寫該對象的窗體被移開之後,該窗體部分或全部暴露時,Paint事件發生。如果在代碼中使用了各種圖形方法的輸出,則使用Paint過程可以確定這樣的輸出在必須時能被重繪。使用窗體Refresh方法時,Paint事件即被調用。窗體Paint事件處理過程為:    Private Sub Form_Paint() 

說明:如果窗體的AutoRedraw屬性被設定為True,系統自動進行重新繪圖。

2.Resize事件

當窗體第一次顯示或窗體的狀态改變時将觸發Resize事件,如對窗體進行最大化、最小化、還原、被滑鼠拖動進行放大、縮小操作。使用Resize過程可以調整窗體的大小,也可以用來調整窗體上控件的大小與位置,使控件的大小随着窗體大小改變而改變,進而使得窗體布局更加合理和美觀。窗體Resize事件處理過程為:

Private Sub Form_Resize() 

比如:用 OnPaint 進行實時繪圖的

protected override void OnPaint(PaintEventArgs e)

{

        base.OnPaint(e);

        Graphics dc = e.Graphics;

        //以下是繪圖内容

}

三. GUI重繪過程中帶來的問題

主要是窗體的閃爍問題,網上處理的方式有很多種,常見的有二種:

1. 使用雙緩沖(two way soft-closing)技術

     如果窗體在響應WM_PAINT消息的時候要進行複雜的圖形處理,那麼窗體在重繪時由于過頻的重新整理而引起閃爍現象。解決這一問題的有效方法就是雙緩沖技術。

     因為窗體在重新整理時,總要有一個擦除原來圖象的過程OnEraseBkgnd,它利用背景色填充窗體繪圖區,然後在調用新的繪圖代碼進行重繪,這樣一擦一寫造成了圖象顔色的反差。當WM_PAINT的響應很頻繁的時候,這種反差也就越發明顯。于是我們就看到了閃爍現象。

我們會很自然的想到,避免背景色的填充是最直接的辦法。但是那樣的話,窗體上會變的一團糟。因為每次繪制圖象的時候都沒有将原來的圖象清除,造成了圖象的殘留,于是窗體重繪時,畫面往往會變的亂七八糟。是以單純的禁止背景重繪是不夠的。我們還要進行重新繪圖,但要求速度很快,于是我們想到了使用BitBlt函數。它可以支援圖形塊的複制,速度很快。我們可以先在記憶體中作圖,然後用此函數将做好的圖複制到前台,同時禁止背景重新整理,這樣就消除了閃爍。以上也就是雙緩沖繪圖的基本的思路。

    首先給出實作的程式,然後再解釋,同樣是在OnDraw(CDC *pDC)中: 

  CDC MemDC; //首先定義一個顯示裝置對象 

  CBitmap MemBitmap;//定義一個位圖對象 //随後建立與螢幕顯示相容的記憶體顯示裝置 MemDC.CreateCompatibleDC(NULL); //這時還不能繪圖,因為沒有地方畫 ^_^ 

  //下面建立一個與螢幕顯示相容的位圖,至于位圖的大小嘛,可以用視窗的大小,也可以自己定義

  (如:有滾動條時就要大于目前視窗的大小,在BitBlt時決定拷貝記憶體的哪部分到螢幕上)

  MemBitmap.CreateCompatibleBitmap(pDC,nWidth,nHeight); //将位圖選入到記憶體顯示裝置中 //隻有選入了位圖的記憶體顯示裝置才有地方繪圖,畫到指定的位圖上 

  CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap); //先用背景色将位圖清除幹淨,這裡我用的是白色作為背景 //你也可以用自己應該用的顔色

  MemDC.FillSolidRect(0,0,nWidth,nHeight,RGB(255,255,255)); //繪圖 

  MemDC.MoveTo(……); MemDC.LineTo(……); //将記憶體中的圖拷貝到螢幕上進行顯示 

  pDC->BitBlt(0,0,nWidth,nHeight,&MemDC,0,0,SRCCOPY); //繪圖完成後的清理 //把前面的pOldBit選回來.在删除MemBitmap之前 要先從裝置中移除它。

     MemDC.SelectObject(pOldBit); MemBitmap.DeleteObject(); MemDC.DeleteDC(); (來源于百度)

2. 調用Control.SetStyle 窗體樣式方法

如:public form_From()

{

            InitializeComponent();   

            this.SetStyle(ControlStyles.UserPaint, true);   

            this.SetStyle(ControlStyles.ResizeRedraw, true);//調整大小時重繪邊界。

            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);// 禁止擦除背景.

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);// 雙緩沖

            this.UpdateStyles();

}

      經過以上的步驟閃爍問題依然存在,最好的解決之道恐怕要在系統消息函數上再做文章,提供消息鈎子設定視窗句柄函數。例如:WM_ERASEBKGND消息傳遞函數,這一點有待深究。

經過一階段的學習,發現微軟的.NET平台有很多可取之處,在大學過過好幾種程式設計語言,程式設計語言之間相識的地方有很多。比如c#和java。用.NET開發軟體周期短且效率高的。個人認為對一個程式員而言,時間應該是最寶貴的。學習.NET的人越來越多,我也是浩浩大軍中的一員,出于對程式設計的熱衷,最大限度的追求和實作軟體界面的完美,下邊用圖檔方式展示目前自己已經實作的精仿QQ窗體的界面效果。之是以模仿QQ界面,原因很簡單就是要實作一個企業級使用的即時通訊元件。在以後的博文中将陸續介紹。

目前已經實作的QQ界面功能需求有:

1.實作窗體皮膚透明化處理,實作窗體半透明效果。

2.實作包含類似于QQ的主題闆,調色闆,純色闆的皮膚控制器。

3.實作軟體退出皮膚動态儲存,動态主題圖檔排序功能。

4.實作窗體主題皮膚動态預覽功能。

5.實作使用者自定義皮膚功能。

6.實作皮膚主題動态删除功能。

程式使用的是QQ圖檔資源,在此聲明不做任何商業操作,僅僅是用于技術上的探究。下面是一些效果圖以飨大家:

仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題
仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題
仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題
仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題
仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題
仿騰訊QQ界面一,  調用系統API消息函數給窗體添加動态特效二、winform窗體重繪三. GUI重繪過程中帶來的問題

    個人覺得使用用.NET平台設計軟體界面的确很出色。WPF的出現将帶來更多更炫的使用者體驗。當然文章中的有些觀點并不成熟。隻是一孔之見,一口之言,望各位牛人大蝦不吝拍磚。本人今年大四,即将畢業,希望和志同道合的朋友一起交流技術心得。聯系方式QQ:875297974

繼續閱讀