这个让我起了墙。从Delphi 6到XE5的大部分转换都在顺利进行,但我有各种例程来动态构建各种TForm后代(NO DFM),弹出它并通常返回一个值。我有很多在D6中工作正常的人。一般来说,我选择一个我想要弹出的地方(比如在面板上),以及我想要弹出的内容(编辑框,备忘录,列表框......)。我创建表单,设置初始值并调用showmodal并返回一些结果。
在XE5中编译的相同代码有执行(毛刺)。一个是创建的表单接受left,top等,但不会在那里显示。值在属性中正确,但表单位于错误的位置。第二个,可能是相关的(故障)是当我创建一个TMemo或TListbox并在其中存储一些文本时,“ShowModal”正确显示数据,但“Show”没有。
我花了几个小时将问题消化到最简单的形式,删除虚拟的所有个人代码。如此显示,它完美运作
如果我注释掉这一行,它就不起作用 - 表格显示在错误的地方
XX.ClientToScreen(Point(0,0)); // EXTREMELY WEIRD PATCH
这一行是一个函数调用,它不会影响其他任何东西,我不使用返回的值。
注释掉的“显示”行显示了另一个问题(数据未显示)。
我曾在各种各样的地方尝试Application.ProcessMessages
,但它永远不会让事情变得更好,有时会让事情变得更糟。
让我“困惑”。
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
type TMemoForm = class(TForm)
private
public
XMemo : TMemo;
end;
Function PopUpMemoStr(txt : AnsiString; x : integer = 200; y : integer = 200; w : integer = 400 ; h : integer = 400 ) : AnsiString; // more or less a dummy for testing on XE5 2/28/14
var XX : TMemoForm;
begin
XX := TMemoForm.CreateNew(Application);
XX.ClientToScreen(Point(0,0)); // *** EXTREMELY WEIRD FIX ***
XX.Left := X; XX.Top := Y; XX.Width := w; XX.height := h;
XX.caption := 'Dummy PopUpMemo';
XX.XMemo := TMemo.create(XX);
XX.XMemo.parent := XX;
XX.XMemo.align := alClient;
XX.XMemo.text := txt;
//logit('PopUpMemoStr R='+TRectToStr(MyGetScreenRect(XX)));
XX.showmodal;
//XX.show; delay(3.00); // other "no data" problem
XX.free;
end;
//exercise code -- Panel2 is just a visible spot to see if positioning works correctly
var s : AnsiString;
var R : TRect;
begin
//R := MyGetScreenRect(Panel2);
R := Rect(414,514,678,642); // just a useful screen location for testing
s := 'One'+CRLF+'Two'+CRLF+'Three'+CRLF+'Four'; // "CRLF is #13#10
PopUpMemoStr(s,R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top);
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
答案 0 :(得分:4)
要解决表单定位问题,您需要将表单Position
设置为poDesigned
。
对于你的第二个问题,你不能那样拖延。您没有给表单提供处理邮件的机会。将其更改为类似下面的代码会正确显示数据(尽管你真的不应该这样做):
begin
XX := TMemoForm.CreateNew(nil);
try
XX.Position := poDesigned; // This line needs to be added for the positioning
XX.SetBounds(X, Y, w, h);
XX.Caption := 'Dummy PopUpMemo';
XX.XMemo := TMemo.Create(XX);
XX.XMemo.Parent := XX;
XX.XMemo.Align := alClient;
XX.XMemo.Text := txt;
//logit('PopUpMemoStr R='+TRectToStr(MyGetScreenRect(XX)));
// XX.ShowModal;
// This displays the data correctly but is not advisable
XX.Show;
for I := 1 to 6 do
begin
Sleep(500);
Application.ProcessMessages;
end;
finally
XX.Free;
end;
end;
如果您想使用Show()
作为此类表单,则应使用表单的OnClose
事件并将其Action
参数设置为caFree
,然后执行{您的代码中的{1}}。将计时器放在Form上x秒,并在计时器结束时Show()
。有点像这样:
Close()
type
TMemoForm = class(TForm)
public
XMemo : TMemo;
XTimer: TTimer;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure TimerElapsed(Sender: TObject);
end;
procedure TMemoForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end;
procedure TMemoForm.TimerElapsed(Sender: TObject);
begin
Close;
end;
答案 1 :(得分:1)
即使您没有使用返回的点,您在新创建的表单上调用ClientToScreen
这个非常奇怪的补丁也应该解决问题。
如果您不使用它,当您设置表单的边界时,由于尚未创建表单的窗口,VCL会保留此信息以便稍后在窗口时传递给API要显示。但是由于poDefaultPosOnly
属性的Position
设置,VCL还告诉API使用默认窗口位置,因此该信息将被丢弃。
在您使用它的情况下,为了能够在屏幕中确定表单的位置,VCL首先创建表单的窗口。因此,当您稍后设置表单的边界时,它们实际上是通过SetWindowPos
实现的。
因此,如果您已经使用过
XX.HandleNeeded;
而不是
XX.ClientToScreen(Point(0,0));
这将是一个更直接的解决方法。
当然,正确的解决方案是在Graymatter的answer中。
我无法评论Show
不显示数据,您在问题中发布的代码不应表现出这种行为。