0

I have the following procedure in Delphi 6:

procedure TfrmUserCRUD.ShowErrorWithFocus(Message: string; FocusedField: TWinControl); begin try raise Exception.Create(Message); except on E : Exception do begin ShowMessage(E.Message); FocusedField.SetFocus; Abort; end; end; end; 

This is how I'm calling the function:

procedure TfrmUserCRUD.ValidateFields(); begin if not(chkListProducts.Checked) and (chkUsesProductValue.Checked) then ShowErrorWithFocus('You need to use the product list if you wanna use the product value.', chkListProducts); if (chkUsesProductValue.Checked) and (edtProductValue.KeyValue = nil) then ShowErrorWithFocus('The field "value of product" needs to be filled', edtProductValue); end; 

The objective of this procedure is to receive an error message and one of the fields from the form (CheckBox, Grid, Edit, etc) and whenever the function is called, it's supposed to show the message on screen with the error, then focus the field that it received like the system was highlighting it, like in those pictures:

image

image

I've been trying to use different methods so it could focus on the field, but if I use raise, the program loses the field variable, if I use Abort, the program doesn't do anything. I've also tried different ways of focusing the TField, like using Perform() and event updates, but it didn't worked as intended.

Any ideas of what I could do to resolve this problem?

5
  • 1
    I'm not very good in working with try..except statements. But I believe Catch Me If You Can and Catch Me If You Can - Part II blogs from Dalija Prasnikar might provide some explanation. Well the second blog also explains why relying on exceptions in modern LLVM compiler that Delphi uses for other platforms can be especially troublesome. Commented Dec 22, 2023 at 18:37
  • @SilverWarior Since the procedure needs to stop all process and focus on the field that it received, i was trying to use raise exception, but i would definetly change the command to abort or exit if it works Commented Dec 22, 2023 at 19:00
  • 2
    @SilverWarior My blog post is for LLVM backed compilers, not Windows ones. This is Delphi 6. No LLVM in sight here. Commented Dec 22, 2023 at 19:02
  • 2
    The code you have shown here works fine. The issue is in the code you are not showing. How do you call that ShowErrorWithFocus method? You may need to edit the question with minimal reproducible example The abort procedure in the exception handler is useless. See the documentation on what Abort does docwiki.embarcadero.com/Libraries/en/System.SysUtils.Abort Commented Dec 22, 2023 at 19:11
  • Im simplying sending one string with a message and one TWinControl component. Since it's suposed to work with 72 different messages, there's a lot of different components. The first one that I'm trying to use on a test is a TRxDBLookupCombo, but the main thing is, the fields are not focusing as I wanted it to Commented Dec 22, 2023 at 19:29

1 Answer 1

2

It makes absolutely no sense to raise an exception just to immediately catch it. You don't need the try..except at all:

procedure TfrmUserCRUD.ShowErrorWithFocus(Message: string; FocusedField: TWinControl); begin ShowMessage(Message); FocusedField.SetFocus; Abort; end; 

That being said, depending on the context in which ShowErrorWithFocus() is being called (which you did not show), it may not be valid/prudent to set focus right away (the OS/VCL can be really finicky about focus changes done out of order), so you may need to delay the focus until after the message queue has settled down first. PostMessage() will work fine for that, ie you could post a message to the Form, where you pass the FocusedField pointer in the message's lParam, and then the message handler can call SetFocus() on that object, eg:

const WM_APP_SETFOCUS = WM_APP + 1; procedure TfrmUserCRUD.ShowErrorWithFocus(Message: string; FocusedField: TWinControl); begin ShowMessage(Message); //FocusedField.SetFocus; PostMessage(Handle, WM_APP_SETFOCUS, 0, LPARAM(FocusedField)); end; procedure TfrmUserCRUD.WndProc(var Message: TMessage); begin if Message.Msg = WM_APP_SETFOCUS then TWinControl(Message.LParam).SetFocus else inherited; end; 

UPDATE:

You didn't show where you are calling ValidateFields() from, exactly. Calling SetFocus() while input focus is already in progress of being changed can cause UI problems. But since you mentioned in a comment that you are calling it in a Button OnClick event, then in that context you can simply SetFocus() the desired control first and then raise (and not catch!) the error message. Let the VCL display the error message to the user for you, and then the focused control will regain input focus after the error dialog is dismissed, eg:

procedure TfrmUserCRUD.SomeButtonClick(Sender: TObject); begin ValidateFields; end; procedure TfrmUserCRUD.ValidateFields; begin ... ShowErrorWithFocus(...); ... end; procedure TfrmUserCRUD.ShowErrorWithFocus(Message: string; FocusedField: TWinControl); begin FocusedField.SetFocus; raise Exception.Create(Message); end; 
Sign up to request clarification or add additional context in comments.

3 Comments

I've added an example of how I am calling the function, since the original code validades more than 75 fields. I have some questions regarding your answer: Is the procedure WndProc a regular procedure or it's a form event? If i add the PostMessage() to the code, will the program stop the next process? Since the button that calls that function is also the button that saves data into the database, the main objective of the procedure is to stop that from happening.
WndProc() is a virtual method of every TWinControl, so your Form can simply override it. And PostMessage() runs asynchronously, so it will NOT block subsequent code from continuing on after the message is posted.
Considering the solution you used on the update, this might work on a newer version of delphi, but in my project, the solution you made only focus the first field of the TabOrder(I'm using the build 6.240 bc the company can't update the system entirely).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.