views:

141

answers:

1

Sometimes a keystroke on a form can have different recipents, depending on the state of the application. See the following sample:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
  private
    ListView1: TListView;
    ButtonOK: TBitBtn;
    ButtonCancel: TBitBtn;
    procedure ButtonClick(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

constructor TForm1.Create(AOwner: TComponent);
begin
  inherited CreateNew(AOwner);
  ClientWidth := 300;
  ClientHeight := 240;

  ListView1 := TListView.Create(Self);
  ListView1.Name := 'ListView1';
  ListView1.Parent := Self;
  ListView1.Height := 200;
  ListView1.Align := alTop;
  ListView1.AddItem('aaaaa', nil);
  ListView1.AddItem('bbbbb', nil);
  ListView1.AddItem('ccccc', nil);

  ButtonOK := TBitBtn.Create(Self);
  ButtonOK.Parent := Self;
  ButtonOK.Left := 8;
  ButtonOK.Top := 208;
  ButtonOK.Kind := bkOK;
  ButtonOK.OnClick := ButtonClick;

  ButtonCancel := TBitBtn.Create(Self);
  ButtonCancel.Parent := Self;
  ButtonCancel.Left := 90;
  ButtonCancel.Top := 208;
  ButtonCancel.Kind := bkCancel;
  ButtonCancel.OnClick := ButtonClick;
end;

procedure TForm1.ButtonClick(Sender: TObject);
begin
  ShowMessage((Sender as TBitBtn).Caption);
  Application.Terminate;
end;

end.

(To run this, create a standard VCL app and replace the contents of Unit1.pas with the above.)

If one starts the app and presses Enter or Esc, the appropriate button are "clicked". However when one starts editing the listview (by clicking one and a half time on an item) Enter and Esc should accept or cancel the editing which they don't - they still "click" the buttons.

Similar scenarios exist if one has actions with shortcuts F2 or F4 on a form containing a cxGrid, which by default uses these shortcuts to start edit mode or drop down combobox editors.

Do you have an idea how I can continue do use the comfort of TButton.Default/Cancel and actions, while not having to reimplement the key handling of all the components I use?

+2  A: 

I guess you have bad luck with the controls you use. TMemo handles it correctly, but indeed an editable TListView does not. The problem seems to originate from win32 rather then the VCL wrapper around it. So it eems that you have to reimplement the key handling on TListView if you do not like its current behavior.

procedure WMGetDlgCode(var Message: TMessage); message WM_GETDLGCODE;

procedure TMyListView.WMGetDlgCode(var Message: TMessage);
begin
  inherited;

  if IsEditing then
    Message.Result := Message.Result or DLGC_WANTALLKEYS;
end;

Since all controls behave different and it is the controls themselves that decide which keys they are interested in, I can't see how you could fix it without having to change unwanted behavior.

Lars Truijens
It should be also possible to do the same without making a descendant class, like here: http://stackoverflow.com/questions/2363456/how-do-i-catch-a-vk-tab-key-in-my-tedit-control-and-not-let-it-lose-the-focus
Serg