線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2335
推到 Plurk!
推到 Facebook!

在不同ToolButton觸發MouseUp 事件的問題(可能涉及 Delphi)

答題得分者是:m8815010
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-11-23 18:34:37 IP:219.137.xxx.xxx 未訂閱
我原先在 "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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-11-23 18:49:00 IP:219.137.xxx.xxx 未訂閱
Unit2.h 內容:
//---------------------------------------------------------------------------
#ifndef Unit2H
#define Unit2H
//---------------------------------------------------------------------------
#include 
#include 
#include 
#include <Forms.hpp>
#include 
#include 
#include <Buttons.hpp>
#include 
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:        // IDE-managed Components
        TToolBar *ToolBar1;
        TToolButton *ToolButton1;
        TToolButton *ToolButton2;
        TToolButton *ToolButton3;
        TToolButton *ToolButton4;
        TMemo *Memo1;
        TPanel *Panel1;
        TSpeedButton *SpeedButton1;
        TSpeedButton *SpeedButton2;
        TSpeedButton *SpeedButton3;
        TSpeedButton *SpeedButton4;
        void __fastcall ToolButton1MouseUp(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y);
        void __fastcall ToolButton1MouseDown(TObject *Sender, TMouseButton Button,
          TShiftState Shift, int X, int Y);
private:        // User declarations
public:                // User declarations
        __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Unit2.cpp 內容:
//---------------------------------------------------------------------------
#include 
#pragma hdrstop    #include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------    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));
}
//---------------------------------------------------------------------------    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));
}
//---------------------------------------------------------------------------
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-11-23 18:50:22 IP:219.137.xxx.xxx 未訂閱
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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-11-23 18:51:33 IP:219.137.xxx.xxx 未訂閱
另外我也查看過 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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-11-25 00:10:29 IP:59.104.xxx.xxx 未訂閱
    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

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-11-25 21:11:07 IP:219.137.xxx.xxx 未訂閱
m8815010 您好: 首先為了您騰出時間提供協助而致謝,其次為了讓您看了那麼冏長的問題而致歉。 我提出的問題是因為想要使用拖曳方式來調整 TToolBar 上的 TToolButton 位置而引發的,因此才會有在不同按鈕上檢測 MouseDown 及 DownUp 事件的需求。 我試了一下您提供的方式,結果正如您所預料的,BCB4 並未支援 TApplicationEvents 這個物件,看來您提供的這招我是無法 "直接" 使用了,我會試試看可否以攔截 Application 訊息的方式來 "比照" 處理? 發表人 - RedSnow 於 2004/11/25 21:38:43
RedSnow
版主


發表:79
回覆:1322
積分:845
註冊:2003-12-15

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-11-26 00:01:30 IP:219.137.xxx.xxx 未訂閱
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

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-11-26 00:51:28 IP:219.137.xxx.xxx 未訂閱
剛才邊試邊找資料,結果下列這兩篇資料分別給了我一些啟發:    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 兩位的啟發。
系統時間:2024-03-29 15:37:29
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!