Jump to content
Sign in to follow this  
DavidRM

ShowModal and Measuring Text

Recommended Posts

I'm trying to create a simple modal-ish "show message".

Here is the ShowMessageForm:

type
  TShowMessageForm = class(TW3Form)
  private
    {$I 'ShowMessageForm:intf'}
    FMessagePanel: TW3Panel;
    FMessageLabel: TW3Label;
    //
    FMessageText: string;
  protected
    procedure InitializeForm; override;
    procedure InitializeObject; override;
    procedure Resize; override;
  public
    procedure UpdateUI;
    property MessageText: string read FMessageText write FMessageText;
  end;

implementation

{ TShowMessageForm }

uses
  SmartCL.Fonts.Detector;

procedure TShowMessageForm.InitializeForm;
begin
  inherited;
  // this is a good place to initialize components
end;

procedure TShowMessageForm.InitializeObject;
begin
  inherited;
  {$I 'ShowMessageForm:impl'}
  FMessagePanel := TW3Panel.Create(Self);
  FMessagePanel.Name := 'MessagePanel';

  FMessageLabel := TW3Label.Create(FMessagePanel);
  FMessageLabel.AutoSize := False;
  FMessageLabel.Caption := '...';
end;
 
procedure TShowMessageForm.Resize;
begin
  inherited;
  UpdateUI;
end;
 
procedure TShowMessageForm.UpdateUI;
var
  tMetrics: TW3TextMetric;
  padding, margin, border: integer;
  panelWidth: integer;
begin
  var CSSHandle := TW3CustomBrowserAPI.GetComputedStylesFor(FMessagePanel.Handle);
  if (CSSHandle) then
  begin
    padding := w3_getPropertyAsInt(CSSHandle, 'paddingLeft');
    margin := w3_getPropertyAsInt(CSSHandle, 'marginLeft');
    border := w3_getPropertyAsInt(CSSHandle, 'borderLeft');
  end
  else
  begin
    padding := 2;
    margin := 2;
    border := 2;
  end;
  FMessageLabel.Caption := FMessageText;
  tMetrics := FMessageLabel.MeasureText(FMessageText);
  FMessageLabel.SetSize(tMetrics.tmWidth, Round(tMetrics.tmHeight * 1.5));
  panelWidth := FMessageLabel.Width + padding * 2 + margin * 2 + border * 2;
  FMessageLabel.Top := padding;
  FMessageLabel.Left := padding;
  FMessagePanel.Width := FMessageLabel.Width + padding * 4 + margin * 2 + border * 2;
  FMessagePanel.Height := FMessageLabel.Height + padding * 4 + margin * 2 + border * 2;
  FMessagePanel.SetBounds((ClientWidth - FMessagePanel.Width) div 2,
    (ClientHeight - FMessagePanel.Height) div 2,
    FMessagePanel.Width, FMessagePanel.Height);
end;

 

<snark>As you can see, I've learned my lesson and don't use the form designer or the so-called "layout manager", finding my life is much less painful just creating and arranging the components at run time.</snark>

Here is the ShowModal call:

procedure ShowMessage(const aMessage: string);
begin
  HideMessage;
  _MessageShowing := True;
  Application.ShowModal('ShowMessageForm', 'MessagePanel', '',
    lambda (dialog)
      TShowMessageForm(dialog).MessageText := aMessage;
      TShowMessageForm(dialog).UpdateUI;
    end,
    nil, nil);
end;

procedure HideMessage;
begin
  if _MessageShowing then
    Application.HideModal(mrCancel);
  _MessageShowing := False;
end;

 

The problem is the call to MeasureText in UpdateUI. It returns 0,0 for the width, height.

What am I missing?

-David

Share this post


Link to post
Share on other sites

the problem is in your UpdateUI proc

this works :

  FMessageLabel.Caption := FMessageText;
  tMetrics := FMessageLabel.MeasureText(FMessageText);
  FMessageLabel.SetSize(tMetrics.tmWidth, Round(tMetrics.tmHeight * 1.5));
  FMessageLabel.Top := padding;
  FMessageLabel.Left := padding;

  //FMessagePanel.Width := FMessageLabel.Width + padding * 4 + margin * 2 + border * 2;
  FMessagePanel.Width := tMetrics.tmWidth + padding * 4 + margin * 2 + border * 2;

  //FMessagePanel.Height := FMessageLabel.Height + padding * 4 + margin * 2 + border * 2;
  FMessagePanel.Height := tMetrics.tmHeight + padding * 4 + margin * 2 + border * 2;

  //FMessagePanel.SetBounds((ClientWidth - FMessagePanel.Width) div 2,
  //  (ClientHeight - FMessagePanel.Height) div 2,
  //  FMessagePanel.Width, FMessagePanel.Height);
  FMessagePanel.SetBounds((ClientWidth - FMessagePanel.Width) div 2,
    (ClientHeight - FMessagePanel.Height) div 2,
    tMetrics.tmWidth + padding * 4 + margin * 2 + border * 2, tMetrics.tmHeight + padding * 4 + margin * 2 + border * 2);

basically the SetSize call on line 3 results in FMessageLabel.Width and Height having a value of zero (wrong), however in the DOM both FMessageLabel.handle.style.width and height at that point show correct values (i.e. '124px'). My guess is that this has to do with dimensioning a child element before the parent is ready. Maybe @jarto could shine some light on that.

Anyway, dimensioning everything on the basis of a separate var (tMetrics) rather than on fluid parent / child element dimensions overcomes that problem. 
 

Share this post


Link to post
Share on other sites

That achieves *a* result but doesn't solve the problem.

The first time through, MeasureText returns an actual result (as in, not 0,0). That allows the panel's SetBounds to do something. But never again. From thereon, it only returns 0,0.

What's a decent workaround, do you figure?

-David

Share this post


Link to post
Share on other sites

In the ShowModal, the "init" callback is called before FormActivated is called. Thus, my calling UpdateUI in the init callback is... premature.

By adding an OnActivated event handler to the ShowMessageForm, which calls UpdateUI (removing the call from the init callback), my original code works as expected.

-David

Share this post


Link to post
Share on other sites

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
Sign in to follow this  

×