Delphi 7表单在Vista中无法使用锚点功能。

14

该软件是基于Delphi 7构建的。

在我的XP机器上,窗体会按照我期望的方式进行调整大小。然而,在两台Vista机器上,我有一些组件的锚点设置为[akLeft,akTop,akRight,akBottom],但是当我调整窗体大小时,这些组件不会随着窗体一起拉伸,留下右边缘和底部的空白。在XP机器上,组件会正确地随着窗体一起拉伸。

因此,似乎Vista机器正在忽略锚定属性。有什么想法是什么原因导致这种情况并如何解决?

重要更新(弗朗索瓦):
我们的D2007应用程序在x64 Windows上也出现了同样的问题。
Andreas的答案确实是解决方法。 所以这与D7或Vista无关。


该程序是在哪个版本的Windows下编译的? - Argalatyr
1
请看Argalatyr的回答。它有意义吗? - Hemant
弗朗索瓦:是的,假设Robo的问题与我们刚遇到的故障相同,而不是其他无关的问题。 - Mason Wheeler
6个回答

12

我觉得你是不是对此有一种印象,只有在嵌套控件大约20层深的情况下才适用? - Argalatyr
这取决于系统范围内安装了多少WH_CALLWNDPROC窗口钩子。 (例如,Logitech使用WH_CALLWNDPROC钩子,TActionManager也是如此)。 - Andreas Hausladen
我在工作中遇到了这个问题,通过你在这里的帖子找到了它的原因。非常感谢你提供的信息和解决方法,Andreas。你已经获得了许多成就,这又是其中一项。 - Mason Wheeler
非常抱歉回复晚了。我在.dpr文件中将ControlResizeBugFix.pas添加到项目中,但没有任何改变。在我的64位Windows 7机器上,控件仍然无法调整大小。 - Robo
1
好的,问题已经解决。这与某些窗体的OldCreateOrder属性默认为true有关,而有些默认为false,这导致了一些窗体调整大小的代码无法正常工作。如果我将该属性更改为false、保存窗体,然后再次打开它,它将在某些窗体上重新默认为true。 - Robo
在MSDN博客文章中也有关于这个问题的一些信息:http://blogs.msdn.com/b/alejacma/archive/2008/11/20/controls-won-t-get-resized-once-the-nesting-hierarchy-of-windows-exceeds-a-certain-depth-x64.aspx?PageIndex=2,以及这篇微软知识库文章:http://support.microsoft.com/kb/953934。 - garethm

2
可能是因为Vista显示的透明框架导致的,为了让不同的窗口具有相同的透明外观。

尝试使用“Align”(alClient)而不是锚点。由于您正在使用所有的锚点,这样做更有意义。


这样做不行,因为该控件将占据整个屏幕,覆盖其他控件。 - Robo
1
例如,您的屏幕上有一个覆盖大部分区域的备忘录,并且在表单底部有一些按钮。您首先放置一个面板并将其Align属性设置为alBottom。您将控件放置在该面板上。然后,您放置备忘录控件并将其Align属性设置为alClient(这将填充表单但保留底部面板)。 - Hemant
+1 这个确实有效(根据Hemant的额外评论)。请参考我的答案中的可行代码示例(我本来想编辑Hemant的答案,但担心这样做会很无礼)。 - Argalatyr

2

在 Delphi 4 引入锚点之前,我们通过动态调整组件大小来实现相同的效果。您可以在表单的 onresize 事件中轻松移动 / 调整组件。

将表单的 doublebuffered 属性设置为 true 可以通过缓冲 paint 方法来减少闪烁。我记得我们以前也不得不自己实现这个功能!


1
作为我提出的动态调整大小的替代方案,基于Hemant的建议,我拼凑了一些可行的代码(如下所示)。只需创建一个VCL表单应用程序,在上面放置一个不接触表单任何边缘的tpanel(默认情况下,Align = alNone),并将Unit1替换为下面的代码。运行时,您将看到4个黄色面板围绕最初添加的面板,并且中央面板将随着表单的大小调整而调整大小(就像所有锚点都是true一样)。
unit Unit1;

interface

uses
  Windows, Classes, Controls, Forms, ExtCtrls, Graphics;

type
  TPanelPos = (ppLeft, ppRight, ppTop, ppBottom);
  TForm1 = class(TForm)
    Panel1: TPanel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    Panels : array[TPanelPos] of tpanel;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  PanelPos : TPanelPos;
begin
  for PanelPos := ppLeft to ppBottom do
  begin
    Panels[PanelPos] := tpanel.Create(Form1);
    Panels[PanelPos].Parent := Form1;
    Panels[PanelPos].Color := clYellow;
    case PanelPos of
     ppLeft :
       begin
         Panels[PanelPos].Align := alLeft;
         Panels[PanelPos].Width := Panel1.Left - 1;
       end;
     ppRight :
       begin
         Panels[PanelPos].Align := alRight;
         Panels[PanelPos].Width := Form1.Width - Panel1.Left - Panel1.Width;
       end;
     ppTop :
       begin
         Panels[PanelPos].Align := alTop;
         Panels[PanelPos].Height := Panel1.Top - 1;
       end;
     ppBottom :
       begin
         Panels[PanelPos].Align := alBottom;
         Panels[PanelPos].Height := Form1.Height - Panel1.Top - Panel1.Height;
       end;
    end;
    Panel1.Align := alClient;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  PanelPos : TPanelPos;
begin
  for PanelPos := ppLeft to ppBottom do
    Panels[PanelPos].Free;
end;

end.

0
尝试在Vista上以XP兼容模式运行程序。由Delphi 7编译的程序可能不完全支持Vista本机模式(这并不令人惊讶)。

客户希望在本机Vista上运行它,而不是兼容模式,希望有办法绕过这个问题。 - Robo
明白了。抱歉我无法提供更多帮助,因为我不再使用D7,我的回答已经总结了我的理解情况。祝你找到解决方案! - Argalatyr
2
如果你想要完整的Vista支持,你需要升级。自Delphi 2007以来,这已经成为了一个特性。事实上,如果你真的想保持最新,你应该获取Delphi 2010,它于上周发布。它不仅支持Windows 7,还支持Vista。 - Mason Wheeler
2
Mason: 这是事实,但这并没有真正回答问题。对于某些项目坚持使用旧版本有可信的理由,并在这些限制条件内找到满足规格要求的方法是一个现实世界中的挑战。 - Argalatyr

0

看起来这是一个相当古老的问题,无论如何,在宇宙中只有一种解决此问题的方法:使用旧风格的 Windows 编程大小调整方法,使用 API 拦截 WM_SIZE 和 WM_SIZING,这是不会出错的方法,并且将在您所知道的每个 Windows 上运行。

当然,这意味着您必须主要使用 GetClientRect() 来确定宽度和高度,然后根据这些值调整控件的大小,当然这可能听起来像点火航天器一样,但这是最好的方法。

否则,您可以在调整大小的过程中执行更实际和快速的操作,例如:

Control1.Left := Control2.Left + (buttonControl.Width div 2) - (buttonControl3.Width div 2);
//for example widths
Control4.Width    := (Control.Width * 4) + (Control.Left * 8) + 54 ;

我可以在任何版本的Windows上进行这种编码和函数操作。

你只需要屏幕分辨率上的一些数值作为参考,就可以做出类似这样的操作:

iCXSCREEN := GetSystemMetrics(SM_CXSCREEN);
iCYSCREEN := GetSystemMetrics(SM_CYSCREEN);

    if ((iCXSCREEN = 1280) and (iCYSCREEN = 720)) or  ((iCXSCREEN = 1280) and (iCYSCREEN = 700)) or ((iCXSCREEN = 1280) and (iCYSCREEN = 600)) then begin

// blah blah

end;

希望能对其他人有所帮助!
祝好!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接