フォームをWindowState = wsMaximized
に設定すると、フォームが最大化されることがありますが、最大化されません。
長年のバグ:これは、2003年にボーランドのニュースグループで最初に尋ねた質問です。
そして再び2006年に:
そして再び2008年に:
2012年のエンバカデロフォーラムで誰かが質問しました。
18年前のバグをStackoverflowに移植する番です。多分誰かがようやく回避策を見つけました。
再現手順:
私の投稿には6ダースの失敗モードが含まれていましたが、最も簡単な方法は次のとおりです。
Label
とEdit
をフォームにドロップします。
OnEnter
のTEdit
イベントを追加します。
procedure TForm1.Edit1Enter(Sender: TObject);
begin
Label1.Font.Style := Label1.Font.Style + [fsBold];
end;
フォームを設定します。
WindowState
to wsMaximizedAutoScroll
to Falseそしてバジンガは失敗する。
2008年の投稿の他のステップの1つ:
- 新しいアプリとフォームを作成します。
- 設計時にフォームを最大化(WindowState = wsMaximized)に設定します。
- フォームにListViewコントロールをドロップします。
OnShow中に、20個の空のアイテムをリストビューに追加します。
procedure TForm1.FormShow(Sender: TObject); var i: Integer; begin for i := 1 to 20 do ListView1.Items.Add; end;
設計時にフォームのAutoScrollプロパティをfalseに設定します(AutoScroll = False)。
もちろん、私がしないの後には "RadStudioのバージョンn
で修正されています。ただそれを使用してください" 。私は実際の修正(もしあれば)を探しています。これには、CodeGearが最終的に修正したときに、VCLソースに関連する変更を引用することが含まれます。 (それが修正されている場合でも)。
注:Position
をpoDesignedからその他に変更しても修正されません。
私が使用していた恐ろしい、醜い、ひどい、嫌な、回避策は、OnShow
の間にタイマーを開始し、タイマーが起動したらフォームを最大化することでした:
procedure TForm1.tmrVclMaximizeHackTimer(Sender: TObject);
begin
Self.WindowState := wsMaximized;
end;
後でこのハックを改良して、OnShow
の間にメッセージを投稿しました。これは基本的にタイマーメッセージと同じですが、タイマーを使用する必要はありません。
const
WM_MaximizeWindow = WM_APP + $03;
procedure TForm1.FormShow(Sender: TObject);
begin
if (Self.WindowState = wsMaximized) then
begin
Self.WindowState := wsNormal;
PostMessage(Self.Handle, WM_MaximizeWindow , 0, 0);
end;
end;
private
procedure WMMaximizeWindow(var Message: TMessage); message WM_MaximizeWindow;
procedure TForm1.WMMaximizeWindow(var Message: TMessage);
begin
Self.WindowState := wsMaximized;
end;
ときどき、DelphiがやったことのないOnAfterShow
イベントを発明します。
const
WM_AfterShow = WM_APP + $02;
procedure TForm1.FormShow(Sender: TObject);
begin
PostMessage(Self.Handle, WM_AfterShow, 0, 0);
if (Self.WindowState = wsMaximized) then
begin
Self.WindowState := wsNormal;
FMaximizeNeeded := True;
end;
end;
private
procedure WMAfterShow(var Message: TMessage); message WM_AfterShow;
procedure TForm1.WMAfterShow(var Message: TMessage);
begin
if FMaximizeNeeded then
begin
FMaximizeNeeded := False;
Self.WindowState := wsMaximized;
end;
end;
しかし、ハックはハックよりも優れています。
D7/Win7で再現できます。
私はwsMaximized
をまったく使用していません(あなたが説明しているのと同様のランダム問題)。
回避策:use OnActivate
-> ShowWindow(Handle, SW_MAXIMIZE)
例:
procedure TForm1.FormActivate(Sender: TObject);
begin
// Maximize only once when the Form is first activated
if not FMaxsimized then
begin
FMaxsimized := True;
ShowWindow(Handle, SW_MAXIMIZE);
end;
end;
このメソッドはOnShow
の間は機能しません。
より良い回避策:use ShowWindowAsync
during OnShow
またはOnCreate
例:
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowWindowAsync(Handle, SW_MAXIMIZE);
end;
これにより、操作の完了を待たずにウィンドウの表示状態が設定されます。
これはDelphiのバグではなく、WindowsのCreateWindow関数のバグ(または奇妙な動作)だと思います。 CreateWindowを検索してWS_MAXIMIZEが機能していない場合、CreateWindowまたはCreateWindowExを呼び出してスタイルパラメータにWS_MAXIMIZEを渡し、アプリケーションを実行したときに最大化されたウィンドウが表示されないという同様の非常に古いスレッドとディスカッションが見つかります。
問題は、WS_OVERLAPPEDWINDOWを使用する場合、WS_MAXIMIZEが明らかに適用されないことです。 WS_OVERLAPPEDWINDOWをWS_POPUPに置き換えると、ウィンドウが最大化されます。もちろん、これはWindowsのすべてのバージョン、またはWindows Shell UIのすべてのバージョンにさえ当てはまるとは限りません。
WS_OVERLAPPEDWINDOWはMSの古いデフォルトウィンドウの「タイプ」であり、特定のスタイルを無視するようにCreateWindow/Exをコーディングしているようで、ShowWindowはSW_SHOWDEFAULTで呼び出され、CreateProcess起動情報パラメーターに従ってウィンドウが表示されると考えられます。これにより、最終的にユーザーはシェルのショートカット設定を使用して、アプリのメインウィンドウをどのように表示するかを制御できます。
回避策は、ShowWindowを呼び出すことです。 Delphiでも動作するはずです。
procedure TForm1.FormShow(Sender: TObject);
begin
ShowWindow(Handle, SW_MAXIMIZE);
end;
私が使用するソリューションが他の人を助けることを願っています(既知のウィンドウが最初に設計時サイズで表示されます)。
theTimer.Enabled:=False;WindowState:=wsMaximized;
それは私には決して失敗しません。
フォームが表示され、そのようなショーのすべての保留中のタスクが完了するとすぐに、タイマーがトリガーされ、ウィンドウが最大化されます。
少し前に、最大化ボタンがある場所にマウスクリックを送信するというトリックを使用していましたが、Windows OSのバージョン、プラグイン(Linuxの場合)などを確認すると、状況が非常に難しくなることがわかりました。これは、ユーザーがウィンドウを最大化するように要求する場合とまったく同じように機能しました。
現在使用しているタイマーはまったく同じですが、OSのチェックなどは避けてください。
言うまでもありません。DesignTimeでWindowStateをwsNormalに設定します(wsMinimizedにもwsMaximizedにも設定しないでください)。
うわー!私は投稿を見ませんでした:
ShowWindowAsync(Handle、SW_MAXIMIZE);
そのおかげで、私の問題はタイマーよりもはるかにうまく解決されますが、完璧ではありませんが、それでも少しちらつきが発生します(ウィンドウが不完全なレンダリングで表示され、最大化された状態になります)、タイマーよりもはるかに優れています最大化されていない状態では、表示される時間が短くなります。
また、OnShowメソッドの以前のSetBounds()と互換性があります。
私が望むこと:フォームを表示する前に、初期サイズ(幅、高さ)と、場合によっては初期位置(左、上)を設定しますが、そのフォームは最大化して表示する必要があります。このような位置とサイズは、ユーザーがウィンドウを最大化しない場合のものです。
そのShowWindowAsync
はそのような目的に最適であり、醜いタイマーを追加する必要はありません(最初の文として、コードにinterval = 1および.Enabled = Falseを指定します)。
投稿を読んだときに、どうしてそれを見逃すことができたのでしょう!
それで、今私は使用します(ちょうど例としてモニターに対する相対的なOS初期サイズ):
procedure TtheForm.FormShow(Sender: TObject);
var
theInitialDefaultWidth,theInitialDefaultHeight:Integer;
begin
theInitialDefaultWidth:=Round(Screen.Width*3/5);
theInitialDefaultHeight:=Round(Screen.Height*3/5);
WindowState:=wsNormal; // So it can still have at design time wsMaximized, this is for the SetBounds to work on a non maximized state
SetBounds((Screen.Width-theInitialDefaultWidth)div 2,(Screen.Height-theInitialDefaultHeight)div 2,theInitialDefaultWidth,theInitialDefaultHeight); // Set default position and default size as i wish
ShowWindowAsync(Handle,SW_MAXIMIZE); // Make the window to be shown maximized when it will be visible
// ... // Rest of actions for the FormShow method
end;
完璧に動作します!設計時のプロパティを変更する必要はありません。そのままにできます(WindowState = wsMaximized、Position = poScreenCenterなど)。問題の100%コードソリューション。
どうもありがとう!
P.D .: Linuxで動作しますか? Linux用にコードがコンパイルされたとき(Lazarusで)、私はそれをテストして確認する必要があることを意味します。それが機能するかどうかは、今まで使用していたものを大幅に改善するでしょう。