4

I was just about to replace a TEdit + TButton combination with one TButtonedEdit control but when I tried to test it, I found no way to "press" the (right) button using the keyboard.

I tried Alt+Enter, Alt+Down, Alt+Right, the same keys with Ctrl and a few more key combinations but none of them worked. The VCL sources did not shed any light on this issue either (but hey "professional programmers don't look at the VCL sources" anyway)

Am I missing something?

This is with Delphi 2010 on a Windows XP box, the TButtonedEdit component was introduced in Delphi 2009 IIRC.

Note: I have accepted Andreas Rejbrand's answer because it answers the question. But I have also added my own answer for the benefit of those who might be interested in what I actually implemented.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
  • 4
    Professional programmers study the RTL/VCL source code extensively. – Andreas Rejbrand Feb 13 '11 at 11:32
  • 1
    @Andreas: Yes, I know, I certainly do. This was just referring to Embarcadero's comment on not including the RTL/VCL sources with the new entry level Delphi version. – dummzeuch Feb 13 '11 at 12:48

3 Answers3

4

No, there is no such keyboard shortcut, partly (maybe) because of the ambiguity in which button (the left or right button) the keyboard shortcut should execute.

I always do it like this:

procedure TForm1.ButtonedEdit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (Key = VK_RETURN) and (ssCtrl in Shift) then
    ButtonedEdit1RightButtonClick(Sender);
end;

The Ctrl+Enter shortcut is very natural if the button displays a modal dialog (which helps the user fill the edit box), or something similar. If it instead executes a procedure taking the edit text as argument (e.g., an address bar or a search box), Enter alone is more suitable. If the button is a clear button (that clears the edit box), then Escape might be the best shortcut, or possibly no shortcut at all (and then it is a good thing that there is no default shortcut).

The fact that the suitable shortcut depends on the situation also suggests that there should be no default shortcut, I think.

By the way, don't forget to make the TButtonedEdit DoubleBuffered, for otherwise it will flicker way too much.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Of course using `DoubleBuffered` runs the risk of resulting in broken painting in certain themes (e.g. Windows Basic). And where's the flicker coming from, I don't see it. – David Heffernan Feb 13 '11 at 11:46
  • 1
    @David: Move the mouse rapidly across the control (so that at times the mouse is above the control, and at other times outside the control). The bitmap will flicker. – Andreas Rejbrand Feb 13 '11 at 11:48
  • I could barely detect that. I'd personally elect to have that behaviour rather than mis-draw in other themes. Of course this control may not be one that mis-draws but I've had my fill of the `DoubleBuffered` property and its strangeness when DWM is not enabled. – David Heffernan Feb 13 '11 at 11:50
  • Yes, this allergy is quite apparent! I don't like flickering either but I don't think you need to apply double buffering everywhere to avoid it. – David Heffernan Feb 13 '11 at 11:52
3

I have now created an interposer class that looks like this:

interface
{...}
type
  TdzButtonedEdit = class(TButtonedEdit)
  protected
    procedure KeyDown(var _Key: Word; _Shift: TShiftState); override;
  public
    procedure Loaded; override;
  end;

{...}

implementation

{...}

{ TdzButtonedEdit }

procedure TdzButtonedEdit.KeyDown(var _Key: Word; _Shift: TShiftState);
begin
  inherited;
  if (_Key = VK_RETURN) and (ssCtrl in _Shift) then
    if Assigned(OnRightButtonClick) then
      OnRightButtonClick(Self);
end;

procedure TdzButtonedEdit.Loaded;
begin
  inherited;
  if RightButton.Visible and (RightButton.Hint = '') then begin
    RightButton.Hint := _('Ctrl+Return to ''click'' right button.');
    ShowHint := true;
  end;
end;

which I use in the form by declaring:

TButtonedEdit = class(TdzButtonedEdit)
end;

before the form's class declaration.

If I can ever be bothered I'll make it a full blown custom component.

btw: Why did Embarcadero make TEditButton.TGlyph strict private? That's very inconvenient because normally I would have called RightButton.Glyph.Click rather than OnRightButtonClick.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
  • 1
    I think you need an `if Assigned(OnRightButtonClick) then` in your `KeyDown`. A lot of things are private in the RTL/VCL; I remember seeing a thread with a sensible discussion on pros and cons, but can't find it right now. – Jeroen Wiert Pluimers Feb 13 '11 at 16:24
0

Given that there is no way to pass the input focus to these embedded buttons, and given that they display glyphs, how could there be keyboard access? How would the user discover it?

On a modal dialog you can press enter and so long as the focus control is not a button, then the default button is pressed and the form closes. That is part of the platform UI standard. Similarly for escape and cancel. Many other controls have standard keyboard access (lists, drop downs, edits etc.)

This is not a standard control and so it would be wrong to impose some default keyboard access beyond what is expected in an edit control. It's fine for the designer to add access because they know what is reasonable on their form, but the VCL designers got it right by not including a default behaviour that would apply to every instance of this control..

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Tooltips can make the keyboard shortcuts discoverable. The IE8 address bar does this, for example. – Giel Feb 13 '11 at 12:34
  • I am used to the TJvDirectoryEdit and TJvFilenameEdit controls which look similar and use Alt-Down as a shortcut. Also, I could probably add a hint to the control (which on the other hand only displays when the mouse hovers above the control...) – dummzeuch Feb 13 '11 at 12:50
  • 1
    @dummzeuch: Alt+Down is the shortcut to drop down the drop-down list in a combo box. Using the same shortcut to trigger the clicking action of a button sounds unwise. I definitely wouldn't do that. – Andreas Rejbrand Feb 13 '11 at 13:25
  • @Andreas indeed, this is my point. Since one of these buttoned edits can have a button that could do *anything*, a default is a bad idea. For a drop down list, it always does the same thing, and the keyboard access is fine. – David Heffernan Feb 13 '11 at 13:26
  • 1
    @Andreas, @David - I think clicking the button should pop some dialog, other than that I disagree. A combo box is characteristically very similar to a buttoned edit, it has an edit and a button, so Alt+Down is an expected shortcut for pressing the button at the right side of an edit. The IDE has it - like the 'Font' property in the OI. Even the VCL has implemented it this way, like the pick-list of a column for a DBGrid. – Sertac Akyuz Feb 13 '11 at 13:42
  • 1
    @Sertac: Alt+**Down** drops **down** the drop-**down** list in a combo box. That is a very special kind of button, not at all like the buttons found in `TButtonedEdits`, in web browsers, file browsers, etc. I can think of three main applications, and three corresponding shortcuts, as I wrote in my answer (modal dialog -> Ctrl+Enter, like the object inspector; execute sth -> Enter, like a web browser's address bar or search bar; and clear the edit box -> Escape). – Andreas Rejbrand Feb 13 '11 at 13:46
  • 1
    @Andreas - I have no objection to 'Ctrl+Enter', but I still think that showing the drop down list or showing a dialog is not all that different. – Sertac Akyuz Feb 13 '11 at 13:53