1. 程式人生 > >QQ揭祕:如何實現托盤閃動訊息提醒?【低調贈送:QQ高仿版GG 4.1 最新原始碼】

QQ揭祕:如何實現托盤閃動訊息提醒?【低調贈送:QQ高仿版GG 4.1 最新原始碼】

  當QQ收到好友的訊息時,托盤的圖示會變成好友的頭像,並閃動起來,點選托盤,就會彈出與好友的聊天框,隨即,托盤恢復成QQ的圖示,不再閃動。當然,如果還有其它的好友的訊息沒有提取,托盤的圖示會變成另一個好友的圖示,並繼續閃動。那麼,QQ的這一效果是如何實現的了?我在QQ高仿GG2014中實現了同樣的效果,這裡我就詳細地介紹一下。另外,文末最後會奉上GG最新版本4.1的原始碼,這次甚至包含了JustLib專案的原始碼哦!

      想要直接下載體驗的朋友請點選:“下載中心”

一.TwinkleNotifyIcon的實現原理

  這個會閃動的托盤圖示,我將其定義為一個元件TwinkleNotifyIcon,我們先看TwinkleNotifyIcon的類圖:

  

   從TwinkleNotifyIcon類圖,我們已經可以看出大致的實現方案:

(1)TwinkleNotifyIcon 內部使用了NotifyIcon,以顯示在右下角的托盤。

(2)使用一個Timer定時器來控制托盤的閃動。

(3)使用一個佇列friendQueue來存放待提取的好友訊息。

(4)使用另一個佇列groupQueue來存放待提取的群訊息。

(5)當網路引擎接收到一個好友/群訊息時,我們就呼叫PushFriendMessage/PushGroupMessage方法,將其壓入friendQueue/groupQueue,並開始閃動圖示。

(6)當托盤被點選時,就從Queue中提取最早的一個訊息,並將其交給對應的聊天視窗去處理。

二.TwinkleNotifyIcon 實現要點

  我們順著以下的順序來研究TwinkleNotifyIcon的實現程式碼,就很容易了:

(1)壓入好友/群訊息。

(2)點選托盤,提取訊息。

(3)重新判斷Queue中是否還有待提取的訊息,以設定托盤的狀態。

1. 壓入訊息

  我們以PushFriendMessage方法為例,PushGroupMessage的道理是一樣的。

    public void PushFriendMessage(string userID, int informationType, byte[] info, object tag)
    {           
        
lock (this.locker) { try { this.twinkleNotifySupporter.PlayAudioAsyn(); //播放訊息提示音 //首先檢視是否已經存在對應的聊天視窗 IChatForm form = this.twinkleNotifySupporter.GetExistedChatForm(userID); if (form != null) { form.HandleReceivedMessage(informationType, info, tag); return; } //接下來準備將訊息壓入queue UnhandleFriendMessageBox cache = null; lock (this.locker) { //先檢視queue中目標好友對應的Cache是否存在 for (int i = 0; i < this.friendQueue.Count; i++) { if (this.friendQueue[i].User == userID) { cache = this.friendQueue[i]; break; } } if (cache == null) //如果不存在,則為好友新建一個Cache { cache = new UnhandleFriendMessageBox(userID); this.friendQueue.Add(cache); //觸發UnhandleMessageOccured事件 if (this.UnhandleMessageOccured != null) { this.UnhandleMessageOccured(UnhandleMessageType.Friend, userID); } } cache.MessageList.Add(new Parameter<int, byte[], object>(informationType, info, tag)); } string userName = this.twinkleNotifySupporter.GetFriendName(userID); this.notifyIcon1.Text = string.Format("{0}({1}) {2}條訊息", userName, userID, cache.MessageList.Count); //獲取好友的頭像,將其作為托盤圖示 this.twinkleIcon = this.twinkleNotifySupporter.GetHeadIcon(userID); this.ControlTimer(true); //啟動閃爍 } catch (Exception ee) { MessageBox.Show(ee.Message); } } }

(1)在壓入訊息的時候,先要播放訊息提示音,以通知使用者收到了新的訊息。

(2)首先要判斷訊息的來源好友是否正在和自己聊天(已經打開了與對方的聊天視窗),如果是,則直接將訊息交給聊天視窗去顯示。否則,進入下一步。

(3)看當前的佇列中是否已經存在了目標好友的Cache,因為可能已經有了待提取的來自該好友的訊息了。如果已經存在這個Cache,則將訊息直接放入Cache,否則,為之新建一個,再放入。

(4)之所以要觸發UnhandleMessageOccured事件,是為了通知外面,有待提取的訊息出現了。比如,MainForm就會預定這個訊息,然後使得好友列表中對應的頭像閃動。

    void notifyIcon_UnhandleMessageOccured(UnhandleMessageType type, string friendOrGroupID)
    {
        if (type == UnhandleMessageType.Friend)
        {
            this.friendListBox1.SetTwinkleState(friendOrGroupID, true); 
            this.recentListBox1.SetTwinkleState(friendOrGroupID, false, true);
            return;
        }

        if (type == UnhandleMessageType.Group)
        {
            this.groupListBox.SetTwinkleState(friendOrGroupID, true);
            this.recentListBox1.SetTwinkleState(friendOrGroupID, true, true);
            return;
        }
    }

  上面的UnhandleMessageOccured事件處理函式,不僅僅使得好友列表中對應的頭像閃動,即使是最近聯絡人中,如果存在目標好友,也會使其頭像閃動。

(5)將托盤圖示設定為目標好友的頭像,並將ToolTip設定為好友的名稱及待提取的訊息數量。

(6)使用定時器閃動圖示。

2.點選托盤,提取訊息

  如果托盤正在閃動,表明有待提取的訊息,此時點選托盤,將提取佇列中最早壓入的好友的訊息。

    void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
    {
        try
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }

            lock (this.locker)
            {
                if (this.friendQueue.Count > 0)
                {
                    UnhandleFriendMessageBox cache = this.friendQueue[0];
                    this.friendQueue.RemoveAt(0);
                    IChatForm form = this.twinkleNotifySupporter.GetChatForm(cache.User);
                    if (form != null) //如果為null,表示剛刪除好友
                    {
                        form.HandleReceivedMessage(cache.MessageList);
                    }

                    this.DetectUnhandleMessage();

                    if (this.UnhandleMessageGone != null)
                    {
                        this.UnhandleMessageGone(UnhandleMessageType.Friend, cache.User);
                    }
                    return;
                }

                if (this.groupQueue.Count > 0)
                {
                    UnhandleGroupMessageBox cache = this.groupQueue[0];
                    this.groupQueue.RemoveAt(0);
                    IGroupChatForm form = this.twinkleNotifySupporter.GetGroupChatForm(cache.Group);
                    form.HandleReceivedMessage(cache.MessageList);

                    this.DetectUnhandleMessage();

                    if (this.UnhandleMessageGone != null)
                    {
                        this.UnhandleMessageGone(UnhandleMessageType.Group, cache.Group);
                    }
                    return;
                }
            }

            if (this.MouseClick != null)
            {
                this.MouseClick(sender, e);
            }
        }
        catch (Exception ee)
        {
            MessageBox.Show(ee.Message + " - " + ee.StackTrace);
        }
    }

(1)從上面程式碼執行的順序來看,是優先提取好友訊息,當所有的好友訊息提取完後,才提取群訊息。

(2)提取訊息時,會呼叫twinkleNotifySupporter的GetChatForm方法來建立與目標好友的聊天視窗,並將提取的訊息交給這個視窗去處理。

(3)當一個好友的訊息被提取後,會觸發UnhandleMessageGone事件,以通知外部訊息已經被提取了。比如,MainForm就會預定這個訊息,然後使得好友列表中對應的頭像不再閃動。

    void notifyIcon_UnhandleMessageGone(UnhandleMessageType type, string friendOrGroupID)
    {
        if (type == UnhandleMessageType.Friend)
        {
            this.friendListBox1.SetTwinkleState(friendOrGroupID, false); 
            this.recentListBox1.SetTwinkleState(friendOrGroupID, false, false);
            return;
        }

        if (type == UnhandleMessageType.Group)
        {
            this.groupListBox.SetTwinkleState(friendOrGroupID, false);
            this.recentListBox1.SetTwinkleState(friendOrGroupID, true, false);
            return;
        }
    }

(4)同時,會重新掃描佇列中待提取訊息的狀況,重設托盤圖示的狀態,這就是DetectUnhandleMessage方法做的事情。

3.重新判斷Queue中是否還有待提取的訊息,以設定托盤的狀態

  每當有訊息被提取後,我們都需要重新掃描Queue中是否還有其它的待提取訊息,DetectUnhandleMessage方法會被經常呼叫。

    private void DetectUnhandleMessage()
    {
        if (this.friendQueue.Count == 0 && this.groupQueue.Count == 0)
        {
            this.ControlTimer(false);
        }
        else if (this.friendQueue.Count > 0)
        {
            UnhandleFriendMessageBox cache = this.friendQueue[0];
            string userName = this.twinkleNotifySupporter.GetFriendName(cache.User);
            this.notifyIcon1.Text = string.Format("{0}({1})  {2}條訊息", cache.User, userName, cache.MessageList.Count);
            this.twinkleIcon = this.twinkleNotifySupporter.GetHeadIcon(cache.User);
        }
        else
        {
            UnhandleGroupMessageBox cache = this.groupQueue[0];
            string groupName = this.twinkleNotifySupporter.GetGroupName(cache.Group);
            this.notifyIcon1.Text = string.Format("{0}({1})  {2}條訊息", groupName, cache.Group, cache.MessageList.Count);
            this.twinkleIcon = this.twinkleNotifySupporter.GroupIcon;
        }
    }

(1)如果好友訊息的Queue和群訊息的Queue當中都沒有任何訊息了,則不再閃動托盤圖示。

(2)再依次掃描好友訊息的Queue和群訊息的Queue,如果發現還有待提取的訊息,則設定托盤圖示的影象,設定ToolTip,並開始閃動圖示。

三.GG V4.1 原始碼 

   下載最新版本,請轉到這裡。 

   

歡迎和我探討關於GG的一切,我的QQ:2027224508,多多交流!  

大家有什麼問題和建議,可以留言,也可以傳送email到我郵箱:[email protected]。 

如果你覺得還不錯,請粉我,順便再頂一下啊,呵呵  

相關推薦

QQ揭祕如何實現托盤閃動訊息提醒低調贈送QQ仿GG 4.1 最新原始碼

  當QQ收到好友的訊息時,托盤的圖示會變成好友的頭像,並閃動起來,點選托盤,就會彈出與好友的聊天框,隨即,托盤恢復成QQ的圖示,不再閃動。當然,如果還有其它的好友的訊息沒有提取,托盤的圖示會變成另一個好友的圖示,並繼續閃動。那麼,QQ的這一效果是如何實現的了?我在QQ高仿GG2014中實現了同樣的效果,這裡

QQ揭祕如何實現窗體靠邊隱藏?低調贈送QQ仿GG 4.2 最新原始碼

      QQ有個靠邊隱藏的功能,使用起來很方便:在螢幕上拖動QQ的主窗體,當窗體的上邊沿與螢幕的上邊沿對齊時,主窗體就會duang~~地隱藏起來,當將滑鼠移到螢幕上邊沿的對應區域時,主窗體又會duang~~顯示出來。   我在GG的最新版4.2中也增加了靠邊隱藏的功能,支援靠左邊沿隱藏、靠上邊沿隱藏、靠

如何實現錄製視訊聊天的全過程? 低調贈送QQ仿GG 4.3 最新原始碼

  前段時間做個專案,客戶需要將視訊對話的整個過程錄製下來,這樣,以後就可以隨時觀看。想來錄製整個視訊聊天的過程這樣的功能應該是個比較常見的需求,比如,基於網路語音視訊的1:1的英語口語輔導,如果能將輔導的整個過程錄製下來生成一個標準的MP4檔案,就是一份難得的資料,便於以後複習和分享。我將1:1的視訊對話錄

如何做到在虛擬資料庫和真實資料庫之間自由切換?低調贈送QQ仿GG 4.4 最新原始碼

      記得以前在公司上班時,有時候白天的活沒幹完,我就會把工作帶回家晚上加班繼續做。但是,我們開發用的資料庫是部署在公司局網內部的一臺伺服器上的,在家裡是肯定連不上這臺機器的。在家裡沒有資料庫,服務端就跑不起來,功能也就沒辦法除錯。後來我們的解決方法就是使用虛擬資料庫。在公司上班時,就使用公司局網的真實

可在廣域網部署執行的QQ仿 -- GG嘰嘰(原始碼

前段時間看到園子裡有朋友開發了QQ高仿版的程式,我也非常有興趣,以前一直有個做即時聊天程式的夢,趁這段時間工作不是很忙,就開始動手來做這個事情。根據我以往積累下來的專案經驗,實現QQ的基本功能,問題應該不大。當然,我的目標並不是做一個QQ高仿版的玩具,而是希望做成一個能能夠真正使用的產品(當然是免費的),並持

可在廣域網部署執行的QQ仿 -- GG2014 完美!新增支援聊天記錄、好友分組、托盤閃動訊息提醒、登入狀態、GIF動態表情

  距上次GG V3.7版本()的釋出,已經有50天了,這50天對於GG來說,是一個重大的飛躍。因為這段時間通過一些基於GG的實戰專案,發現了GG的很多bug和不足之處,我都一一做了修正,並增加了一些基礎且必須的功能。這次釋出的是GG V4.0版本,又稱為GG 2014。   記得在GG早期版本時,園子裡的

即時通訊系統中實現聊天訊息加密,讓通訊更安全低調贈送C#開源即時通訊系統(支援廣域網)——GGTalk4.5 最新原始碼

  在即時通訊系統(IM)中,加密重要的通訊訊息,是一個常見的需求。尤其在一些政府部門的即時通訊軟體中(如稅務系統),對即時聊天訊息進行加密是非常重要的一個功能,因為談話中可能會涉及到機密的資料。我在最新的GG 4.5中,增加了對即時聊天訊息進行加密的功能,但這一功能並不是強制的,可以通過開關來進行控制。本文

可在廣域網部署執行的QQ仿 -- GG嘰嘰V3.6,增加語音訊息、語音留言等功能

  自從微信出來後,語音訊息和語音留言變得非常流行,按下一個鍵說話,比打字要方便多了。GG在V3.6版本增加了對語音訊息和語音留言(或稱為離線語音訊息)的支援。這兩個功能的實現已經很完整,只是比較遺憾的一點是:GG所使用的文字框控制元件,還沒有辦法像微信的聊天視窗的文字框那樣嵌入表示語音訊息的控制元件,所以,

可在廣域網部署執行的QQ仿 -- GG嘰嘰V3.2,增加離線訊息、離線檔案功能(原始碼

  (幾句題外話:雖然就如何將GG發展為一個有商業價值的產品,我還沒有很清晰明確的思路,但是從GG釋出以來,通過GG認識了一些朋友,也接了一些小單子,賺了一點小錢。有了一點甜頭,目前和2、3個好朋友一起做做小專案也是不錯的,這未嘗不是一條養家餬口之路了?呵呵)   距離上次更新(GG嘰嘰V3.0,完善基礎功

可在廣域網部署執行的QQ仿 -- GG嘰嘰V3.5,增加自拍頭像功能、細節優化(原始碼

  距離上次發版本(GG嘰嘰V3.4,增加系統設定、最近聯絡人、群功能)又有1個月了,在這個月內,由於空閒時間不是很多,所以,GG增加的主要功能只是拍照並設定其為自己頭像、修改密碼、刪除好友、以及一些bug的修改。我試著列了一下接下來GG要優化的地方,總共達20多條,看來GG離一個正式的產品還有很長的路要走。

可在廣域網部署執行的QQ仿 -- GG嘰嘰V3.4,增加系統設定、最近聯絡人、群功能(原始碼

  自從上次版本(GG嘰嘰V3.2,增加離線訊息、離線檔案功能)釋出後,我個人覺得主要的大功能都實現得差不多了,接下來的幾個版本將不斷優化GG的細節,提高其可用性。這次版本更新的內容主要是為GG增加了系統設定、並完善的了群所需的基礎功能。 一.GG V3.4 新增功能展現  1.群功能完善 (1)建立群

可在廣域網部署執行的QQ仿 -- GG嘰嘰V3.0,完善基礎功能(原始碼

  (前段時間封閉式開發完了一個專案,最近才有時間繼續更新GG的後續版本,對那些關注GG的朋友來說,真的是很抱歉。)GG的前面幾個版本開發了一些比較高階的功能,像視訊聊天、遠端桌面、檔案傳送、遠端磁碟等,但是,有一些基礎且必需的功能一直未實現,比如註冊、新增好友、加入群、群聊天等等。經常有朋友留言問這些功能要

可在廣域網部署執行的QQ仿 -- GG嘰嘰V1.8(原始碼

距離的GG 1.0釋出已經三週了,這三週內,我利用業餘時間為GG增加了視訊聊天的功能。個人覺得進展有些緩慢,主要是因為大多數時間都花在了UI上。由於本人不會PS,所以圖片素材都是從網上一個一個搜下來的,這個過程確實很煩人,而且最終有些素材還不是很滿意。 一.GG V1.8 新增功能展現 (1)傳送視訊會話

可在廣域網部署執行的QQ仿 -- GG嘰嘰V2.4,增加遠端協助、桌面共享功能(原始碼

  QQ的遠端協助、或者說桌面共享是一個非常實用的功能,所以,2.4版本的GG複製了它,而且,GG增強了桌面共享的功能,它可以允許指定要共享桌面的區域,這樣,對方就只能看到指定區域的桌面,這對節省流量會非常有幫助。   GG實現這些功能的過程並不是那麼簡單,因為內部業務邏輯的關聯容易把人搞暈。從執行起來的程

可在廣域網部署執行的QQ仿 -- GG嘰嘰V3.7,優化視訊聊天、控制更多相關細節

  在廣域網中,由於網路的結構紛繁複雜、而且其實時狀況又是千變萬化的,所以,要使廣域網中的視訊聊天達到一個令人滿意的效果,存在諸多挑戰。這次釋出的GG 3.7版本嘗試在這一方向上做一些努力,據我自己測試,相比之前版本,新版本GG的視訊聊天的效果確實有較大提升。本文不僅會分享GG的最新原始碼,而且也會把我在過去

在主頁面添加個qq客服實現當點擊圖片時可以與指定QQ號的人進行聊天

site 新建 ack 調用 position 默認 點擊 進行 images 首先在主頁面內容的最後面添加一個div <!--QQ客服代碼--> <style type="text/css"> .qqkef

Unity實戰篇實現連連看死局判定(二具體實現

要做死局判定,我們要明確在什麼時候檢察地圖是否死局。 剛剛初始化地圖 每次消除之後  檢查死局前我們也要同步更新有向鄰接表字典和地圖陣列 我們約定,陣列值為-1代表此處為空 遍歷字典,找到要去除的元素,從字典刪除 避免異常,刪除元素後即退出函

Unity實戰篇實現連連看死局判定(一資料結構的選擇以及基本思路概述)

最近在做連連看小遊戲,整體完成的差不多,還差一個死局判定,若為死局,即重新洗牌。 由於專案結構較為繁雜,建議大家先下載原始碼 原始碼下載連結:https://gitee.com/NKG/UnityWorks/blob/master/UnityPackages/LinkUp.unitypa

仿介面實現功能

第一步: 匯入類連結1連結2 第二步: 在AppDelegate.m裡 標頭檔案 #import “ViewController.h” 程式碼如下: self.window.rootViewController = [ViewController new]; self.window.back

詳解C# 網絡編程系列實現類似QQ的即時通信程序

並且 會話 hat chat .sh odin unicode 情況 plist 引言: 前面專題中介紹了UDP、TCP和P2P編程,並且通過一些小的示例來讓大家更好的理解它們的工作原理以及怎樣.Net類庫去實現它們的。為了讓大家更好的理解我們平常中常見的軟件QQ的工作原理