[Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する

782 views
Skip to first unread message

MoonDoldo

unread,
Nov 29, 2007, 10:04:18 AM11/29/07
to Del...@ml.users.gr.jp
Moondoldoです。

フォームの最大化の際に、大きさや位置の制限を動的に値を変えたいので以下の
ようなコードを書いています。

(略)
private
{ Private 宣言 }
//フォームの大きさと位置の制限
procedure WMGetMinMaxInfo(var msg : TWMGetMinMaxInfo);
message WM_GETMINMAXINFO;
public
{ Public 宣言 }
FMaxSizeX, FMaxSizeY, FMaxPositionX, FMaxPositionY: Integer;
end;
(略)
procedure TForm1.FormCreate(Sender: TObject);
begin
FMaxSizeX := 500;
FMaxSizeY := 600;
FMaxPositionX := 10;
FMaxPositionY := 20;
end;

procedure TForm1.WMGetMinMaxInfo(var msg: TWMGetMinMaxInfo);
begin
msg.MinMaxInfo.ptMaxSize.X := FMaxSizeX;
msg.MinMaxInfo.ptMaxSize.Y := FMaxSizeY;
msg.MinMaxInfo.ptMaxPosition.X := FMaxPositionX;
msg.MinMaxInfo.ptMaxPosition.Y := FMaxPositionY;
end

procedure TForm1.Button2Click(Sender: TObject);
begin
//この値を変えれば動的に制限できる…が既に最大化してる場合はどうする?
FMaxSizeX := 200;
FMaxSizeY := 300;
FMaxPositionX := 40;
FMaxPositionY := 50;
end;

Button2Clickのイベントで大きさと位置の制限が変更されますが、既にウインド
ウを最大化した後だと当然「WM_GETMINMAXINFO」が来ないのでウインドウに変化
はありません。
この場合どうしたら良いのでしょうか?
何かヒントを下さい、よろしくお願いします。

※「元のサイズに戻す」→「最大化」するという方法は見た目がみっともないの
で無しでお願いします。

ムーンドルド

鈴木充

unread,
Nov 29, 2007, 6:58:16 PM11/29/07
to Del...@ml.users.gr.jp
鈴木@EcoSoftです。

---[[Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する]への返信です。---


> Button2Clickのイベントで大きさと位置の制限が変更されますが、既にウインド
> ウを最大化した後だと当然「WM_GETMINMAXINFO」が来ないのでウインドウに変化
> はありません。
> この場合どうしたら良いのでしょうか?

Button2Click 内で WindowState = wsMaximized 時にのみ SetBounds() すれば
どうでしょうか。(最大化時の状態にのみ反映されるようです <D7>)

if WindowState = wsMaximized then
SetBounds(FMaxPositionX, FMaxPositionY, FMaxSizeX, FMaxSizeY);

---
---
// 鈴木 充 <http://www.geocities.jp/eco21426/>


Yamamoto Satoshi

unread,
Nov 30, 2007, 11:40:12 AM11/30/07
to Del...@ml.users.gr.jp
こんにちは。

> Button2Clickのイベントで大きさと位置の制限が変更されますが、既にウインド
> ウを最大化した後だと当然「WM_GETMINMAXINFO」が来ないのでウインドウに変化
> はありません。
> この場合どうしたら良いのでしょうか?

鈴木さんもおっしゃっておりますが

Button2Clickイベントで
・最大化している時は
・位置を移動させる
という処理をしてあげるといいです。

SetBoundsやMoveWindow APIで位置を合わすと
タスクバーの位置を考慮しないように移動してしまいますので
タスクバーが左や上に配置しているときに誤動作します。

タスクバー位置を考慮するコードなどをいれると下記のようになりました。
どうぞ。

//タスクバーを除いたデスクトップの大きさを求める
function NoneTaskBarDesktopRect: TRect;
var
rectDesktop : TRect;
begin
Result := Rect(0,0,0,0);
if SystemParametersInfo(SPI_GETWORKAREA, 0, @rectDesktop, 0) then
begin
Result := rectDesktop;
end;
end;

//デスクトップサイズを求める
//マルチディスプレイ対応
function GetDesktopTop: Integer;
begin
Result := GetSystemMetrics(SM_YVIRTUALSCREEN);
end;
function GetDesktopLeft: Integer;
begin
Result := GetSystemMetrics(SM_XVIRTUALSCREEN);
end;
function GetDesktopHeight: Integer;
begin
Result := GetSystemMetrics(SM_CYVIRTUALSCREEN);
end;
function GetDesktopWidth: Integer;
begin
Result := GetSystemMetrics(SM_CXVIRTUALSCREEN);
end;
function GetDesktopRect: TRect;
begin
Result := Bounds(GetDesktopLeft, GetDesktopTop, GetDesktopWidth, GetDesktopHeight);
end;

function TaskBarAdjustmentDesktopPosition(OriginalPosition: TPoint): TPoint;
begin
Result.X :=
OriginalPosition.X + (NoneTaskBarDesktopRect.Left-GetDesktopLeft);
Result.Y :=
OriginalPosition.Y + (NoneTaskBarDesktopRect.Top-GetDesktopTop);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
AdjustmentPosition: TPoint;
begin


FMaxSizeX := 200;
FMaxSizeY := 300;
FMaxPositionX := 40;
FMaxPositionY := 50;

if WindowState=wsMaximized then
begin
AdjustmentPosition :=
TaskBarAdjustmentDesktopPosition(Point(FMaxPositionX, FMaxPositionY));
Self.SetBounds(
AdjustmentPosition.X, AdjustmentPosition.Y, FMaxSizeX, FMaxSizeY);
end;
end;

> 送信者 MoonDoldo <do1...@king-postman.com>
> 宛先 Del...@ml.users.gr.jp
> 日時 2007/11/30 0:04:18
> 件名 [Delphi:90115] ウインドウを最大化したまま最大化サイズを調節する
> ----

> ※「元のサイズに戻す」→「最大化」するという方法は見た目がみっともないの
> で無しでお願いします。

-----
Yamamoto Satoshi
sat...@big.or.jp


MoonDoldo

unread,
Nov 30, 2007, 6:51:37 PM11/30/07
to Del...@ml.users.gr.jp
 MoonDoldoです。

鈴木さん、Yamamotoさん、お返事ありがとうございます。

もう一度WM_GETMINMAXINFOを発生させる方法があるのかと予想していたのですが、
既に最大化されている場合は自前で位置と大きさを設定するしかないのですね。

試してみます、ありがとうございます。

コードが出来上がりましたら、サマリーとして後ほど公開したいと思います。

ムーンドルド

MoonDoldo

unread,
Dec 1, 2007, 12:26:08 PM12/1/07
to Del...@ml.users.gr.jp
 MoonDoldoです。

マルチディスプレイでちょっとした問題が出てきました。

最大化でサイズ・位置の制限(WM_GETMINMAXINFO)をした後、最大化したままサイズ・位置の制限を解除したくなりました。
そこでサイズを元の大きさに戻すのにSetBoundsを使ったところ、ウインドウの外枠が隣のディスプレイにはみ出して見えるようになってしまいました。

通常の最大化だと、ウインドウの枠がはみ出す位置と大きさになるにも関わらず、隣のディスプレイにはみ出した枠は見えません。

以下書いている途中のコードです。

procedure TForm1.WMGetMinMaxInfo2;
var
WkMonitorInfo : TMonitorInfo;
WkSmCxframe, WkSmCyframe: Integer;
begin
// 最大化の時のみ実行される
if IsZoomed(Self.Handle) then
begin
// マルチモニタ対応の有効面の取得
WkMonitorInfo.cbSize := SizeOf(WkMonitorInfo);
if GetMonitorInfo(Self.Monitor.Handle, @WkMonitorInfo) = True then
begin
if RadioButton1.Checked = True then
begin
// ここのコードまだ書いてない
end
else begin
// 通常、Windowsでは最大化した際にウインドウの枠は有効面の外にはみ出る
// 大きさは有効面より左右2辺、上下2辺の枠の分だけ大きくなる。
// ウインドウの位置も左1辺、上1辺分だけ左上にずれる事になる。
// これだと隣のディスプレイに枠の部分がはみでて見えるように思えるが、
// ウインドウの枠が全て外側にある場合はそうはならない。

if Self.BorderStyle <> bsNone then
begin
// ウインドウの枠の幅を取得
WkSmCxframe := GetSystemMetrics(SM_CXFRAME);
WkSmCyframe := GetSystemMetrics(SM_CYFRAME);
end
else begin
// BorderStyleがbsNoneの場合は枠がないため枠の大きさを考慮しない
WkSmCxframe := 0;
WkSmCyframe := 0;
end;

// 通常の最大化の位置
Self.SetBounds(
WkMonitorInfo.rcWork.Left - WkSmCxframe,
WkMonitorInfo.rcWork.Top - WkSmCyframe,
WkMonitorInfo.rcWork.Right -
WkMonitorInfo.rcWork.Left +
(WkSmCxframe * 2),
WkMonitorInfo.rcWork.Bottom -
WkMonitorInfo.rcWork.Top +
(WkSmCyframe * 2));
end
end;
end;
end;

どうしたら最大化をしたまま、枠が見えない通常の最大化に戻せるのでしょうか?
ヒントを下さい、よろしくお願いします。

ムーンドルド

khe00221

unread,
Dec 2, 2007, 12:27:32 PM12/2/07
to Del...@ml.users.gr.jp
KHE00221 です

元に戻すサイズを最大(0,0,Screen.Width,Screen.Height) にしてから最大から元に戻し、その後最大化してみました

var
WindowPlacement,SaveWindowPlacement : TWindowPlacement;

begin
//元に戻す用に保存
GetWindowPlacement(Form1.Handle,@SaveWindowPlacement);
//元に戻すサイズを変更し、元に戻す
WindowPlacement.length := SizeOf(WindowPlacement);
WindowPlacement.showCmd := SW_SHOWNORMAL;
WindowPlacement.flags := WPF_RESTORETOMAXIMIZED;
WindowPlacement.rcNormalPosition := Rect
(0,0,Screen.Width,Screen.Height);
SetWindowPlacement(Form1.Handle,@WindowPlacement);
//最大化
ShowWindow(Form1.Handle, SW_SHOWMAXIMIZED );
end;

元に戻すときは

SetWindowPlacement(Form1.Handle,@SaveWindowPlacement);

を実行してください

でないと最大化する前のサイズには戻りません

-----------------------------
http://khe00221.image.coocan.jp/
-----------------------------

khe00221

unread,
Dec 2, 2007, 12:41:49 PM12/2/07
to Del...@ml.users.gr.jp
少し変更です

最大化後 Button1 でクリックし、サイズを変更後 Button2 で最大化します

元のサイズに戻すと Button2 で最大化する前のサイズに戻ります。

procedure TForm1.Button1Click(Sender: TObject);
begin
Left := 100;
Top := 100;
Width := 400;
Height := 400;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
WindowPlacement,SaveWindowPlacement : TWindowPlacement;
begin

if Form1.WindowState = wsMaximized then
begin

GetWindowPlacement(Form1.Handle,@SaveWindowPlacement);

WindowPlacement.length := SizeOf(WindowPlacement);
WindowPlacement.showCmd := SW_SHOWNORMAL;
WindowPlacement.flags := WPF_RESTORETOMAXIMIZED;
WindowPlacement.rcNormalPosition := Rect
(0,0,Screen.Width,Screen.Height);
SetWindowPlacement(Form1.Handle,@WindowPlacement);

ShowWindow(Form1.Handle, SW_SHOWMAXIMIZED );

WindowPlacement.length := SizeOf(WindowPlacement);
WindowPlacement.showCmd := SW_SHOWNORMAL;
WindowPlacement.flags := WPF_RESTORETOMAXIMIZED;

SetWindowPlacement(Form1.Handle,@SaveWindowPlacement);

end;

end;

khe00221

unread,
Dec 2, 2007, 6:59:56 PM12/2/07
to Del...@ml.users.gr.jp
どう見てもおかしですよね・・・前に送信したの

でまた修正版 こんどのは平気だと思います

最大化のサイズは -4 , -4 , Screen.Width + 4 , Screen.Height + 4 のようです

最大化し、その後リサイズしないで実行すると多少ちらつきます。

procedure TForm1.Button2Click(Sender: TObject);
var
WindowPlacement,SaveWindowPlacement : TWindowPlacement;

ARect : TRect;
begin

if Form1.WindowState = wsMaximized then
begin

   //再最大化する前の状態を保存
GetWindowPlacement(Form1.Handle,@SaveWindowPlacement);
   //この2行がなければ最初の最大化する前のサイズに戻ります
GetWindowRect(Form1.Handle,ARect);
SaveWindowPlacement.rcNormalPosition := ARect;
//再最大化


WindowPlacement.length := SizeOf(WindowPlacement);
WindowPlacement.showCmd := SW_SHOWNORMAL;
WindowPlacement.flags := WPF_RESTORETOMAXIMIZED;
WindowPlacement.rcNormalPosition := Rect

(-4,-4,Screen.Width+8,Screen.Height+8);
SetWindowPlacement(Form1.Handle,@WindowPlacement);
ShowWindow(Form1.Handle, SW_SHOWMAXIMIZED );
//次回元に戻す際のサイズを設定

鈴木充

unread,
Dec 2, 2007, 7:34:25 PM12/2/07
to Del...@ml.users.gr.jp
鈴木@EcoSoftです。

---[[Delphi:90122] Re: ウインドウを最大化したまま最大化サイズを調節する]への返信です。---
> どうしたら最大化をしたまま、枠が見えない通常の最大化に戻せるのでしょうか?
> ヒントを下さい、よろしくお願いします。

一旦通常に戻すとちらつきが気になるというのでしたら、

LockWindowUpdate(Handle);
WindowState := wsNormal;
WindowState := wsMaximized;
LockWindowUpdate(0);

でいいような気もしますが...そういう問題ではない?

MUROHASHI Yuzo

unread,
Dec 3, 2007, 9:37:43 AM12/3/07
to Del...@ml.users.gr.jp
室橋雄三@自宅です。
MLはお久しぶりです。


MoonDoldo さん:
> 既に最大化されている場合は自前で位置と大きさを設定するしかないのですね。

なんとなく面白そうなので、書いてみました。
WindowsとDelphiとでウィンドウ状態の情報が交錯すると、
挙動がおかしくなるので、APIで一気に処理させました。
ちょっと危険な香りがしますが・・・。

当方、マルチモニタ環境がないため、
的を射ていないかもしれませんが、ご参考までに。

---
フォームにボタンを2つ配置します。
---
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
FMaxSizeX: Integer;
FMaxSizeY: Integer;
FMaxPositionX: Integer;
FMaxPositionY: Integer;

procedure WMGetMinMaxInfo(var Message : TWMGetMinMaxInfo); message WM_GETMINMAXINFO;

procedure ChangeMaxInfo(nMaxSizeX, nMaxSizeY, nMaxPositionX, nMaxPositionY: Integer);
public
{ Public 宣言 }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
FMaxSizeX := 500;
FMaxSizeY := 600;
FMaxPositionX := 10;
FMaxPositionY := 20;
end;

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
begin
with Message.MinMaxInfo^ do
begin
ptMaxSize.X := FMaxSizeX;
ptMaxSize.Y := FMaxSizeY;
ptMaxPosition.X := FMaxPositionX;
ptMaxPosition.Y := FMaxPositionY;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ChangeMaxInfo(200, 300, 40, 50);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ChangeMaxInfo(500, 600, 10, 20);
end;

procedure TForm1.ChangeMaxInfo(nMaxSizeX, nMaxSizeY, nMaxPositionX,
nMaxPositionY: Integer);
var
wp1: TWindowPlacement;
wp2: TWindowPlacement;
begin
// WindowsとDelphiとで状態関係を保つため、最大化時のみ処理する
if IsZoomed(Self.Handle) then
begin
// 現在の位置情報を取得
// ※一番最初に最大化した時点のリストア
// (元のサイズに戻す)サイズを憶えて置くため
ZeroMemory(@wp1, sizeof(TWindowPlacement));
wp1.length := sizeof(TWindowPlacement);
GetWindowPlacement(Self.Handle, @wp1);

// フォームの最大化スタイルを無理やり消しちゃう
SetWindowLong(Self.Handle
,GWL_STYLE
,GetWindowLong(Self.Handle, GWL_STYLE) and not WS_MAXIMIZE);

// 新しい最大化のサイズを設定する
FMaxSizeX := nMaxSizeX;
FMaxSizeY := nMaxSizeY;
FMaxPositionX := nMaxPositionX;
FMaxPositionY := nMaxPositionY;

// さらに最大化
ShowWindow(Self.Handle, SW_MAXIMIZE);

// 新しい位置情報を取得
ZeroMemory(@wp2, sizeof(TWindowPlacement));
wp2.length := sizeof(TWindowPlacement);
GetWindowPlacement(Self.Handle, @wp2);

// リストア時の情報のみ上書き
wp2.rcNormalPosition := wp1.rcNormalPosition;

// 位置情報を書き戻す
SetWindowPlacement(Self.Handle, @wp2);
end;
end;
n n
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- d(^n^)b -=+
| 室橋雄三 [MUROHASHI Yuzo] |
| Mail: maxi...@power.email.ne.jp |
+=- q(-~-)p -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=+
U U

MoonDoldo

unread,
Dec 3, 2007, 11:10:02 AM12/3/07
to Del...@ml.users.gr.jp
 MoonDoldoです。

KHE00221さん、鈴木さん、お返事有難うございます。

KHE00221さんのコードは、「元のサイズに戻す」の時に最大化時の大きさのウインドウサイズを指定して
ウインドウの収縮を防ぎ、そのまま「最大化」をする事によって、ちらつきを最小限に抑えている様です。

鈴木さんのコードは、ウインドウの描画そのものを停止して
「元のサイズに戻す」→「最大化」をした後、描画再開している様です。

とりあえずどちらでも自分の要求は満たせるのですが、
今回はウインドウに張ってあるコンポーネントのOnResizeの回数が最小限になりそうな
KHE00221さんの方法で行こうと思います。

------------------------------------------------
鈴木さん、Yamamotoさん、KHE00221さん、大変助かりました、ありがとうごさいます。
みなさんの助言を見つつ、作ったのが以下のコードです。

※同じ内容のファイルを以下のページでダウンロード出来るようにしてあります。
http://www.wikihouse.com/doldoworkz/index.php?Delphi-ML%A4%C7%B6%B5%A4%A8%A4%C6%A4%E2%A4%E9%A4%C3%A4%BF%A5%C6%A5%AF%A5%CB%A5%C3%A5%AF

FormにはRadioButton1、RadioButton2が張ってあります。

(省略)
private
{ Private 宣言 }

// 最大化時にWM_GETMINMAXINFOでフォームの大きさを調整した際に
// フォームが移動できてしまうのを防止するためのコード
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;

// フォームの大きさと位置の制限


procedure WMGetMinMaxInfo(var msg : TWMGetMinMaxInfo); message WM_GETMINMAXINFO;

// 既に最大化している場合のサイズ変更
procedure WMGetMinMaxInfo2;
public
{ Public 宣言 }
FSizeX, FSizeY, FPositionX, FPositionY: Integer;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.WMSysCommand(var Message: TWMSysCommand);
begin
if IsZoomed(Self.Handle) and ((Message.CmdType and $FFF0) = SC_MOVE) then
begin
Exit;
end;
inherited;
end;

procedure TForm1.WMGetMinMaxInfo(var msg: TWMGetMinMaxInfo);
var
WkMonitorInfo : TMonitorInfo;

WkSizeX, WkSizeY: Integer;
WkPositionX, WkPositionY: Integer;
WkPositionRight, WkPositionBottom: Integer;
begin
// 最大化の際に来るメッセージ
// ここで何もしなかった場合は通常の最大化となる

// マルチモニタ対応の有効面の取得
WkMonitorInfo.cbSize := SizeOf(WkMonitorInfo);
if GetMonitorInfo(Self.Monitor.Handle, @WkMonitorInfo) = True then
begin
if RadioButton1.Checked = True then
begin

// 最大化の大きさおよび位置を指定する
// 有効面以上の大きさにならないようにする
WkSizeX :=
Min(FSizeX, WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left);
WkSizeY :=
Min(FSizeY, WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top);

// 位置の値を保持
WkPositionX := FPositionX;
WkPositionY := FPositionY;

// 有効面から左上にはみ出ている場合は直す
if WkPositionX < WkMonitorInfo.rcWork.Left then
begin
WkPositionX := WkMonitorInfo.rcWork.Left;
end;
if WkPositionY < WkMonitorInfo.rcWork.Top then
begin
WkPositionY := WkMonitorInfo.rcWork.Top;
end;

// 有効面から右下にはみ出ている場合は直す
WkPositionRight := WkPositionX + WkSizeX;
WkPositionBottom := WkPositionY + WkSizeY;
if WkPositionRight > WkMonitorInfo.rcWork.Right then
begin
WkPositionX := WkMonitorInfo.rcWork.Right - WkSizeX;
end;
if WkPositionBottom > WkMonitorInfo.rcWork.Bottom then
begin
WkPositionY := WkMonitorInfo.rcWork.Bottom - WkSizeY;
end;

// GetMonitorInfo,Self.Top,Self.Leftで帰ってくる値は
// プライマリディスプレイの左上を原点(0,0)とした値が帰ってくるが、
// msg.MinMaxInfo.ptMaxPositionは各種ディスプレイごとの左上を原点(0,0)
// とした座標を指定しなければいけない
msg.MinMaxInfo.ptMaxSize.X := WkSizeX;
msg.MinMaxInfo.ptMaxSize.Y := WkSizeY;
msg.MinMaxInfo.ptMaxPosition.X :=
WkPositionX - WkMonitorInfo.rcMonitor.Left;
msg.MinMaxInfo.ptMaxPosition.Y :=
WkPositionY - WkMonitorInfo.rcMonitor.Top;
end
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
FSizeX := 400;
FSizeY := 400;
FPositionX := 0;
FPositionY := 0;
end;

procedure TForm1.WMGetMinMaxInfo2;
var
WkMonitorInfo : TMonitorInfo;
WkSmCxframe, WkSmCyframe: Integer;

WkSizeX, WkSizeY: Integer;
WkPositionX, WkPositionY: Integer;
WkPositionRight, WkPositionBottom: Integer;

WkWindowPlacement, WkSaveWindowPlacement : TWindowPlacement;


begin
// 最大化の時のみ実行される
if IsZoomed(Self.Handle) then
begin
// マルチモニタ対応の有効面の取得
WkMonitorInfo.cbSize := SizeOf(WkMonitorInfo);
if GetMonitorInfo(Self.Monitor.Handle, @WkMonitorInfo) = True then
begin
if RadioButton1.Checked = True then
begin

// 最大化の大きさおよび位置を指定する
// 有効面以上の大きさにならないようにする
WkSizeX :=
Min(FSizeX, WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left);
WkSizeY :=
Min(FSizeY, WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top);

// 位置の値を保持
WkPositionX := FPositionX;
WkPositionY := FPositionY;

// 有効面から左上にはみ出ている場合は直す
if WkPositionX < WkMonitorInfo.rcWork.Left then
begin
WkPositionX := WkMonitorInfo.rcWork.Left;
end;
if WkPositionY < WkMonitorInfo.rcWork.Top then
begin
WkPositionY := WkMonitorInfo.rcWork.Top;
end;

// 有効面から右下にはみ出ている場合は直す
WkPositionRight := WkPositionX + WkSizeX;
WkPositionBottom := WkPositionY + WkSizeY;
if WkPositionRight > WkMonitorInfo.rcWork.Right then
begin
WkPositionX := WkMonitorInfo.rcWork.Right - WkSizeX;
end;
if WkPositionBottom > WkMonitorInfo.rcWork.Bottom then
begin
WkPositionY := WkMonitorInfo.rcWork.Bottom - WkSizeY;
end;

Self.SetBounds(WkPositionX, WkPositionY, WkSizeX, WkSizeY);


end
else begin
// 通常、Windowsでは最大化した際にウインドウの枠は有効面の外にはみ出る
// 大きさは有効面より左右2辺、上下2辺の枠の分だけ大きくなる。
// ウインドウの位置も左1辺、上1辺分だけ左上にずれる事になる。

if Self.BorderStyle <> bsNone then


begin
// ウインドウの枠の幅を取得
WkSmCxframe := GetSystemMetrics(SM_CXFRAME);
WkSmCyframe := GetSystemMetrics(SM_CYFRAME);
end
else begin
// BorderStyleがbsNoneの場合は枠がないため枠の大きさを考慮しない
WkSmCxframe := 0;
WkSmCyframe := 0;
end;

WkPositionX := WkMonitorInfo.rcWork.Left - WkSmCxframe;
WkPositionY := WkMonitorInfo.rcWork.Top - WkSmCyframe;
WkSizeX :=
WkMonitorInfo.rcWork.Right - WkMonitorInfo.rcWork.Left +
(WkSmCxframe * 2);
WkSizeY :=
WkMonitorInfo.rcWork.Bottom - WkMonitorInfo.rcWork.Top +
(WkSmCyframe * 2);

// 隣のディスプレイに枠の部分がはみでて見えてしまうのを防止するために
// 「元のサイズに戻す」→「最大化」を行う

// ウィンドウの配置情報を保持
GetWindowPlacement(Self.Handle, @WkSaveWindowPlacement);
try
// 一度元のサイズに戻すが、
// ちらつきを最小限にするために最大化と同じ大きさで元のサイズに戻す
WkWindowPlacement.length := SizeOf(WkWindowPlacement);
WkWindowPlacement.showCmd := SW_SHOWNORMAL;
WkWindowPlacement.flags := WPF_RESTORETOMAXIMIZED;
WkWindowPlacement.rcNormalPosition :=
Rect(WkPositionX, WkPositionY,
WkPositionX + WkSizeX, WkPositionY + WkSizeY);
SetWindowPlacement(Self.Handle, @WkWindowPlacement);
// 再最大化する
ShowWindow(Self.Handle, SW_SHOWMAXIMIZED);
finally
//保持していたウィンドウの配置情報を戻す
SetWindowPlacement(Form1.Handle, @WkSaveWindowPlacement);
end;
end
end;
end;
end;

procedure TForm1.RadioButton1Click(Sender: TObject);
begin
WMGetMinMaxInfo2;
end;

procedure TForm1.RadioButton2Click(Sender: TObject);
begin
WMGetMinMaxInfo2;
end;

今後ともよろしくお願い致します。

ムーンドルド

MoonDoldo

unread,
Dec 3, 2007, 11:17:31 AM12/3/07
to Del...@ml.users.gr.jp
 MoonDoldoです。

室橋さんお返事ありがとうございます。

>MoonDoldo さん:
>> 既に最大化されている場合は自前で位置と大きさを設定するしかないのですね。
>
>なんとなく面白そうなので、書いてみました。

おお、こういった方法もあるのですね。
今後の参考にさせて頂きます、ありがとうございます。

ムーンドルド

MoonDoldo

unread,
Dec 3, 2007, 12:02:23 PM12/3/07
to Del...@ml.users.gr.jp
 MoonDoldoです。

コードでわかりずらい部分があったので修正です。

2ヶ所ある以下のコード


> // 位置の値を保持
> WkPositionX := FPositionX;
> WkPositionY := FPositionY;

この場合、FPositionXとFPositionYは、プライマリディスプレイの左上を原点(0,
0)とした座標を指定する事になります。

以下のように変えると

// 位置の値を保持
WkPositionX := FPositionX + WkMonitorInfo.rcMonitor.Left;
WkPositionY := FPositionY + WkMonitorInfo.rcMonitor.Top;

FPositionXとFPositionYは、各種ディスプレイごとの左上を原点(0,0)
とした座標で設定する事が出来ます。
例としてはこちらのほうがわかりやすいと思います。

ムーンドルド

Reply all
Reply to author
Forward
0 new messages