0

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?

Jasper
  • 2,166
  • 4
  • 30
  • 50
Uli Gerhardt
  • 13,748
  • 1
  • 45
  • 83

1 Answers1

2

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
  • 42,837
  • 6
  • 126
  • 143
  • 1
    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 – kludg Mar 09 '10 at 19:31
  • Instead of creating your own TmyEdit or the like, simply use a line like `type TEdit = class(StdCtrls.TEdit) {...} end;` to add whatever you wish to TEdit, including new message handling for key presses. Everywhere on your form that you have a standard TEdit will now use your newly extended version. Alternately, add your new type declaration to a unit to use it from multiple forms. You will have to make sure that your unit is added to the uses clause AFTER all the units that contain the original controls (adding it ot the end is the easiest solution). – Jerry Gagnon Sep 14 '11 at 17:15