views:

1114

answers:

6

The software is built on Delphi 7.

On my XP machine, the form resizes as I expect. However, on two Vista machines, I have components with anchors set to [akLeft, akTop, akRight, akBottom], but when I resize the form, the components don't stretch with the form, leaving blank spaces on the right and bottom edge. On the XP machine, the components correctly stretch with the form.

So, it seems like the Vista machine is ignoring the anchor property. Any ideas what's causing this and how to fix it?

Important update (François):
We had the same problem with our D2007 application and on all x64 windows.
Andreas' answer was indeed the fix. So it is not D7 nor Vista related.

A: 

Try running the program in XP compatibility mode on Vista. Programs compiled by Delphi 7 may not fully support Vista native mode (no surprise there, really).

Argalatyr
The clients will want to run it in native Vista rather than compatibility mode, hoping there's some way to get around that.
Robo
Understood. Sorry I don't have more to offer - I no longer use D7, and my response summarizes my understanding of the situation. I hope you find a solution!
Argalatyr
If you want full Vista support, you're going to have to upgrade. It's been a feature since Delphi 2007. In fact, if you really want to stay current, you ought to get Delphi 2010, which came out last week. It's got full support for Windows 7 as well as Vista.
Mason Wheeler
Mason: that's true, but it doesn't really answer the question. There are credible reasons for sticking with an older version for some projects, and finding a way to satisfy specs within those constraints is a real-world challenge.
Argalatyr
+1  A: 

It might be because of the transparent frame which is shown by Vista. (In order to give different windows same transparent appearance.

Try using "Align" (alClient) instead of anchors. Since you are using all anchors, that makes more sense.

Hemant
That won't work because the control will take up the entire screen, covering other controls.
Robo
For example you have memo covering most of your screen and you have some buttons at the bottom of the form. You fist place a panel and set its Align property to alBottom. You place your controls on that panel. Then you place memo control and set its align property to alClient (this will fill the form but leave the bottom panel).
Hemant
+1 this does work (with Hemant's additional comment). See working code in my answer as an example (I'd have edited Hemant's answer, but worried that might be rude).
Argalatyr
If D7 already has AlignWithMargins, alClient could work.
Ulrich Gerhardt
+2  A: 

Before anchors were introduced in Delphi 4, we resized components dynamically to achieve the same effect. You can easily move/adjust the components in the form's onresize event.

Setting the form's doublebuffered property to true may reduce flicker, by buffering the paint method. I recall we used to have to implement that ourselves, too!

Argalatyr
+5  A: 

Maybe it is related to the "Windows Kernel stack overflow" problem that occurs if your control has many parents. And if you run it on a 64 bit system the kernel stack overflow happens much faster. (more about this here: http://news.jrsoftware.org/news/toolbar2000/msg07779.html)

On Embarcadero's CodeCentral is a workaround for this bug (which is also copied almost 1:1 into the Delphi 2009 VCL): http://cc.embarcadero.com/Item/25646

Andreas Hausladen
Am I right to have the impression that this applies only if you have controls nested about 20 levels deep?
Argalatyr
It depends on how many WH_CALLWNDPROC window hooks are system-wide installed. (Logitech for example uses WH_CALLWNDPROC hooks, and so does the TActionManager).
Andreas Hausladen
I just ran into this one at work and managed to track it down to this issue thanks to your post here. Thank you for the information and the fix, Andreas. Yet another feather in your already-considerable cap.
Mason Wheeler
+1  A: 

As an alternative to the dynamic resizing I suggested, based on Hemant's suggestion I slapped together some working code (below). Just create a VCL forms application, drop on a tpanel that does not touch any edge of the form (by default, Align = alNone) and replace Unit1 with the code below. When you run it, you'll see 4 yellow panels surrounding the one initially added, and the central panel will resize with the form (as if all anchors were 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.
Argalatyr
Nice (and thorough) snippet!
Hemant
A: 

It looks this is pretty old question, anyway here's the only one solution for this problem in the Universe : Use the old style Windows programming sizing method using API trapping WM_SIZE and WM_SIZING, that's the infalible one and will function in every Windows you'll know.

Of course this means you have to use mainly GetClientRect() to determine witdhs and heights and then resize controls based on such values, sure that may sound like trying to ignite a spaceship but it's the best.

Otherwise you could do something more practical and quickly in a resizing procedure like :

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

I do that kind of coding and functions in just all Windows no matter wich version it would be.

You only need some values on the screen resolution for reference doing something like this :

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;

Hope helps someone else!

Cheers!

Neuron