Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > ShorCut у Action


Автор: Frees 7.5.2008, 09:37
На форме есть кнопка которой назначена Action1 у акций ShortCut = Del

Если активным контролом будет Edit1 и нажать кнопку Del, что бы удалить символ из  Edit1, то начнет выполняться акция а символ не удалится. 

А нужно что бы когда активным контролом был Edit1 при нажатий кнопки Del акция не выполнялась а удалился символ в Edit1

как можно решить?

пробовал так:
в событий OnUpdate у ActionList написать
Код

procedure TForm1.ActionList1Update(Action: TBasicAction;
  var Handled: Boolean);
begin
  inherited;
  if ActiveControl is TEdit then
     ActionList1.State := asSuspended
     else ActionList1.State := asNormal;
end;



но в таком случае находясь в Edit1 и нажав на Button в котором указана Action1 она не выполняется, так как кнопки которые я использую не принимаю на себя фокус и ActionList1.State := asNormal; не выполняется.

Автор: MetalFan 7.5.2008, 10:16
Цитата(Frees @  7.5.2008,  09:37 Найти цитируемый пост)
Если на форме будет еще и едит то Кнопка дел того что бы стереть символ вызовет выполнение акций

шо сказал?!  smile не понял

Автор: Frees 7.5.2008, 10:25
Если активным контролом будет Edit1 и нажать кнопку Del, что бы удалить символ из  Edit1, то начнет выполняться акция а символ не удалится. 

так понятнее или еще пояснить?

Автор: MetalFan 7.5.2008, 10:59
так, это выяснили... а что надо, чтобы происходило?

Автор: Frees 7.5.2008, 11:33
нужно что бы когда активным контролом был Edit1 при нажатий кнопки Del акция не выполнялась а удалился символ в Edit1

Автор: Rennigth 7.5.2008, 11:52
Frees, А дизейслить Action по события едита OnEnter  и енаблить по OnExit непробовал?

Добавлено через 5 минут и 6 секунд
Frees, вот например, все ок работает.
Код

unit Unit31;

interface

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

type
  TForm31 = class(TForm)
    edt1: TEdit;
    actlst1: TActionList;
    actTest: TAction;
    btn1: TButton;
    procedure actTestExecute(Sender: TObject);
    procedure edt1Enter(Sender: TObject);
    procedure edt1Exit(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form31: TForm31;

implementation

{$R *.dfm}

procedure TForm31.actTestExecute(Sender: TObject);
begin
  ShowMessage('');
end;

procedure TForm31.edt1Enter(Sender: TObject);
begin
  actTest.Enabled := False;
end;

procedure TForm31.edt1Exit(Sender: TObject);
begin
  actTest.Enabled := True;
end;

end.


Нужно сделать конечно более универсально, но эт ты уже сам smile

Автор: Frees 7.5.2008, 12:00
Цитата(Rennigth @  7.5.2008,  11:52 Найти цитируемый пост)
А дизейслить Action по события едита OnEnter  и енаблить по OnExit непробовал?

тут 2 проблемы первое: форм много контролов на них тоже и писать обработку OnEnter и OnExit в каждой форме не очень хочется
второе если дизаблить  Action то кнопки с этими Action тоже будут отдизеблены что будет не оч красиво выглядеть

Автор: Rennigth 7.5.2008, 12:31
Цитата(Frees @  7.5.2008,  12:00 Найти цитируемый пост)
второе если дизаблить  Action то кнопки с этими Action тоже будут отдизеблены что что будет не оч красиво выглядеть 

Тады так можно:
Код

unit Unit31;

interface

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

type
  TForm31 = class(TForm)
    edt1: TEdit;
    actlst1: TActionList;
    actTest: TAction;
    btnTest: TButton;
    procedure actTestExecute(Sender: TObject);
    procedure edt1Enter(Sender: TObject);
    procedure edt1Exit(Sender: TObject);
  private
    lSaveShotCut: TShortCut;
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  Form31: TForm31;

implementation

{$R *.dfm}

procedure TForm31.actTestExecute(Sender: TObject);
begin
  ShowMessage('');
end;

constructor TForm31.Create(AOwner: TComponent);
begin
  inherited;
  lSaveShotCut := actTest.ShortCut;
end;

procedure TForm31.edt1Enter(Sender: TObject);
begin
  actTest.ShortCut := 0;
end;

procedure TForm31.edt1Exit(Sender: TObject);
begin
  actTest.ShortCut := lSaveShotCut;
end;

end.



Цитата(Frees @  7.5.2008,  12:00 Найти цитируемый пост)
тут 2 проблемы первое: форм много контролов на них тоже и писать обработку OnEnter и OnExit в каждой форме не очень хочется

Цитата(Rennigth @  7.5.2008,  11:52 Найти цитируемый пост)
Нужно сделать конечно более универсально

smile
Вообще нужно сделать класс который натравливать на форму, он и будет искать едитбл контролы и эшены, запонимать и переопределять у них OnEnter/OnExit.
Может не самый оптимальный вариант, но пока ничего лутшего не придумал.

Автор: MetalFan 7.5.2008, 13:03
вариант номер 3: написать наследника от TAction, перекрыть Execute, в котором сделать проверку контрола в фокусе....

Автор: Rrader 7.5.2008, 13:19
Frees, 
Код

Unit Unit1;

Interface

Uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, ActnList, StdCtrls, Buttons;

Type
  TForm1 = Class(TForm)
    Edit1: TEdit;
    ActionList1: TActionList;
    Action1: TAction;
    SpeedButton1: TSpeedButton;
    Button1: TButton;
    Procedure Action1Execute(Sender: TObject);
    Procedure FormCreate(Sender: TObject);
  Private
    { Private declarations }
  Public
    Procedure OnMyShortCut(Var Msg: TWMKey; Var Handled: Boolean);
    { Public declarations }
  End;

Var
  Form1: TForm1;

Implementation

{$R *.dfm}

Procedure TForm1.Action1Execute(Sender: TObject);
Begin
  ShowMessage('Yes');
End;

Procedure TForm1.FormCreate(Sender: TObject);
Begin
  OnShortCut := OnMyShortCut;
End;

Procedure TForm1.OnMyShortCut(Var Msg: TWMKey; Var Handled: Boolean);
Begin
  Handled := False;
  If Msg.CharCode = VK_DELETE Then
    If ActiveControl Is TEdit Then
    Begin
      (ActiveControl As TEdit).Perform(WM_KEYDOWN, Msg.CharCode, 0);
      Handled := True;
    End;
End;

End.

Автор: Rennigth 7.5.2008, 13:35
Frees, 
Накатал класс, сырой но рабочий, если понравиться, то доработаю. Пока только с Edit-ами умеет общаться:
Код

unit uAEASCBlocker;

(* By Bifor Rennigth *)
(* ... *)

interface

uses
  Windows, SysUtils, Classes, Controls, ActnList, Forms, StdCtrls;

type
  PEditbleCtrl = ^TEditbleCtrl;
  TEditbleCtrl = record
    Control: TEdit;
    OldOnEnter: TNotifyEvent;
    OldOnExit: TNotifyEvent;
  end;

  PActionCtrl = ^TActionCtrl;
  TActionCtrl = record
    Control: TAction;
    SaveShortCut: TShortCut;
  end;

  TAEActionSCBlocker = class(TComponent)
  private
    FEditbleCtrls: TList;
    FActions: TList;
    FShortCuts: array of TShortCut;
    FTargerForm: TCustomForm;
  protected
    procedure EditbleCtrlEnterEvent(ASender: TObject);
    procedure EditbleCtrlExitEvent(ASender: TObject);

    procedure LoadEditbleCtrls;
    procedure ClearEditbleCtrls;

    procedure LoadActions;
    procedure ClearActions;
  public
    constructor Create(AOwner: TComponent;
      ATargetForm: TCustomForm); reintroduce; virtual;
    destructor Destroy; override;

    procedure RegisterShortCuts(AShortCuts: array of TShortCut);
  end;

implementation

{ TAEActionSCBlocker }

procedure TAEActionSCBlocker.ClearActions;
var
  i: Integer;
begin
  for I := 0 to FActions.Count - 1 do
  begin
    FreeMemory(FActions.Items[i]);
    FActions.Clear;
  end;
end;

procedure TAEActionSCBlocker.ClearEditbleCtrls;
var
  i: Integer;
begin
  for I := 0 to FEditbleCtrls.Count - 1 do
  begin
    FreeMemory(FEditbleCtrls.Items[i]);
    FEditbleCtrls.Clear;
  end;
end;

constructor TAEActionSCBlocker.Create(AOwner: TComponent;
  ATargetForm: TCustomForm);
begin
  inherited Create(AOwner);
  FTargerForm := ATargetForm;

  FEditbleCtrls := TList.Create;
  FActions := TList.Create;
end;

destructor TAEActionSCBlocker.Destroy;
begin
  ClearEditbleCtrls;
  ClearActions;
  FreeAndNil(FEditbleCtrls);
  FreeAndNil(FActions);
  inherited;
end;

procedure TAEActionSCBlocker.EditbleCtrlEnterEvent(ASender: TObject);
var
  i: Integer;
  lpAC: PActionCtrl;
begin
  for i := 0 to FActions.Count - 1 do
  begin
    lpAC := FActions.Items[i];
    lpAC^.Control.ShortCut := 0;
  end;
end;

procedure TAEActionSCBlocker.EditbleCtrlExitEvent(ASender: TObject);
var
  i: Integer;
  lpAC: PActionCtrl;
begin
  for i := 0 to FActions.Count - 1 do
  begin
    lpAC := FActions.Items[i];
    lpAC^.Control.ShortCut := lpAC^.SaveShortCut;
  end;
end;

procedure TAEActionSCBlocker.LoadEditbleCtrls;
var
  i: Integer;
  lpEC: PEditbleCtrl;
  lEdit: TEdit;
begin
  ClearEditbleCtrls;
  if Assigned(FTargerForm) then
  begin
    for i := 0 to FTargerForm.ComponentCount - 1 do
      if (FTargerForm.Components[i] is TEdit) then
      begin
        lEdit := TEdit(FTargerForm.Components[i]);
        if Assigned(lEdit) then
        begin
          lpEC := GetMemory(SizeOF(TEditbleCtrl));
          lpEC^.Control := lEdit;
          lpEC^.OldOnEnter := lEdit.OnEnter;
          lpEC^.OldOnExit := lEdit.OnExit;
          lEdit.OnEnter := EditbleCtrlEnterEvent;
          lEdit.OnExit := EditbleCtrlExitEvent;
          FEditbleCtrls.Add(lpEC);
        end;
      end;
  end;
end;

procedure TAEActionSCBlocker.LoadActions;

  function ExistSC(ASC: TShortCut): Boolean;
  var
    i: Integer;
  begin
    Result := False;
    for i := Low(FShortCuts) to High(FShortCuts) do
      if FShortCuts[i] = ASC then
      begin
        Result := True;
        Break;
      end;
  end;

var
  lAction: TAction;
  lpAC: PActionCtrl;
  i: Integer;
begin
  ClearActions;
  if Assigned(FTargerForm) then
  begin
    for i := 0 to FTargerForm.ComponentCount - 1 do
      if (FTargerForm.Components[i] is TAction) then
      begin
        lAction := TAction(FTargerForm.Components[i]);
        if Assigned(lAction) and ExistSC(lAction.ShortCut) then
        begin
          lpAC := GetMemory(SizeOF(TActionCtrl));
          lpAC^.Control := lAction;
          lpAC^.SaveShortCut := lAction.ShortCut;
          FActions.Add(lpAC);
        end;
      end;
  end;
end;

procedure TAEActionSCBlocker.RegisterShortCuts(AShortCuts: array of TShortCut);
var
  i: Integer;
begin
  SetLength(FShortCuts, Length(AShortCuts));
  for i := Low(AShortCuts) to High(AShortCuts) do
    FShortCuts[i] := AShortCuts[i];

  LoadEditbleCtrls;
  LoadActions;
end;

end.


Использовать так:

Код

unit Unit31;

interface

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

type
  TForm31 = class(TForm)
    edt1: TEdit;
    actlst1: TActionList;
    actTest: TAction;
    btnTest: TButton;
    procedure actTestExecute(Sender: TObject);
  private
    FBlocker: TAEActionSCBlocker;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

var
  Form31: TForm31;

implementation

{$R *.dfm}

procedure TForm31.actTestExecute(Sender: TObject);
begin
  ShowMessage('');
end;

constructor TForm31.Create(AOwner: TComponent);
begin
  inherited;
  FBlocker := TAEActionSCBlocker.Create(Self, Self);
  FBlocker.RegisterShortCuts([VK_DELETE]);
end;

destructor TForm31.Destroy;
begin
  FBlocker.Free;
  inherited;
end;

end.

Автор: aktuba 7.5.2008, 14:17
вариант 4: использовать ActionManager. в нем больше возможностей.

Автор: Frees 7.5.2008, 14:36
Цитата(Rennigth @  7.5.2008,  12:31 Найти цитируемый пост)
запонимать и переопределять у них OnEnter/OnExit.

есть едиты которые у которых эти событи уже обрабатываются

Цитата(aktuba @  7.5.2008,  14:17 Найти цитируемый пост)
использовать ActionManager. в нем больше возможностей.

я правдо не пробовал но мне кажется он мою проблему не решит а доп функционал  ActionManager мне пока что не нужен

Автор: Rennigth 7.5.2008, 14:45
Цитата(Frees @  7.5.2008,  14:36 Найти цитируемый пост)
есть едиты которые у которых эти событи уже обрабатываются

Дык кто мешает их запоминать smile

Автор: Frees 7.5.2008, 14:49
Rennigth, Rrader,  попробую покуть то что вы предлжили

Добавлено через 2 минуты и 23 секунды
Rennigth, Есть едиты которым это событие ставится в динамике

Автор: Rennigth 7.5.2008, 14:52
Frees, поправил свой вариант, чтобы уже использованные OnEnter и OnExit тоже вызывались. Проморгал...  smile

Добавлено через 16 секунд
Код

unit uAEASCBlocker;

(* By Bifor Rennigth *)
(* ... *)

interface

uses
  Windows, SysUtils, Classes, Controls, ActnList, Forms, StdCtrls;

type
  PEditbleCtrl = ^TEditbleCtrl;
  TEditbleCtrl = record
    Control: TEdit;
    OldOnEnter: TNotifyEvent;
    OldOnExit: TNotifyEvent;
  end;

  PActionCtrl = ^TActionCtrl;
  TActionCtrl = record
    Control: TAction;
    SaveShortCut: TShortCut;
  end;

  TAEActionSCBlocker = class(TComponent)
  private
    FEditbleCtrls: TList;
    FActions: TList;
    FShortCuts: array of TShortCut;
    FTargerForm: TCustomForm;
  protected
    function FindEditbleCtrl(AObject: TObject): PEditbleCtrl;
    procedure EditbleCtrlEnterEvent(ASender: TObject);
    procedure EditbleCtrlExitEvent(ASender: TObject);

    procedure LoadEditbleCtrls;
    procedure ClearEditbleCtrls;

    procedure LoadActions;
    procedure ClearActions;
  public
    constructor Create(AOwner: TComponent;
      ATargetForm: TCustomForm); reintroduce; virtual;
    destructor Destroy; override;

    procedure RegisterShortCuts(AShortCuts: array of TShortCut);
  end;

implementation

{ TAEActionSCBlocker }

procedure TAEActionSCBlocker.ClearActions;
var
  i: Integer;
begin
  for I := 0 to FActions.Count - 1 do
  begin
    FreeMemory(FActions.Items[i]);
    FActions.Clear;
  end;
end;

procedure TAEActionSCBlocker.ClearEditbleCtrls;
var
  i: Integer;
begin
  for I := 0 to FEditbleCtrls.Count - 1 do
  begin
    FreeMemory(FEditbleCtrls.Items[i]);
    FEditbleCtrls.Clear;
  end;
end;

constructor TAEActionSCBlocker.Create(AOwner: TComponent;
  ATargetForm: TCustomForm);
begin
  inherited Create(AOwner);
  FTargerForm := ATargetForm;

  FEditbleCtrls := TList.Create;
  FActions := TList.Create;
end;

destructor TAEActionSCBlocker.Destroy;
begin
  ClearEditbleCtrls;
  ClearActions;
  FreeAndNil(FEditbleCtrls);
  FreeAndNil(FActions);
  inherited;
end;

procedure TAEActionSCBlocker.EditbleCtrlEnterEvent(ASender: TObject);
var
  i: Integer;
  lpAC: PActionCtrl;
  lpEC: PEditbleCtrl;
begin
  lpEC := FindEditbleCtrl(ASender);
  if Assigned(lpEC) and Assigned(lpEC^.OldOnEnter) then
    lpEC^.OldOnEnter(ASender);

  for i := 0 to FActions.Count - 1 do
  begin
    lpAC := FActions.Items[i];
    lpAC^.Control.ShortCut := 0;
  end;
end;

procedure TAEActionSCBlocker.EditbleCtrlExitEvent(ASender: TObject);
var
  i: Integer;
  lpAC: PActionCtrl;
  lpEC: PEditbleCtrl;
begin
  lpEC := FindEditbleCtrl(ASender);
  if Assigned(lpEC) and Assigned(lpEC^.OldOnExit) then
    lpEC^.OldOnExit(ASender);

  for i := 0 to FActions.Count - 1 do
  begin
    lpAC := FActions.Items[i];
    lpAC^.Control.ShortCut := lpAC^.SaveShortCut;
  end;
end;

function TAEActionSCBlocker.FindEditbleCtrl(AObject: TObject): PEditbleCtrl;
var
  i: Integer;
begin
  Result := nil;
  if Assigned(AObject) then
  begin
    for I := 0 to FEditbleCtrls.Count - 1 do
      if TObject(FEditbleCtrls.Items[i]) = AObject then
      begin
        Result := PEditbleCtrl(FEditbleCtrls.Items[i]);
        Break;
      end;
  end;
end;

procedure TAEActionSCBlocker.LoadEditbleCtrls;
var
  i: Integer;
  lpEC: PEditbleCtrl;
  lEdit: TEdit;
begin
  ClearEditbleCtrls;
  if Assigned(FTargerForm) then
  begin
    for i := 0 to FTargerForm.ComponentCount - 1 do
      if (FTargerForm.Components[i] is TEdit) then
      begin
        lEdit := TEdit(FTargerForm.Components[i]);
        if Assigned(lEdit) then
        begin
          lpEC := GetMemory(SizeOF(TEditbleCtrl));
          lpEC^.Control := lEdit;
          lpEC^.OldOnEnter := lEdit.OnEnter;
          lpEC^.OldOnExit := lEdit.OnExit;
          lEdit.OnEnter := EditbleCtrlEnterEvent;
          lEdit.OnExit := EditbleCtrlExitEvent;
          FEditbleCtrls.Add(lpEC);
        end;
      end;
  end;
end;

procedure TAEActionSCBlocker.LoadActions;

  function ExistSC(ASC: TShortCut): Boolean;
  var
    i: Integer;
  begin
    Result := False;
    for i := Low(FShortCuts) to High(FShortCuts) do
      if FShortCuts[i] = ASC then
      begin
        Result := True;
        Break;
      end;
  end;

var
  lAction: TAction;
  lpAC: PActionCtrl;
  i: Integer;
begin
  ClearActions;
  if Assigned(FTargerForm) then
  begin
    for i := 0 to FTargerForm.ComponentCount - 1 do
      if (FTargerForm.Components[i] is TAction) then
      begin
        lAction := TAction(FTargerForm.Components[i]);
        if Assigned(lAction) and ExistSC(lAction.ShortCut) then
        begin
          lpAC := GetMemory(SizeOF(TActionCtrl));
          lpAC^.Control := lAction;
          lpAC^.SaveShortCut := lAction.ShortCut;
          FActions.Add(lpAC);
        end;
      end;
  end;
end;

procedure TAEActionSCBlocker.RegisterShortCuts(AShortCuts: array of TShortCut);
var
  i: Integer;
begin
  SetLength(FShortCuts, Length(AShortCuts));
  for i := Low(AShortCuts) to High(AShortCuts) do
    FShortCuts[i] := AShortCuts[i];

  LoadEditbleCtrls;
  LoadActions;
end;

end.



Добавлено через 2 минуты и 35 секунд
Цитата(Frees @  7.5.2008,  14:49 Найти цитируемый пост)
Rennigth, Есть едиты которым это событие ставится в динамике 

Вызывай RegisterShortCuts вызывай после присвоения своих событий.

Автор: Frees 7.5.2008, 15:09
сейчас вот нашли пока такое решение, идея не моя колега придумал

Код

SaveActionList: TActionList;
function GetShortCut_Disabled: Boolean;
procedure SetShortCutDisabled(const Value: Boolean);
property actlShortCutDisabled: Boolean read GetShortCut_Disabled write SetShortCut_Disabled;

....
procedure TForm1.SetShortCutDisabled(const Value: Boolean);
begin
  if Value = (ActionList1.Owner = nil) then exit;
  if Value then
    RemoveComponent(ActionList1) else
    InsertComponent(ActionList1);
end;

function TForm1.GetShortCutDisabled: Boolean;
begin
  Result := ActionList1.Owner = nil;
end;


в событий OnUpdate у ActionList написатл

Код

procedure TForm1.ActionList1Update(Action: TBasicAction;
  var Handled: Boolean);
begin
   actlShortCutDisabled := ActiveControl is TEdit;
end;


теперь получается что если мы зашли в Едит то ActionList1 перестает пренадлежать форме и ей не прейдут сообщения о нажатий кнопок на клавиатуре но в то же время сами акции будут жить и работать 

как думаете нормальное решение?

Автор: Rennigth 7.5.2008, 15:13
Frees, Ну если подходит почемубы нет, только не забывай того что если ты отвязываешь ActionList от Owner то при закрытии(дестрое) формы ActionList не уничножиться автоматом, и получишь меморилик.

Автор: Rrader 7.5.2008, 15:26
Frees, чем мой вариант не подходит? smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)