Jump to content
PenelopeSkye

Set focus on dialog box button

Recommended Posts

I must have performed the search incorrectly because I did not find anything like this, so please point me to wherever I should be looking for answers to this question.  I am a newbie to both Delphi\pascal and the forum.

 

I have an app that brings up a search dialog box that leads to a result dialog box. 

When the result dialog box appears the focus is always on the last button pushed when last in the result dialog box.  

 

How do I get a specific button (the OK button) to always have focus no matter what button was last pushed?

 

I tried clicking on the button in the IDE (Delphi 10.3) to see if there was an  ActiveControl property in the object inspector but there is not.

 

How can I set focus to the OK button?

 

Thanks!

Share this post


Link to post

Set it in code:

ButtonOK.SetFocus;

The ActiveControl property is a property of the form but that is only applied when the form is first created and it sounds like you are only doing that once.

Share this post


Link to post
13 hours ago, PenelopeSkye said:

I must have performed the search incorrectly because I did not find anything like this, so please point me to wherever I should be looking for answers to this question.  I am a newbie to both Delphi\pascal and the forum.

 

I have an app that brings up a search dialog box that leads to a result dialog box. 

When the result dialog box appears the focus is always on the last button pushed when last in the result dialog box.  

 

How do I get a specific button (the OK button) to always have focus no matter what button was last pushed?

 

I tried clicking on the button in the IDE (Delphi 10.3) to see if there was an  ActiveControl property in the object inspector but there is not.

 

How can I set focus to the OK button?

 

Thanks!

In addition to Anders' reply: note that (VCL) buttons have two useful properties for dialog boxes:

  • Default - if you set that to true the button will "click" if the user hits the Enter or Return key, regardless of whether the button has focus or not.
  • Cancel - if that is set to true the ESC key will click the button. If the button's ModalResult is set to mrCancel that will close the dialog.

Share this post


Link to post

Thanks Anders, I had tried adding BitBtn1.SetFocus; in various places but that didn't work either.  Do you see a place for it in the code below?  I get to this code by selecting the OK button and then going to code.

 

And thank you PeterBelow, I am not even sure where to check Default or Cancel!  I am finding the IDE to be very confusing to find things!!!

 

 

unit ChooseResult;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, Wwdbigrd, Wwdbgrid, StdCtrls, Buttons, DB, ExtCtrls;

type
  TfChooseResult = class(TForm)
    wwDBGrid1: TwwDBGrid;
    Panel1: TPanel;
    dsResult: TDataSource;
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    procedure wwDBGrid1DblClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  fChooseResult: TfChooseResult;

implementation

{$R *.dfm}

procedure TfChooseResult.wwDBGrid1DblClick(Sender: TObject);
begin
  BitBtn1.click;
end;

end.

Share this post


Link to post

Not very confusing. But it provides many options. Luxury is paid for. Check the Arrange - by Category option in the Object Inspector. So it's clearer.

All events begin with the prefix On. So BitBtn1.OnClick.

Edited by Stano

Share this post


Link to post

Assuming that you're showing this form modally from somewhere else I would do it like this:

 

type
  TfChooseResult = class(TForm)
    wwDBGrid1: TwwDBGrid;
    Panel1: TPanel;
    dsResult: TDataSource;
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    procedure wwDBGrid1DblClick(Sender: TObject);
  private
  public
    function Execute: boolean;
  end;

var
  fChooseResult: TfChooseResult;

implementation

{$R *.dfm}

procedure TfChooseResult.wwDBGrid1DblClick(Sender: TObject);
begin
  BitBtn1.click;
end;

function TfChooseResult.Execute: boolean;
begin
  BitBtn1.SetFocus;
  Result := (ShowModal = mrOK);
end;

and then display the form like this:

begin
  ...do other stuff here...
  if (fChooseResult.Execute) then
  begin
   // User pressed OK
  end else
  begin
    // User closed dialog some other way
  end;
end;

And like Peter suggested, set the ModalResult property of the OK button to mrOK and the Default property of the same to True. If you add a Cancel button, set its ModalResult property to mrCancel and the Cancel property to True.

 

If you're not displaying the form modally, then you'll need to call SetFocus in the forms OnShow event handler instead. This of course assumes that the form isn't visible all the time.

 

44 minutes ago, PenelopeSkye said:

I am not even sure where to check Default or Cancel!  I am finding the IDE to be very confusing to find things!!!

image.png.ff5881694d00d0e89d9b32f6ad854b45.png

image.png.c8e1309611ad3c8457558e5d135b0f9e.png

Share this post


Link to post
2 minutes ago, Stano said:

All events begin with the prefix On. So BitBtn1.OnClick.

Nope. He's not calling the event handler. He's calling the Click method on the button - which emulates a click on the button.

Share this post


Link to post

I learned something new again. Well thank you.

Share this post


Link to post
23 hours ago, PenelopeSkye said:

procedure TfChooseResult.wwDBGrid1DblClick(Sender: TObject);
begin
  BitBtn1.click;
end;

Since you are working with Delphi now. There's a lot to learn about how get Delphi to speak to the Oracle or least a database.   One step is learning about TDataModule.  They're used in some examples.   The quote has a button click inside a double click which is inside a dialog.  How about enabling controls when needed.  Hiding buttons are bad, better to have disabled buttons as placeholders with hints what is needed first.  

 

Pat

 

 

 

   

 

 

Edited by Pat Foley
Removed example

Share this post


Link to post

Thank you everyone!  Apologies if I seem to be ignoring some posts\bits of information, I am trying to just keep my head above water!

 

I have located all the items in the object inspector (thank you!) and all the properties were already set to what was mentioned above.

I added the Execute code mentioned above but the instructions say to then display the form, but the code to call the form has already been written and is being called elsewhere.

I think one of my problems is that I don't understand where this form is being called from.  

 

The process is as follows:

1. While in the app (that has been created\finished long ago and is in constant use) the user hits the key press sequence 'ctrl-S' and a dialog box appears with a text box

2. The user types in a number to search on, and presses OK.

             This is the point where the dialog box with the OK button requiring focus is being called.

 

Should I be looking for the code from the previous dialog box where the user types the search text in order to set focus or should I stick with the code I already posted?

 

Again it is probably very annoying to deal with newbies, please hang in there, I am studying as I go and it is being very helpful!!! Thank you!!!

 

 

 

 

 

Share this post


Link to post
4 minutes ago, PenelopeSkye said:

Should I be looking for the code from the previous dialog box where the user types the search text in order to set focus

Yes

You can use Search->Find in files (Ctrl+Shift+F) to locate the place. Search for " fChooseResult .Show".

 

6 minutes ago, PenelopeSkye said:

Again it is probably very annoying to deal with newbies, please hang in there, I am studying as I go and it is being very helpful!!! Thank you!!!

No problem. Happy to help.

Share this post


Link to post

This is the code where the user puts in the search text (a stock number) and if it is valid the dialog box shows up with the OK button requiring focus!

 

I tried inserting fChooseResult.showModal=mrCancel then fChooseResult.BitBtn1.SetFocus; as well as several other things and it either didn't work or it gave an error message: "Cannot focus a disabled or invisible window"

 

Ideas?  Thank you!!!

procedure TfDesignMaster.FindStockNumber1Click(Sender: TObject);
var
  stocksearch: string;
  did: string;
begin
  stocksearch:=inputbox('Search','Enter Stock Number','');
  //find Stock Number
  if stocksearch<>'' then begin
    did:='';
    //dm.tb_design_master.locate('jmc_stock_num',stocksearch,[]);

    //execute query for Stock #
    if dm.qStockNum.active then dm.qStockNum.close;
    dm.qStockNum.Parameters[0].value:=stocksearch;
    dm.qStockNum.open;
    if dm.qStockNum.recordcount>1 then begin
      //Show list of designs
      fChooseResult.dsResult.DataSet:=dm.qStockNum;
      if fChooseResult.showModal=mrOK then
        did:=dm.qStockNum.fieldbyname('design_id').asstring;
      fChooseResult.dsResult.DataSet:=nil;
    end else
      did:=dm.qStockNum.fieldbyname('design_id').asstring;

    if dm.qStockNum.recordcount=0 then
      messagedlg('Not found',mtError,[mbOK],0)
    else
      datagoto(did);
    //dm.tb_design_master.locate('design_id',did,[]);

    dm.qStockNum.close;
  end;
end;

 

 

 

 

 

Edited by Sherlock
Wrapped code in code tags.

Share this post


Link to post

an error message: "Cannot focus a disabled or invisible window" clearly states what this is about. You need to make sure that the window where you want to target a component is visible and accessible. You don't have one of them (or both).
Only debugging (with Break point) will help here. 

Share this post


Link to post

Replace this:

  if fChooseResult.showModal=mrOK then
    did:=dm.qStockNum.fieldbyname('design_id').asstring;

with:

  if fChooseResult.Execute then
    did := dm.qStockNum.FieldByName('design_id').AsString;

 

and then modify the TfChooseResult form like this:

const
  MSG_AFTERSHOW = WM_USER;

type
  TfChooseResult = class(TForm)
    ...
  protected
    procedure MsgAfterShow(var Msg: TMessage); message MSG_AFTERSHOW;
  public
    function Execute: boolean;
  end;

implementation

{$R *.dfm}

procedure TfChooseResult.MsgAfterShow(var Msg: TMessage);
begin
  BitBtn1.SetFocus;
end;

function TfChooseResult.Execute: boolean;
begin
  PostMessage(Handle, MSG_AFTERSHOW, 0, 0);
  Result := (ShowModal = mrOK);
end;

Edit: Maybe I should explain what's going on.

  1. The PostMessage puts a custom message into the form's message queue.
  2. When ShowModal is called the form is displayed and the modal loop pumps the message queue [*].
  3. The message pump grabs the custom message from the queue and calls the form's message handler (the MsgAfterShow method).
  4. MsgAfterShow focuses the button.

 

[*] Pumping the message queue means that the code loops, reading one message at a time from the message queue and dispatching these messages to the "message handlers". It's "a bit" more complicated than that but hopefully you get the overall picture.

Edited by Anders Melander

Share this post


Link to post

Hi Anders, this produced a a few errors that I am trying to figure out without bugging you with each one 🙂.  

Share this post


Link to post

I finally had to go to a developer in my company.  The issue was that the modal dialog box was being created and destroyed in the same step.  She had me create a procedure that creates the modal dialog box, set the focus, then close it and it worked.  Thanks Anders!

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×