Zax
Zax

Reputation: 491

Create floating TToolbar at run-time without flicker

I'm attempting to create a custom TToolbar at run-time that floats over the form (below the control it is associated with).

My issue is that the process of floating and positioning the toolbar at creation creates a hideous flicker where it is initially drawn at the top-left of the monitor before being moved to my desired position on the form.

I cannot find a way to avoid this. Is there a way?

procedure TMainForm.Button3Click(Sender: TObject);
var
  newToolbar : TToolbar;
  newButton : TToolButton;
begin
  newToolbar := TToolbar.Create(Self);

  newToolbar.Visible := False;

  newToolbar.ManualFloat( Rect( 0, 0, newToolbar.Width, newToolbar.Height ));

  newToolbar.Parent := Self;

  newToolbar.left := 100;
  newToolbar.Top  := 100;

  newToolbar.ShowCaptions := True;

  newButton := TToolButton.Create(Self);
  newButton.Parent := newToolbar;
  newButton.Caption := 'Test';

  newToolbar.Visible := True;
end;

References: - Create TToolbutton runtime - toolbutton with action created at runtime - Delphi - Create a custom TToolBar component

Upvotes: 1

Views: 416

Answers (2)

Tom Brunberg
Tom Brunberg

Reputation: 21033

I am a little puzzled with your solution, so I provide my two takes on the subject. Specifically I don't understand why you are using ManualFloat() and few lines later set the parent of the toolbar, which makes it non-floating.

Here is a solution for a floating toolbar, using ManualFloat(). The toolbar is floating above the form in its own temporary TCustomDockForm, at the given location.

The record needed by ManualFloat() is setup for the final location, thus no flicker in the wrong place, and the control is immediately correctly positioned.

procedure TForm1.Button3Click(Sender: TObject);
var
  newToolbar : TToolbar;
  newButton : TToolButton;
  p: TPoint;
begin
  newToolbar := TToolbar.Create(Self);

  // calculate position in screen coordinates for the floating toolbar
  p := ClientOrigin;
  p.Offset(100, 100);
  // and make it floating in final position
  newToolbar.ManualFloat( Rect(p.X, p.Y, p.X+NewToolbar.Width, p.Y+newToolbar.Height) );

  newToolbar.Visible := False; // really needed ?

  // Then create the toolbar buttons
  newToolbar.ShowCaptions := True;

  newButton := TToolButton.Create(self);
  newButton.Parent := newToolbar;
  newButton.Caption := 'Test';

  newToolbar.Visible := True;
end;

However, since you actually seem to want a non-floating toolbar, that is just located anywhere you like on the form (and not in the default top of the form), a better solution is to skip the ManualFloat() altogether and just set the Align property of the toolbar to alNone. This enables it to be moved anywhere on the parent form.

procedure TForm1.Button4Click(Sender: TObject);
var
  newToolbar : TToolbar;
  newButton : TToolButton;
begin
  newToolbar := TToolbar.Create(Self);
  newToolbar.Align := alNone; // constructor sets it to alTop

  newToolbar.Visible := False; // really needed ?

  newToolbar.Parent := Self;
  newToolbar.Left := 100;
  newToolbar.Top := 200;

  newToolbar.ShowCaptions := True;

  newButton := TToolButton.Create(self);
  newButton.Parent := newToolbar;
  newButton.Caption := 'Test';

  newToolbar.Visible := True; //
end;

This gives you the same appearance as your own code, but omits the ManualFloat().

Finally, an image to show the appearances:

enter image description here

The bottom toolbar is created with Button4Click()

Upvotes: 1

Zax
Zax

Reputation: 491

Thanks @TomBrunberg for your suggestion.

What was needed to make it position over the form without any pre-drawing:

  1. Position it off-screen when ManualFloat is called
  2. Set Visible to false after call to ManualFloat (because ManualFloat sets it true)

Revised code:

procedure TMainForm.Button3Click(Sender: TObject);
var
  newToolbar : TToolbar;
  newButton : TToolButton;
begin
  newToolbar := TToolbar.Create(Self);

  // Float with off-screen position
  newToolbar.ManualFloat( Rect( 0, -200, newToolbar.Width, newToolbar.Height - 200 ));

  // Must hide after ManualFloat call, as it resets Visible to true
  newToolbar.Visible := False;

  // Set parent so we can add buttons, sets props, etc.
  newToolbar.Parent := Self;

  // Move to desired position over form
  newToolbar.left := 100;
  newToolbar.Top  := 100;

  // Add our button content...
  newToolbar.ShowCaptions := True;

  newButton := TToolButton.Create(Self);
  newButton.Parent := newToolbar;
  newButton.Caption := 'Test';

  // Now we can show it
  newToolbar.Visible := True;
end;

Upvotes: 0

Related Questions