1. 程式人生 > >拋棄了上一個 GUI 訊息機制,重寫了一個更靈活高效的

拋棄了上一個 GUI 訊息機制,重寫了一個更靈活高效的

  拋棄了上一個訊息機制,因為它的實現不得不多用了幾個模板函式,在使用的時候有程式碼膨脹的現象。雖然其程度不如 win32gui,SmartWin,不過因為本人有點極端,所以相當地不滿意。於是又開始寫一個新的訊息機制,它的外表看起來像是 SmartWin++ 和 AWT 的混血兒。 

  SmartWin++ 的想法極富創意,但是其實現卻不怎麼漂亮,就像魯迅先生說的:離的越近,傷痕和不足越容易看見。或者更專業一點,借用一個朋友的 QQ 簽名說的:每個整潔的介面後面,都有一個齷齪的實現。仔細看過它的的齷齪實現之後,我想大概是永遠不會用它寫程式了,不過同樣要對作者的靈感表示敬佩和感謝。自己寫這個框架到後來,竟然也有向 SmartWin++ 靠攏的趨勢。

  AWT 的介面和實現很漂亮,不過看它在 C++ 上的這個實現,因為 C++ 與 java 一些語言特性上的差別,導致這個照搬過來的實現並不適用於 C++,一是效能很低,二是使用起來會比較麻煩。大概是因為作者要靠慮跨平臺的因素,所以縛手縛腳的沒有能放開寫。其實在這個基礎上好好地優化改進一下,會是個很不錯的框架。

  自己的這個框架的訊息機制是介於 SmartWin++ 的 Aspects 與 AWT 的 Listener 這間的一種機制。底層實現很簡單,在上面再包裝出一些 Listener 。這些 Listener 的結構看起來像 AWT 的 Listener,完成的功能卻是 SmartWin++ 的 Aspects 的功能。可以對比一下看看


AWT ( C++的一個移植版)

  比如說在 AWT 當中滑鼠相關的 Listener 大概是這樣的:

   1: class MouseListener : public EventListener 
   2: {
   3:  
   4: public:
   5:  
   6:     virtual void mouseClicked( MouseEvent& ) = 0;
   7:     virtual void mousePressed( MouseEvent& ) = 0;
   8:     virtual
void mouseReleased( MouseEvent& ) = 0;
   9:     virtual void mouseEntered( MouseEvent& ) = 0;
  10:     virtual void mouseExited( MouseEvent& ) = 0;
  11:  
  12: };

 
  如果一個類想處理自己的滑鼠訊息,則必須在這個類上派生,然後呼叫addListener 將自己新增進 Listeners 當中即可。比如說要寫一個按鈕類 Button* button,它要處理自己的滑鼠按下的訊息,程式碼大概會是這個樣子:

   1: class Button:public Component,
   2:             ,public MouseListener  // 從 MouseListener 介面派生
   3:             ,public SomethingElse
   4: {
   5:     Button()
   6:     {
   7:         addMouseListener( this );
   8:  
   9:         // do something else
  10:     }
  11:  
  12:     virtual void mousePressed( MouseEvent& me )
  13:     {
  14:         // button is pressed
  15:         // do something
  16:     }
  17: };


  如果還有外部的類想要處理這個按鈕的滑鼠按下訊息,那麼這個外部的類也必須從 MouseListener 派生,然後將自己新增進按鈕的 Listeners 當中。程式碼大概像這個樣子:

   1: // 從 MouseListener 介面派生
   2: class MouseEventTester:public MouseListener,public SomethingElse
   3: {
   4:     // 實現 mousePreseed 函式
   5:     virtual void mousePressed( MouseEvent& )
   6:     {
   7:         // mouse is pressed
   8:         // do something;
   9:     }
  10: };
  11:  
  12: // 新增到按鈕的滑鼠 Listener 列表當中
  13:  
  14: Button* button = new Button();
  15: button->addMouseListener( new MouseEventTester() );


  AWT 都是使用虛擬函式實現的,其效能上會有一些問題,誰叫是從 java 移植的呢。而且訊息處理函式的名字被限定死了,至少那些有特定名字習慣(比如很多人寫的函式非得用大寫字母開始)的程式會一定不會滿意的。另外,訊息的種類也被介面限制死了,除了介面提供的 mousePressed,mouseClicked 等訊息的函式,要新增其它訊息的處理能力就比較麻煩。


SmartWin++

  再看看 SmartWin++ Aspect 方式。SmartWin++ 關於滑鼠訊息的 Aspect 像這個樣子:

   1:  
   2: template</*一大堆模板引數*/>
   3: class AspectMouseClicks
   4: {
   5:     void onLeftMouseUp( Handler eventHandler );
   6:     void onLeftMouseUp( Handler eventHandler);
   7:  
   8:     void onLeftMouseDown( Handler eventHandler);
   9:     void onLeftMouseDown( Handler eventHandler);
  10:  
  11:     void onMouseMove( Handler eventHandler);
  12:     void onMouseMove( Handler eventHandler);
  13:  
  14:     // 其它一些滑鼠訊息
  15:     // .....
  16:  
  17: protected:
  18:     virtual ~AspectMouseClicks()
  19:     {}
  20: };


  還是寫一個按鈕,它想處理自己的滑鼠按下訊息,程式碼大概像這樣:

   1: class Button:public AspectMouseClicks</*一大堆引數*/>
   2: {
   3:     Button()
   4:     {
   5:         onLeftMouseUp( &Button::mousePressed );
   6:     }
   7:     
   8:     void mousePressed( MouseEvent& me )
   9:     {
  10:         // mouse is pressed
  11:         // do something
  12:     }
  13: };


  而因為 SmartWin++ 的設計上的問題,除了按鈕本身之外,僅有按鈕的祖先視窗(包括父視窗)物件也能夠處理它的滑鼠訊息。比如一個視窗 TestWindow,在它之上建立了按鈕 Button,則這個按鈕的訊息要麼被 TestWindow 處理,要麼被自己處理,不能被其它的外部類或函式處理。TestWndow 當中處理這個按鈕的滑鼠按下的訊息的程式碼大概像這樣:

   1: class TestWindow:public Something
   2: {
   3:  
   4: public:
   5:  
   6:     TestWindow()
   7:     {
   8:         Button* button = createButton();
   9:         button->onLeftMouseUp( &TestWindow::mousePressed );
  10:     }
  11:  
  12:     void mousePressed( MouseEvent& me )
  13:     {
  14:         // mouse is pressed
  15:         // do something
  16:     }
  17: };


  SmartWin++ 表面上看起來是使用的函式指標,效率應該會比 AWT 的虛擬函式高一些,其它不然。看看上面的程式碼,指定訊息處理函式的時候,並沒有把訊息處理函式的擁有者的指標傳進去。因此在用函式指標呼叫函式的時候,SmartWin++ 框架為了尋找到函式的擁有者指標,用了很齷齪低效的的一個方法,也正是這樣的方法,使得父視窗類之外的其它類或函式不可能參與到訊息的處理當中來。

自己的機制:
  
  像上面說的,自己新寫的這個訊息機制介於 AWT 的 Listeners 與 SmartWin 的 Aspects 之間。這個框架當中的MouseListener 的定義看起來像這樣:

   1: <typename TImpl>
   2: class MouseListener
   3: {
   4:  
   5: public:
   6:  
   7:     void onMouseClicked( TOwner* owner,MemberHandler handler );
   8:     void onMousePressed( TOwner* owner,MemberHandler handler );
   9:     void onMouseReleased( TOwner* owner,MemberHandler handler );
  10:     void onMouseDblclk( TOwner* owner,MemberHandler handler );
  11:     void onMouseEntered( TOwner* owner,MemberHandler handler );
  12:     void onMouseExited( TOwner* owner,MemberHandler handler );
  13:     void onMouseMoved( TOwner* owner,MemberHandler handler );
  14:  
  15: };


  有滑鼠訊息的 GUI 類都已經從這個 Listener 繼承,比如說如果要寫一個按鈕類,想要它有響應滑鼠按下訊息的能力,則程式碼大概是這樣:

   1:  
   2: // 從 MouseListener 繼承
   3: class Button:public MouseListener<Button>
   4:             ,public SomethingElse
   5: {
   6:  
   7: public:
   8:  
   9:     Button()
  10:     {
  11:         onMousePressed( this,&Button::mousePressed );
  12:     }
  13:     
  14:     void mousePressed( UINT keys,POINT cursor )
  15:     {
  16:         // mouse is pressed
  17:         // do something
  18:     }
  19: };


  因為 Button 已經從 MouseListener 派生,所以所有它的祖先視窗和父視窗都能用 MouseListener 的函式 onMousePressed 來註冊自己的處理函式:

   1: class TestWindow
   2: {
   3:  
   4: public:
   5:  
   6:     TestWindow()
   7:     {
   8:         Button* button = new Button();
   9:         button->onMousePressed( this,&TestWindow::mousePressed );
  10:     }
  11:  
  12:     void mousePressed( Widget* source,UINT keys,POINT cursor )
  13:     {
  14:         // mouse is pressed
  15:         // do something
  16:     }
  17: };


  需要注意的,這個 mousePressed 函式多了一個 Widget* 型別的 source 引數,以便在一個函式處理多個 GUI 物件的滑鼠訊息的時候,用來區別滑鼠訊息是來自哪一個 GUI 物件。因為在按鈕類當中,知道是處理的自己的訊息,所以就不需要這樣一個額外的引數。

  到目前為止看起來好像都跟 SmartWin++ 沒有多大的區別。不過這個框架允許任何類甚至全域性函式也能處理任何 GUI 物件對外公開的訊息。比如說有一個額外的類想處理上面那個按鈕的滑鼠按下訊息,其程式碼大概像這樣:

   1: // 從 MouseListener 介面派生
   2: class MouseEventTester:public MessageListener
   3: {
   4:  
   5: public:
   6:  
   7:     void mousePressed( Widget* source,UINT keys,POINT cursor )
   8:     {
   9:         // mouse is on source,and it is pressed
  10:         // do something;
  11:     }
  12: };
  13:  
  14:  
  15: MouseEventTester* tester = new MouseEventTester();
  16:  
  17: // 新增到按鈕的滑鼠 Listener 列表當中
  18: Button* button = new Button();
  19: button->addListener( &tester );


  這個類不用派生自 MouseListener,而是直接派生自了底層的 MessageListener(其實 MessageListener 對外只提供了一個函式 handleMessage)

  除了上面的方式,也可以這樣幹,更簡單一些,甚至不用任何派生。

   1: // 從 MouseListener 介面派生
   2: class MouseEventTester
   3: {
   4:  
   5: public:
            
           

相關推薦

拋棄一個 GUI 訊息機制重寫一個靈活高效

  拋棄了上一個訊息機制,因為它的實現不得不多用了幾個模板函式,在使用的時候有程式碼膨脹的現象。雖然其程度不如 win32gui,SmartWin,不過因為本人有點極端,所以相當地不滿意。於是又開始寫一個新的訊息機制,它的外表看起來像是 SmartWin++ 和 AWT 的混血兒。    SmartW

網易2019校招程式設計筆試題給定一個N*M矩陣

尚有不足,請高手勿噴,有高見者請不吝賜教 import java.util.Scanner; public class T2 { /*  * 給定一個N*M矩陣,放了牌,朝上  * 對於每個牌進行以下操作  * 翻轉一張牌,與之相鄰的八張牌也翻轉  *

click事件會影響chromeenter的mouseenter和mouseleave這是一個錯誤嗎?【用別人的一個標題為了方便搜尋】

直接上圖:需求是滑鼠移走poptip的時候,提示框消失,但是裡邊點選是ok的 但是bug來了,點選點著就消失了,神奇了。。。 然後找到了一篇文章 https://cloud.tencent.com/developer/ask/172332/answer/274607 主要是chr

spring activeMQ 整合(三): 確認機制ACK(收到訊息應該有一個迴應也就是確認答覆)

之前寫的spring   activemq整合的demo   ,今天繼續完善一下這個demo,讓功能更強大。 繼上篇文章之後,我訊息傳送失敗後,可以重新發送了。但是至於別人有沒有收到,這就不得而而而知了。 這時候就要用到ACK確認機制了。 1.ACK機制:  

objc在向一個物件傳送訊息發生什麼?

objc在向一個物件傳送訊息時,runtime庫會根據物件的isa指標找到該物件實際所屬的類,然後在該類中的方法列表以及其父類方法列表中尋找方法執行,然後在傳送訊息的時候,objc_msgSend方法不會返回值,所謂的返回內容都是具體呼叫時執行的 objc中向

MTU的概念什麽是路徑MTU? MTU發現機制TraceRoute(解)

iss 系列 過大 div 個數 cer pla 大數 因特網 1、MTU的概念 MTU即Maximum Transmission Unit 最大傳輸單元。它是指一種通信協議的某一層上面所能通過的最大數據包大小(以字節為單位)。 2、路徑MTU 路徑MT

今天做一個項目的時候要在一個編輯的jsp頁面的textarea標簽設置value屬性結果發現他沒有value屬性但是是編輯頁面又必須要回顯要修改的內容所以在參考w3cschool之後很輕松的解決這個問題。

w3cschool 一個 ansi cli enc per table prefix cin 今天做一個項目的時候,要在一個編輯的jsp頁面的textarea標簽設置value屬性,結果發現他沒有value屬性,但是是編輯頁面又必須要回顯要修改的內容,所以在參考了w3csc

這是一個非常簡單的題目意在考察你程式設計的基礎能力。千萬別想難哦。輸入為一行包括用空格分隔的三個整數 AA、BB、CC(資料範圍均在-40−40 ~ 4040 之間)。輸出為一行為“A+B+CA

這是一個非常簡單的題目,意在考察你程式設計的基礎能力。千萬別想難了哦。 輸入為一行,包括了用空格分隔的三個整數 A、B、C(資料範圍均在−40 ~ 40 之間)。 輸出為一行,為“A+B+C”的計算結果。 樣例輸入 22 1 3 樣例輸出 26 import java.util.

MFC中傳送自定義訊息機制PostMessage和SendMessage方式

       MFC中有種訊息佇列,使用PostMessage()或者SendMessage()給窗體傳送自定義訊息,當窗體接收到訊息時呼叫該訊息對應繫結的方法。 PostMessage:把訊息投放到執行緒的訊息佇列,不等訊息被處理就立即返回;Send

StartActivityForRequest的傳遞機制從下一個活動向上一個活動傳遞資料

關於startActivityforRequest的使用 想要實現的效果 在一個主介面中點選進入下一個活動,當回到主介面中時,將該活動獲得的資料資訊傳遞到主活動中,類似於使用者釋出訊息,釋出成功後進入訊息頁面 //在主介面的activity定義intent和

Android的訊息機制用Android執行緒間通訊的Message機制Android中Handler的使用方法

轉自:http://www.cnblogs.com/-OYK/archive/2011/08/03/2126657.html Android的訊息機制(一)   android 有一種叫訊息佇列的說法,這裡我們可以這樣理解:假如一個隧道就是一個訊息佇列,那麼裡

分享一個分散式訊息匯流排基於.NET Socket Tcp的釋出-訂閱框架附程式碼下載

一、分散式訊息匯流排      在很多MIS專案之中都有這樣的需求,需要一個及時、高效的的通知機制,即比如當使用者A完成了任務X,就需要立即告知使用者B任務X已經完成,在通常的情況下,開發人中都是在使用者B所使用的程式之中寫資料庫輪循程式碼,這樣就會產品一個很嚴重的兩個問題,第一個問題是延遲,輪循機制要定時

JAVA--第十週作業編寫之一個Teacher類負責給出算術題目隨機給出兩個整數並進行運算並判斷回答者的答案是否正確;編寫一個GUI類ComputerFrame回答者可以通過GUI看到題目並給出

感言:剛開始編的時候沒有把number和number1 設為全域性變數,導致結果不正確。還有本來用的是AWT類,現在改成了Swing類,這個類功能比較強大,元件和視覺化介面都很好。但是不知道圖片怎麼顯示不出來了,在ecplise上應該可以顯示出來的。import jav

部署在WildFly的EJB客戶端呼叫另一個WildFly的EJB服務的過程詳解

本文是前一篇博文的繼續,應用的場景如下:     EJB服務開發完畢後,以ear或jar的方式部署在一個WildFly伺服器上;     EJB客戶端開發(詳解前一篇博文)完畢後,以war的方式(也可以是另外一個ear)部署在另一個WildFly伺服器上。 對於部署EJB

每日一問:Android 訊息機制我有必要再講一次!

堅持原創日更,短平快的 Android 進階系列,敬請直接在微信公眾號搜尋:nanchen,直接關注並設為星標,精彩不容錯過。 我 17 年的 面試系列,曾寫過一篇名為:Android 面試(五):探索 Android 的 Handler 的文章,主要講述的是 Handler 的原理相關面試題,然後簡單地給與

面試官:“看你簡歷寫熟悉 Handler 機制那聊聊 IdleHandler 吧?”

一. 序 Handler 機制算是 Android 基本功,面試常客。但現在面試,多數已經不會直接讓你講講 Handler 的機制,Looper 是如何迴圈的,MessageQueue 是如何管理 Message 等,而是基於場景去提問,看看你對 Handler 機制的掌握是否紮實。 本文就來聊聊 H

點擊頁面的按鈕使之打開一個新窗口加載一個頁面的方法有哪些呢?

body del .html blank oca pos type target put 1.<base target="_blank" /> 頁面只要有a標簽,都會打開一個新的頁面; 2.<input type=‘button‘ value=‘new‘

Java程序員:這是一個最好的時代也是一個最壞的時代

Java狄更斯的《雙城記》有一句話:這是一個最好的時代,也是一個最壞的時代。 對大多數人來說,這是一個最壞的時代。因為變化太大、太快,遠遠超過普通人的想象力和承受力。對極少數人來說,這也是一個最好的時代。因為只要敏銳的抓住了機會,然後善於利用,就可能達到一個前所未有的高度。 作為技術工作者(程序員),我們享受

太深了,梯度傳不下去於是有highway。 幹脆連highway的參數都不要直接變殘差於是有ResNet。 強行穩定參數的均值和方差於是有BatchNorm。RNN梯度不穩定於是加幾個通路和門控於是有LSTM。 LSTM簡化一下GRU。

梯度 直接 ID orm rop 發展 均值 nor 噪聲 請簡述神經網絡的發展史sigmoid會飽和,造成梯度消失。於是有了ReLU。ReLU負半軸是死區,造成梯度變0。於是有了LeakyReLU,PReLU。強調梯度和權值分布的穩定性,由此有了ELU,以及較新的SELU