Q&A

  • 마우스 이벤트에 관한 질문입니다...(버튼 한번만 클릭되게..)
버튼을 클릭하면 어떤 작업이 끝날때까지 다시 그 버튼을 클릭 못하게 하고 싶은데..
아래처럼 버튼 클릭과 동이세 버튼을 Disable시켜도 안되네요..
왜그러죠? 델파이는 원래 그런가요? VB는 안그런거 같은데..

예를 들어 SomeDo라는 함수가 DB에 연결하는 함수라면..
버튼위에서 마우스를 다다다다~ 눌러버리면..
버튼 이벤트가 계속 먹어서 계속 DB에 연결을 시도합니다.
도와주세요~~ㅋㅋ

procedure TForm1.Button1Click(Sender: TObject);
begin
  screen.Cursor := crHourGlass;
  Button1.Enabled := false;
  sleep(3000);                ->요건 테스트를 위해서 집어넣은겁니다.
//SomeDo()...........
  Button1.Enabled := true;
  screen.Cursor := crdefault;
end;

2  COMMENTS
  • Profile
    고지범 2002.09.02 20:22
    음.. 이런 경우는 델파이나 혹은 개발툴의 문제가 아니라 어플리케이션 디자인에 관한 문제 같군요...
    가령, 아래 코드에서 SomeDo() 라는 procedure/function이 동기성을 가지지 못하는 경우, 즉 TForm1.Button1Click 이라는 procedure 안에서 호출하는 것으로 끝나는 것이 아니라 추가적인 작업을 하여서 나중에야 결과가 나타나는 경우-보통 Asyncronous call이라고들 합니다. 말씀하신 DB 연결 등도 마찬가지겠지요...- 해당 작업이 언제 끝나는 지, 지금 진행하고 있는 지 등의 정보가 필요하겠지요...
    제가 생각하기에 가장 간단하고 델파이적인 방식은 TActionManager (Delphi 6), TActionList (Delphi 5)인 듯합니다.
    TActionManager/TActionList에 TAction을 추가시키시고요... Object Inspector를 보시면 OnExecute, OnHint, OnUpdate 라는 Event-handler가 보입니다. 각각은,
    OnExecute : Action 실행 코드
    OnHint : Hint를 보일때 Hint 내용(string), 보일지 여부 결정.
    OnUpdate : 해당 Action의 UI, 혹은 동작여부 결정.
    등의 일을 합니다.
    가령 DB 연결하기 같은 경우는 DB가 연결되어 있는 경우에는 Disabled 되면 되겠지요. 따라서 DB 연결되었음을 나타내는 변수가 있다면, 아래와 같이...
      TForm1 = class(TForm)
        Database1: TDatabase;
        Button1: TButton;
        ActionManager1: TActionManager;
        acDBConnect: TAction; // Button1.Action := acDBConnect로 설정
      private
        FDBConnected :Boolean;
      protected
      procedure Invoke_DBConnection_Thread();
      ......
      end;
      TDBConThread = class(TThead)
      protected
         procedure Execute;override;
      end;

    procedure TDBConThread.Execeute;
    begin
       try
          try
             Form1.DataBase1.Connected := TRUE;
          except
             Form1.DataBase1.Connected := FALSE;
          end;
       finally
          Form1.FDBConnected := Form1.DataBase1.Connected ;
       end;
    end;

    procedure TForm1.acDBConnectExecute(Sender: TObject);
    begin
       if FDBConnected then exit; // 혹시라도 모르니깐...
       Invoke_DBConnection_Thread();
    end;

    procedure TForm1.Invoke_DBConnection_Thread();
    begin
       // thread reference는 저장할 필요 없고 해제도 thread 자신이 함.
       with TDBConThread.Create(TRUE) do begin
          // 다른 설정들...
          FreeOnTerminate := TRUE;
          Resume();
       end;
    end;

    procedure TForm1.acDBConnectHint(var HintStr: String;
      var CanShow: Boolean);
    begin
    // 힌트관련...
    end;

    procedure TForm1.acDBConnectUpdate(Sender: TObject);
    begin
       acDBConnect.Enabled := not FDBConnected;
    end;

    음.. 역시 이런건 간단히 설명이 안되는 군요..
    암튼 오늘도 즐입다...

  • Profile
    홍성락 2002.09.02 20:08
    hsr///////////////////////////////////////////////////////
    버튼 클릭시 최초 더블클릭하면 2번 이상 실행되는건가요?
    버튼은 더블클릭 이벤트를 벌도로 빼내어 있지 않아 더블클릭 제어는 직접못할거 같군요.
    다른 분들의 좋은 방법도 있겠으나 마우스 후킹(MOUSEHook)
    과 전역변수(DblClick :boolean;)로 막아 보았습니다.
    unit Unit1;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;

    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
        procedure FormShow(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
      private
        { Private declarations }
        DblClick :boolean;                     //마우스더블클릭에 필요한 변수
      public
        { Public declarations }
      end;

    var
      Form1: TForm1;

      MOUSEHook: HHOOK;
      function MOUSE_Hook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LResult; stdcall;
    implementation

    {$R *.dfm}
    function MOUSE_Hook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LResult;
    begin
      if nCode > -1 then begin
        if (wParam = WM_LBUTTONDBLCLK) then begin
           Form1.DblClick := True;
        end;
        Result := 0;
      end
      else Result := CallNextHookEx(MOUSEHook, nCode, wParam, lParam);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      if DblClick then begin
         DblClick := false;
         exit;
      end;
      screen.Cursor := crHourGlass;
      Button1.Caption := Button1.Caption + '1';
      Button1.Enabled := false;
      sleep(3000);               // ->요건 테스트를 위해서 집어넣은겁니다.
       //SomeDo()...........
      Button1.Enabled := true;
      screen.Cursor := crdefault;
    end;

    procedure TForm1.FormShow(Sender: TObject);
    begin
        DblClick := false;
        MOUSEHook := SetWindowsHookEx(WH_MOUSE, @MOUSE_Hook, 0, GetCurrentThreadID);
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
        UnHookWindowsHookEx(MOUSEHook);
    end;

    end.