动态TForm创建Delphi XE5中的特性(错误?)

时间:2014-02-28 18:26:17

标签: delphi delphi-xe5

这个让我起了墙。从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);


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------

2 个答案:

答案 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不显示数据,您在问题中发布的代码不应表现出这种行为。