Моя проблема связана с настраиваемым элементом управления, который я пытаюсь разработать, и я не могу понять, как правильно реализовать полосы прокрутки. В основных моментах я остановлюсь на том, что я пытаюсь сделать, чтобы облегчить понимание вопроса.Как заставить полосы прокрутки хорошо играть в пользовательском элементе управления?
- Управление будет простым средством просмотра изображений, изображение будет нарисовано в центре элемента управления.
- Управление осуществляется от
TScrollingWinControl
. - У меня есть опубликованное свойство
FImage
, которое является классомTPicture
, что позволяет загрузить изображение в элемент управления. - Не будет дочерних элементов управления, поскольку я буду рисовать
FImage
на контроле. - В конструкторе я написал
AutoScroll := False;
- Я перехватил
WM_SIZE
сообщений и здесь я могу определить смещения для центрированияFImage
до середины контроля, а также попытаться пересчитать диапазоны прокрутки. - Наконец, я переопределяю метод Paint, чтобы нарисовать центрированный
FImage
на элемент управления.
До сих пор так хорошо изображение можно загружать при проектировании или во время выполнения и отображается в центре элемента управления. Теперь я не могу понять, как правильно настроить прокрутку.
Вот соответствующий код до сих пор:
unit uImageViewer;
interface
uses
Winapi.Windows,
Winapi.Messages,
System.Classes,
Vcl.Controls,
Vcl.Forms,
Vcl.Graphics;
type
TMyImageViewer = class(TScrollingWinControl)
private
FCanvas: TCanvas;
FImage: TPicture;
FOffsetX: Integer; // center position in control for FImage
FOffsetY: Integer; // center position in control for FImage
procedure SetImage(const Value: TPicture);
private
procedure CalculateOffsets; //recalculates the center for FImage
procedure CalculateScrollRanges;
protected
procedure Loaded; override;
procedure PaintControl;
procedure PaintWindow(DC: HDC); override;
procedure WMEraseBkGnd(var Message: TMessage); message WM_ERASEBKGND;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure WMSize(var Message: TMessage); message WM_SIZE;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Canvas: TCanvas read FCanvas;
published
property Align;
property Color;
property Image: TPicture read FImage write SetImage;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Standard', [TMyImageViewer]);
end;
constructor TMyImageViewer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCanvas := TControlCanvas.Create;
TControlCanvas(FCanvas).Control:=Self;
FImage := TPicture.Create;
Self.AutoSize := False; //?
AutoScroll := False;
ControlStyle := ControlStyle + [csOpaque];
end;
destructor TMyImageViewer.Destroy;
begin
FCanvas.Free;
FImage.Free;
inherited Destroy;
end;
procedure TMyImageViewer.Loaded;
begin
inherited Loaded;
CalculateOffsets;
CalculateScrollRanges;
end;
procedure TMyImageViewer.PaintControl;
procedure DrawClientBackground; // paints the control color
begin
Canvas.Brush.Color := Color;
Canvas.Brush.Style := bsSolid;
Canvas.FillRect(ClientRect);
end;
begin
// if not (csDesigning in ComponentState) then
// begin
DrawClientBackground;
// draw the FImage
if (FImage <> nil) and (FImage.Graphic <> nil) then
begin
Canvas.Draw(FOffsetX, FOffsetY, FImage.Graphic);
end;
// end;
end;
procedure TMyImageViewer.PaintWindow(DC: HDC);
begin
FCanvas.Handle := DC;
try
PaintControl;
finally
FCanvas.Handle := 0;
end;
end;
procedure TMyImageViewer.SetImage(const Value: TPicture);
begin
if Value <> FImage then
begin
FImage.Assign(Value);
CalculateOffsets;
CalculateScrollRanges;
Invalidate;
end;
end;
procedure TMyImageViewer.CalculateOffsets;
begin
// for centering FImage in the middle of the control
if FImage.Graphic <> nil then
begin
FOffsetX := (Width - FImage.Width) div 2;
FOffsetY := (Height - FImage.Height) div 2;
end;
end;
procedure TMyImageViewer.CalculateScrollRanges;
begin
HorzScrollBar.Range:= FOffsetX + FImage.Width + FOffsetX;
VertScrollBar.Range:= FOffsetY + FImage.Height + FOffsetY;
end;
procedure TMyImageViewer.WMEraseBkGnd(var Message: TMessage);
begin
Message.Result := 1;
end;
procedure TMyImageViewer.WMPaint(var Message: TWMPaint);
begin
PaintHandler(Message);
end;
procedure TMyImageViewer.WMSize(var Message: TMessage);
begin
inherited;
CalculateOffsets;
CalculateScrollRanges;
Invalidate;
end;
end.
Первоначально я начал писать это в Lazarus, но хотел бы использовать его в Delphi, следовательно, обе метки были добавлены.
Как именно рассчитываются полосы прокрутки? Принимая во внимание, что детей нет или автоматическая прокрутка не включена, поэтому это должны быть ручные вычисления, я просто рисую изображение в центре элемента управления и должен знать, как рассчитать диапазоны полос прокрутки и т. Д.
Я пробовал несколько разных вещей без успеха, и мне просто кажется, что я сейчас что-то вкладываю и надеюсь на лучшее, поэтому я действительно мог бы сделать некоторые рекомендации здесь, пожалуйста.
EDIT
Так отведав работает исходный код в Delphi теперь заставило меня понять, насколько больше различных Лазарь, много вещей, которые должны были быть изменены, чтобы работать под Delphi и даже прямо сейчас полосы прокрутки исчезает.
Спасибо, я знал об использовании компонента TImage, но мне не нравится, как он отображается во время разработки, поскольку я хотел, чтобы он выглядел как мой собственный элемент управления. Я буду внимательно смотреть на ваш ответ. :) – Craig
Есть ли способ заставить полосы прокрутки не прыгать? Например, я загрузил растровое изображение и прокрутил самое левое, а затем, когда я изменил размер окна, полосы прокрутки подскочили (элемент управления был выровнен с клиентом). – Craig
Я не знаю, почему 'TScrollingWinControl' не имеет холста, так или иначе, я думаю, что он должен это делать, поэтому вам нужно выбирать между« TCustomControl »и« TScrollingWinControl ». – Craig