【发布时间】:2017-08-23 21:06:21
【问题描述】:
-------------- 原始问题-------------------- -----
向所有 Delphi 开发人员致敬!在 Delphi 2006 非 MDI 应用程序中,我创建了一个不可调整大小、可自动滚动、可自动调整大小的表单。这是表单单元的摘录:
uses Grid;
TGridFrm = class(TForm)
public
Grid : TGrid;
constructor Create(AOwner : TComponent; Asize : TPoint);
end;
implementation
constructor TGridFrm.Create(AOwner: TComponent; Asize : TPoint);
begin
inherited Create(aowner);
borderstyle := bsSingle; // users are not allowed to resize the form
windowstate := wsNormal;
borderwidth := 0;
autosize := True;
autoscroll := True;
constraints.maxwidth := screen.width - 1;
constraints.maxheight := screen.height - 1;
grid := TGrid.Create(asize.x, asize.y, self);
end;
现在,TGrid 当然是一个带有自己画布的自定义控件。这是其单元的摘录:
TGrid = class (TCustomControl)
public
NoOfCellsX,
NoOfCellsY,
CellSize : integer;
procedure SetZoom(z : integer);
constructor Create(AWidth, AHeight : Integer; AParent : TForm = nil);
end;
implementation
constructor TGrid.Create(AWidth, AHeight : Integer; AParent : TForm = nil);
begin
inherited Create(AParent);
Parent := AParent;
align := alCustom;
left := 0;
top := 0;
end;
procedure TGrid.SetZoom(zoom : integer);
begin
cellsize := zoom * 10 div 100;
width := noofcellsx * cellsize;
height := noofcellsy * cellsize;
end;
在表单的单元中,我已经安排了一些事情(通过 ApplicationEvents 对象),以便在按下数字 +/- 键时使用一些缩放值调用 SetZoom。这一切背后的想法是让我的自定义控件捕捉到表单的左上角(具有一些预定义的边距/边框宽度),并让整个表单在我放大或缩小自定义控件时自动调整其大小,但是永远不会超出屏幕限制。它可以工作,但只能达到滚动条必须可见的程度:它们从不出现。由于这是一个可自动滚动的表单,当表单内的控件(在这种情况下为网格)变得大于受约束的表单并在它变小时时让开时,它们是否应该出现?我什至尝试通过将 SetZoom 移动到表单的类进行一些重构,但无济于事。我在这里错过了什么?
----------------- 之后添加的可编译代码------------------
项目文件:
program MyApp;
uses
Forms,
Grid in 'Source\Grid.pas',
GridForm in 'Source\GridForm.pas' {GridFrm},
Main in 'Source\Main.pas' {MainFrm};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TMainFrm, MainFrm);
Application.Run;
end.
Main.pas:
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TMainFrm = class(TForm)
CreateNewFormButton: TButton;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure CreateNewFormButtonClick(Sender: TObject);
end;
var
MainFrm: TMainFrm;
implementation
{$R *.dfm}
uses
GridForm;
procedure TMainFrm.CreateNewFormButtonClick(Sender: TObject);
var aform : TForm;
begin
aform := TGridFrm.Create(self, point(15, 15));
aform.show;
tgridfrm(aform).grid.SetZoom(100);
end;
procedure TMainFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
end.
GridForm.pas:
unit GridForm;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Grid, AppEvnts;
type
TGridFrm = class(TForm)
ApplicationEvents1: TApplicationEvents;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
private
TheGrid : TGrid;
public
property Grid : TGrid READ TheGrid WRITE TheGrid;
constructor Create(AOwner : TComponent; ASize : TPoint);
end;
var
GridFrm: TGridFrm;
implementation
{$R *.dfm}
procedure TGridFrm.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var keystate : TKeyboardState;
begin
if not Active then begin exit; end;
if msg.message = WM_KEYDOWN then
begin
getkeyboardstate(keystate);
case msg.wparam of
vk_Add : begin // zoom in
grid.setzoom(grid.zoom + 10);
handled := True;
end;
vk_Subtract : begin // zoom out
grid.setzoom(grid.zoom - 10);
handled := True;
end;
// other keys down here...
end;
end;
end;
constructor TGridFrm.Create(AOwner : TComponent; ASize : TPoint);
begin
inherited Create(AOwner);
borderstyle := bsSingle;
borderwidth := 2;
autosize := True;
autoscroll := True;
constraints.maxwidth := screen.width - 1;
constraints.maxheight := screen.height - 1;
visible := False;
grid := TGrid.Create(asize.x, asize.y, random(800) + 500, self);
end;
procedure TGridFrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
end.
还有 Grid.pas:
unit Grid;
interface
uses
StdCtrls, SysUtils, Controls, Forms, Graphics, Dialogs;
type
TGrid = class (TCustomControl)
Lbl1, Lbl2,
GridSizeInfoLbl,
FormSizeInfoLbl,
WarningLbl : TLabel;
public
NoOfCellsX,
NoOfCellsY,
SquareSize, // in 1/1000ths of centimeter
CellSize, // in pixels
Zoom : integer;
procedure SetZoom(z : integer);
constructor Create(x, y, asquaresize : integer; AParent : TForm = nil);
end;
implementation
uses
GridForm;
constructor TGrid.Create(x, y, asquaresize : integer; AParent : TForm = nil);
begin
inherited Create(AParent);
parent := AParent;
color := clTeal;
align := alCustom;
left := 0;
top := 0;
noofcellsx := x;
noofcellsy := y;
squaresize := asquaresize;
Lbl1 := TLabel.Create(self);
Lbl2 := TLabel.Create(self);
GridSizeInfoLbl := TLabel.Create(self);
FormSizeInfoLbl := TLabel.Create(self);
WarningLbl := TLabel.Create(self);
with Lbl1 do
begin
parent := self;
caption := 'Size of grid: ';
width := 55;
height := 18;
left := 2;
top := 1;
end;
with Lbl2 do
begin
parent := self;
caption := 'Size of form: ';
width := 75;
height := 18;
left := 2;
top := 19;
end;
with GridSizeInfoLbl do
begin
parent := self;
width := 100;
height := 18;
left := 65;
top := 1;
end;
with FormSizeInfoLbl do
begin
parent := self;
width := 100;
height := 18;
left := 65;
top := 19;
end;
with WarningLbl do
begin
parent := self;
width := 150;
height := 18;
left := 2;
top := 39;
end;
end;
procedure TGrid.SetZoom(z : integer);
begin
zoom := z;
cellsize := (screen.pixelsperinch * squaresize * zoom) div (1000 * 254);
width := noofcellsx * cellsize;
height := noofcellsy * cellsize;
GridSizeInfoLbl.caption := inttostr(Width) +
'x' + inttostr(Height) +
' (zoom: ' + inttostr(zoom) +
', cellsize zoomed: ' + inttostr(cellsize) +
', squaresize: ' + inttostr(squaresize) +
'mm, squares: ' + inttostr(noofcellsx) + 'x' + inttostr(noofcellsy) + ')';
with tgridfrm(parent) do
begin
left := (screen.Width - width) div 2;
top := (screen.Height - height) div 2;
FormSizeInfoLbl.caption := inttostr(Width) + 'x' + inttostr(Height) +
' (clientarea: ' + inttostr(clientwidth) + 'x' + inttostr(clientheight) + ')';
if self.width > clientwidth then
if self.Height > clientheight then
warninglbl.caption := 'Both scrollbars should appear!'
else
warninglbl.caption := 'Horizontal scrollbar should appear!'
else if self.Height > clientheight then
warninglbl.caption := 'Vertical scrollbar should appear!'
else
warninglbl.caption := 'No scrollbars needed';
end;
end;
end.
代码概要:单击主窗体的按钮会创建一个可自动调整大小的窗体,而该窗体又会创建一个具有随机初始大小的子网格。数字 +/- 键使网格变大或变小,并且表单会相应地自动调整大小,但永远不会显示滚动条,无论网格变得多大(我添加的标签提供视觉反馈)。
【问题讨论】:
-
自动调整大小和自动滚动?我会想象他们会互相打架。它们都受到完全相同的影响:控件放置在其边界之外。
-
发布可编译的代码,让我们看看是不是问题。
-
@SertacAkyuz 我编写了重现问题的代码。我应该怎么把它贴在这里?可以将其发布为我的问题的答案还是违反规则?抱歉,我是新来的。
-
在问题本身中包含一个最小示例,请参阅minimal reproducible example。
-
感谢您更新代码,但它仍然不是 MCVE。据我所知,您的问题似乎与此自定义网格控件无关,而是与它的容器形式有关。这同样适用于 any 控件,对吧?这就是 MCVE 的目的,消除实际上与问题无关的所有内容,特别是“最小”部分。在创建 MCVE 的过程中,您很可能会自己发现问题,因为您无需阅读大量不相关的代码。
标签: delphi