I use a TMemo
in TScrollBox
to show some text, and a TLabel
on top as a header info. Sometimes memo is wider than scroll box and of course Horizontal scroll bar
can be used to scroll left and right to see text in memo.
I want to have a label as a header always centered to scroll box visible area. I can do this by setting Label1.Left:= (Scrollbox1.Width div 2) - (Label1.Width div 2);
and it works but it kind of flickers, shakes when scrolling back and forth. Memo moves smoothly, label doesn't.
Here is unit:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TScrollBox=Class(VCL.Forms.TScrollBox)
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
private
FOnScrollHorz: TNotifyEvent;
public
Property OnScrollHorz:TNotifyEvent read FOnScrollHorz Write FonScrollHorz;
End;
TForm1 = class(TForm)
ScrollBox1: TScrollBox;
Label1: TLabel;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure ScrollBox1Resize(Sender: TObject);
private
procedure MyScrollHorz(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TScrollBox.WMHScroll(var Message: TWMHScroll);
begin
inherited;
if Assigned(FOnScrollHorz) then FOnScrollHorz(Self);
end;
procedure TForm1.MyScrollHorz(Sender: TObject);
begin
Label1.Left:= (Scrollbox1.Width div 2) - (Label1.Width div 2);
end;
procedure TForm1.ScrollBox1Resize(Sender: TObject);
begin
Label1.Left:= (Scrollbox1.Width div 2) - (Label1.Width div 2);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ScrollBox1.OnScrollHorz := MyScrollHorz;
end;
end.
and dfm:
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 212
ClientWidth = 458
Color = clBtnFace
DoubleBuffered = True
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object ScrollBox1: TScrollBox
Left = 0
Top = 0
Width = 458
Height = 212
HorzScrollBar.Smooth = True
HorzScrollBar.Tracking = True
Align = alClient
BiDiMode = bdLeftToRight
DoubleBuffered = True
ParentBiDiMode = False
ParentDoubleBuffered = False
TabOrder = 0
OnResize = ScrollBox1Resize
ExplicitHeight = 337
object Label1: TLabel
Left = 192
Top = 30
Width = 69
Height = 13
BiDiMode = bdLeftToRight
Caption = 'Details header'
ParentBiDiMode = False
end
object Memo1: TMemo
Left = 24
Top = 70
Width = 700
Height = 89
Lines.Strings = (
'Details...')
TabOrder = 0
end
end
end
I tried using DoubleBuffered
but doesn't help.
Any suggestions how to make Label1 move without flickering/shaking, as smooth as Memo1 does when scrolling?
EDIT:
The design will eventually be that I have 3 or scrollboxes on form and each one contain up to 3 memos with header. And scrolling needs to be by scrollbox as all memos in same scroll box need to be scrolled at the same time. That means I do not see how it would work with putting label on form or panel and then on form, outside scrollboxes:
EDIT 2:
The answers below do provide good solutions, but they do make necessary to place the Labels
, that are centered, out of the Scrollbox
and put on the Form
itself. And then move either by Scrollbox's
scroll bars
or by scroll bars
directly on Form
. This does get desired affect, but it adds a little inconvenience with Labels
not being part of Scrollbox
, anymore.
-" Memo moves smoothly, label doesn't."
That's because you're trying to prevent it from moving. Detach your OnScrollHorz
handler and the label will move smoothly. But that's not what you want, it will not be centered to the form any more.
The problem is, during the inherited
call (WM_HSCROLL
), the label moves along with the memo. After the default handling, you relocate the label, hence the flicker.
You can expose an additional event handler that will fire before default scrolling (OnBeforeHorzScroll), and hide the label when it fires. While smoothly centered, it will cause a different kind of flicker where the label momentarily disappears. Still may not be satisfactory.
The solution is to use a control that is parented to the form, a sibling to the scroll box. You can't do that with a TLabel
as it is a graphic control, but you can use TStaticText
. The "structure pane" of the IDE may come handy if the static accidentally goes behind the scroll box at design time.