在不同ToolButton觸發MouseUp 事件的問題(可能涉及 Delphi) |
答題得分者是:m8815010
|
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
我原先在 "C++程式語言討論區(C++Builder)" 區提出一個有關 TToolButton 的問題 (http://delphi.ktop.com.tw/topic.php?TOPIC_ID=58993),至今未能獲得任何回應,我想大概是發錯區或是提問方式不得要領,因此改到此區重新發問,希望能獲得諸位先進們的協助。 這次我以範例來說明問題,測試檔案的建立步驟如下:
1. 建立新專案。 2. 在 Form1 上放置一個 TToolBar,並建立 4 個 (或多個) TToolButton。 3. 在 Form1 下端放置一個 TPanel,並在其上設置 4 個 (或多個) TSpeedButton。 4. 在 Form1 中央或空檔處設置一個 TMemo 物件。 5. 所有的 TToolButton 及 TSpeedButton 均共用相同的 OnMouseDown 及 OnMouseUp 事件。 6. 在 MouseDown/MouseUp 事件中分別將按下/釋放的按鈕名稱及滑鼠 X, Y 座標值的訊息記錄到 Memo1 內。 接下來我說明問題:
1. 當我在上方的 ToolBar1 點選 ToolButton1 後,由 Memo1 中可見到 Mouse Down 及 Mouse Up 的觸發訊息。 2. 當我在上方的 ToolBar1 點選 ToolButton1 並按住滑鼠左鍵不放,然後移到其它的 ToolButton2 (或ToolButton1 之外的其它 TToolButton) 上方再放掉滑鼠左鍵,結果由 Memo1 中僅能見到 Mouse Down 的觸發訊息,Mouse Up 訊息未能被記錄。 3. 在 Panel1 上以上述相同方式來測試 TSpeedButton 的結果不會有第 2 項的問題,Mouse Down 及 Mouse Up 事件均可被正確的觸發。 我想請教各位先進的是:
1. TToolButton 為何無法在其它同類按鈕處接收到 MouseUp 事件? 2. 有沒有什麼方法能 TToolButton 能在其它同類按鈕處接收到 MouseUp 事件,例如:改寫原型、直接在自己程式中加一段程序、使用 API、攔截系統訊息....等等。 附註:
因為我使用的開發工具是 BCB4,因此我將問題分類歸為 BCB 類,但是可能涉及元件的原型問題,所以在標題加註 (可能涉及 Delphi),另外為了便於討論,我也將測試檔案的內容列出如下:(預視時無法將所有內容一次貼出,不知是否為系統限制?因此分段貼出) 發表人 - RedSnow 於 2004/11/23 19:38:17
|
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
Unit2.h 內容:
//--------------------------------------------------------------------------- #ifndef Unit2H #define Unit2H //--------------------------------------------------------------------------- #includeUnit2.cpp 內容: //--------------------------------------------------------------------------- #include |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
Unit2.dfm 內容:
object Form1: TForm1 Left = 192 Top = 108 Width = 544 Height = 257 Caption = 'Form1' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object ToolBar1: TToolBar Left = 0 Top = 0 Width = 536 Height = 33 ButtonHeight = 21 ButtonWidth = 65 Caption = 'ToolBar1' ShowCaptions = True TabOrder = 0 object ToolButton1: TToolButton Left = 0 Top = 2 Caption = 'ToolButton1' ImageIndex = 0 OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end object ToolButton2: TToolButton Left = 65 Top = 2 Caption = 'ToolButton2' ImageIndex = 1 OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end object ToolButton3: TToolButton Left = 130 Top = 2 Caption = 'ToolButton3' ImageIndex = 2 OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end object ToolButton4: TToolButton Left = 195 Top = 2 Caption = 'ToolButton4' ImageIndex = 3 OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end end object Memo1: TMemo Left = 0 Top = 33 Width = 536 Height = 156 Align = alClient ScrollBars = ssBoth TabOrder = 1 end object Panel1: TPanel Left = 0 Top = 189 Width = 536 Height = 41 Align = alBottom TabOrder = 2 object SpeedButton1: TSpeedButton Left = 8 Top = 8 Width = 65 Height = 21 Caption = 'SpeedButton1' OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end object SpeedButton2: TSpeedButton Left = 73 Top = 8 Width = 65 Height = 21 Caption = 'SpeedButton1' OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end object SpeedButton3: TSpeedButton Left = 138 Top = 8 Width = 65 Height = 21 Caption = 'SpeedButton1' OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end object SpeedButton4: TSpeedButton Left = 203 Top = 8 Width = 65 Height = 21 Caption = 'SpeedButton1' OnMouseDown = ToolButton1MouseDown OnMouseUp = ToolButton1MouseUp end end end |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
另外我也查看過 VCL 的相關原始檔案,結果如下: TToolButton 的原型在 comctrls.pas 檔案中,其 MouseUp 事件的設定如下:
procedure TToolButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited MouseUp(Button, Shift, X, Y); if (Button = mbLeft) and (X >= 0) and (X < ClientWidth) and (Y >= 0) and (Y <= ClientHeight) then begin if then Down := False; Click; end; end;TSpeedButton 的原型在 buttons.pas 檔案中,其 MouseUp 事件的設定如下: procedure TSpeedButton.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var DoClick: Boolean; begin inherited MouseUp(Button, Shift, X, Y); if FDragging then begin FDragging := False; DoClick := (X >= 0) and (X < ClientWidth) and (Y >= 0) and (Y <= ClientHeight); if FGroupIndex = 0 then begin { Redraw face in-case mouse is captured } FState := bsUp; FMouseInControl := False; if DoClick and not (FState in [bsExclusive, bsDown]) then Invalidate; end else if DoClick then begin SetDown(not FDown); if FDown then Repaint; end else begin if FDown then FState := bsExclusive; Repaint; end; if DoClick then Click; UpdateTracking; end; end;我並不知道兩者的設定為何不同?我也不太懂 Delphi,因此不知道這些設定是否與 TToolButton 在不同位置上接收 MouseUp 事件有何種關聯? |
m8815010
版主 發表:99 回覆:372 積分:289 註冊:2003-11-13 發送簡訊給我 |
RedSnow你好< >: 終於看懂你隴長的題目,提供一點小小研究心得< >! 正常的button click事件是同一點buttondown然後buttonup的,但會有特別的分開行為,也就是和你說的情況一樣: 1.按下ToolButton,然後按著,離開ToolButton後再放開
2.在其它region按下滑鼠左鍵,按著,移到ToolButton上再放開
3.按下ToolButton,按著不放,再用Ctrl tab鍵切換Ap
4.其它特異的手法...... 針對這些不同的操作過程,Builder當然也對每個元件撰寫對應的程式碼,但每個元件不儘相同,也因此造成如TToolButton、TSpeenButton等不同的反應結果! 以Builder來說,是以Application為最上層的觀念,所以今天滑鼠、keyboard等外部的I/O會先由Ap本身得到訊息,再由Ap決定要把該訊息送給內部的那些元件! 以TSpeedButton等元件而言,只要ButtonDown是在它的區域內發生後,不管你的ButtonuUp動作在那裏發生,Application本身都會認定這個ButtonUp訊息就是屬於你的,所以一定會把WM_LBUTTONUP訊息送給SpeedButton!也就是down、up一定是一組的,不可分離!這是TSpeedButton的運作方式! 而TToolButton則不然,結果就是那樣,如果ButtonUp在其它ToolButton上發生時,則這個訊息將被skip掉,也就是Application不會將WM_LBUTTONUP訊息送給原來的那個ToolButton,也就是down、up不會同步! 看了一下source code,要overriding等,似乎有一定的難度,連看懂也不昜,因為牽連的所source不只post的那些! 我用比較笨的方式implement,因為比較簡單,精神就是一定要把button down後的那個button up訊息,無條件的送給被按下的那個ToolButton! sample:
In .h ~~ class TForm1 : public TForm { __published: // IDE-managed Components TToolBar *ToolBar1; TToolButton *ToolButton1; TToolButton *ToolButton2; TToolButton *ToolButton3; TToolButton *ToolButton4; TMemo *Memo1; TApplicationEvents *ApplicationEvents1; void __fastcall ToolButton1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); void __fastcall ApplicationEvents1Message(tagMSG &Msg, bool &Handled); void __fastcall ToolButton1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y); private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); void __fastcall MenuItemOnClick(TObject* Sender); }; ~~ In .cpp ~~ bool if_down=false; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg, bool &Handled) { if (Msg.message==WM_LBUTTONUP && if_down) { TShiftState ss; ss << ssLeft; ToolButton1MouseUp(ToolButton1,mbLeft,ss,LOWORD(Msg.lParam),HIWORD(Msg.lParam)); if_down=false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::ToolButton1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { Memo1->Lines->Add("Down"); if_down=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::ToolButton1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (if_down) { Memo1->Lines->Add("Up"); if_down=false; } }Conclusion 1.我的測試環境是BCB 6.0,4.0的話可能完全不適用! 2.我測試TToolButton只有在up事件移到其它TToolButton上發生時,才有收不到訊息的問題,其它一切情況都可以! 3.本例可避免這種問題,但方法很笨,可是很直覺! 4.因為Builder有現成的Application Message事件可用,所以先直接引用! 5.本範例只針對TToolButton1做處理 6.本範例只針對滑鼠左鍵做處理 小小研究心得,不保正字字正確,希望有幫助! |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
m8815010 您好: 首先為了您騰出時間提供協助而致謝,其次為了讓您看了那麼冏長的問題而致歉。 我提出的問題是因為想要使用拖曳方式來調整 TToolBar 上的 TToolButton 位置而引發的,因此才會有在不同按鈕上檢測 MouseDown 及 DownUp 事件的需求。 我試了一下您提供的方式,結果正如您所預料的,BCB4 並未支援 TApplicationEvents 這個物件,看來您提供的這招我是無法 "直接" 使用了,我會試試看可否以攔截 Application 訊息的方式來 "比照" 處理? 發表人 - RedSnow 於 2004/11/25 21:38:43
|
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
m8815010 您好: 我試著用 Application->OnMessage 的方式來代替 TApplicationEvents 的偵測動作,大致上可以達到和您寫出來的動作相同,但是這僅解決了 MouseUp 事件的觸發,我仍然無法取得觸發 MouseUp 事件時滑鼠指標所在的按鈕名稱,請問您是否知道在下列以紅色標示處,是否有辦法動態取得觸發 MouseUp 事件時游標所在的按鈕名稱? 程式所設定數個 TToolButton 的 OnMouseDown 與 OnMouseUp 均共用 ToolButton1MouseDown 與 ToolButton1MouseUp 事件。
bool if_down=false; __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { Application->OnMessage = AppMessage; } //--------------------------------------------------------------------------- void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled) { if(Msg.message == WM_LBUTTONUP && if_down){ TShiftState ss; ss << ssLeft; ToolButton1MouseUp(ToolButton1, mbLeft, ss, LOWORD(Msg.lParam),HIWORD(Msg.lParam)); if_down=false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::ToolButton1MouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { Memo1->Lines->Add("Button Down: \t" ((TToolButton*)Sender)->Name ", X=" IntToStr(X) ", Y=" IntToStr(Y)); if_down=true; } //--------------------------------------------------------------------------- void __fastcall TForm1::ToolButton1MouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { Memo1->Lines->Add("Button Up: \t" ((TToolButton*)Sender)->Name ", X=" IntToStr(X) ", Y=" IntToStr(Y)); if_down=false; } //--------------------------------------------------------------------------- .... 餘略 .... |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
剛才邊試邊找資料,結果下列這兩篇資料分別給了我一些啟發: http://delphi.ktop.com.tw/topic.php?topic_id=43058
http://delphi.ktop.com.tw/topic.php?topic_id=41000 因此我試著將前一篇求解的那一行敘述:
ToolButton1MouseUp(ToolButton1, mbLeft, ss, LOWORD(Msg.lParam),HIWORD(Msg.lParam));
改成如下:
PostMessage(Msg.hwnd, WM_LBUTTONUP, 0, Msg.lParam);
結果可以達到我所要的效果了,有相同問題的網友們不妨也參考一下。 再次多謝 m8815010 版主的協助,以及上述兩篇舊文裡 dllee 及 helliluya 兩位的啟發。
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |