Question

I have a custom component of type TSpeedButton that has two extra properties defined:

CommentHeading: string;
CommentText: string;

I set CommentHeading at design time.

When the speed button is pressed a memo is shown with a button beneath it for saving its contents. The procedure that handles this:

procedure CustomSpeedButton1Click(Sender: TObject);
begin
   Receiver := CustomSpeedButton1.Name; // possibly used to save the memo text back to this speedbuttons property after comments are submitted
   ViewComments(CustomSpeedButton1.CommentTitle,CustomSpeedButton1.CommentText);
end;

And the ViewComments procedure itself:

procedure ViewComments(comment_caption:string; comment_text:string);
begin
  label15.Hide; // label showing editing in progress, hidden until user begins typing
  Button1.Enabled     := false; // the button for saving the memo text, hidden until user begins typing
  CommentsBox.Visible := true; // pop up the comment box at the bottom of the form
  CommentsBox.Caption := 'Comments: ' + comment_caption;
  CommentsMemo.Text   := comment_text; // if there are existing comments assign them to memo
end;

The contents of the memo need to be assigned to the CommentText property of the custom SpeedButton.

What I was initially thinking was that I could pass the component name to a variable when the custom SpeedButton gets pressed and then retrieve that name when the save button on the memo is pressed and use it to assign the memo text to the speedbuttons CommentText property. But then I realized that to do this I'd have to use some kind of case..of statement that checked for each possible speedbutton name and then assign the memo value to its properties and this just seems ridiculously tedious.

Is there an easier way to assign the memo text to the speedbutton that opened the memo to begin with?

Was it helpful?

Solution

Ultimately, you're asking how to tell the ViewComments function which button's properties it's working with.

Do you understand what the Sender parameter is doing in the OnClick event? It's telling the event handler which object's event is being handled. It's serving precisely the role that you're looking to bring to the ViewComments function.

That's what Mason was getting at in his answer. Rather than pass all the property values, pass the object itself:

procedure ViewComments(CommentButton: TCustomSpeedButton);

Then call it from all your buttons' event handlers:

procedure TForm1.CustomSpeedButton1Click(Sender: TObject);
begin
  ViewComments(CustomSpeedButton1);
end;

procedure TForm1.CustomSpeedButton2Click(Sender: TObject);
begin
  ViewComments(CustomSpeedButton2);
end;

No strings, no case statements, no lookups.

That should answer your question, but you can do it even better. Remember what I said before about the Sender parameter? When someone clicks the first button, the Sender parameter of that OnClick handler will be the button, so we can rewrite the first event handler like this:

procedure TForm1.CustomSpeedButton1Click(Sender: TObject);
begin
  ViewComments(Sender as TCustomSpeedButton);
end;

And you can rewrite the second event handler like this:

procedure TForm1.CustomSpeedButton2Click(Sender: TObject);
begin
  ViewComments(Sender as TCustomSpeedButton);
end;

Hmm. They're the same. Having two identical functions is wasteful, so get rid of one and rename the other so it doesn't sound button-specific:

procedure TForm1.CommentButtonClick(Sender: TObject);
begin
  ViewComments(Sender as TCustomSpeedButton);
end;

Then set the OnClick properties of both buttons to refer to that one event handler. You can't do that just by double-clicking the property in the Object Inspector. You'll need to either type the name yourself, choose it from the drop-down list, or assign the event property at run time:

CustomSpeedButton1.OnClick := CommentButtonClick;
CustomSpeedButton2.OnClick := CommentButtonClick;

I'd also like to encourage you to use more meaningful names for your controls. That Label15 is particularly egregious. How can you remember that the fifteenth label is the one that indicates that editing is in progress? Call it EditInProgressLabel, for instance.

OTHER TIPS

Since you're already passing extra variables around, why not just pass the SpeedButton itself? Then you won't need to look up the reference.

A small change to your code should do the trick:

procedure TForm1.CustomSpeedButton1Click(Sender: TObject);
var
  btn: TCustomSpeedButton;
begin
   btn := Sender as TCustomSpeedButton;
   Receiver := btn.Name; 
   ViewComments(btn.CommentTitle, btn.CommentText);
end;

and after editing the comment:

procedure TForm1.StoreComments(comment: string);
var
  btn: TCustomSpeedButton;
begin
  btn := FindComponent(Receiver) as TCustomSpeedButton;
  btn.CommentText := comment;
end;

You can also memorize the button itself instead of just it's name.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top