web-dev-qa-db-ja.com

wsMaximizedフォームが最大化されて表示されない

フォームをWindowState = wsMaximizedに設定すると、フォームが最大化されることがありますが、最大化されません。

enter image description here

長年のバグ:これは、2003年にボーランドのニュースグループで最初に尋ねた質問です。

そして再び2006年に:

そして再び2008年に:

2012年のエンバカデロフォーラムで誰かが質問しました。

18年前のバグをStackoverflowに移植する番です。多分誰かがようやく回避策を見つけました。

再現手順

私の投稿には6ダースの失敗モードが含まれていましたが、最も簡単な方法は次のとおりです。

  • LabelEditをフォームにドロップします。

    enter image description here

  • OnEnterTEditイベントを追加します。

    procedure TForm1.Edit1Enter(Sender: TObject);
    begin
       Label1.Font.Style := Label1.Font.Style + [fsBold];
    end;
    
  • フォームを設定します。

    • WindowState to wsMaximized
    • AutoScroll to False

そしてバジンガは失敗する。

2008年の投稿の他のステップの1つ:

  1. 新しいアプリとフォームを作成します。
  2. 設計時にフォームを最大化(WindowState = wsMaximized)に設定します。
  3. フォームにListViewコントロールをドロップします。
  4. OnShow中に、20個の空のアイテムをリストビューに追加します。

    procedure TForm1.FormShow(Sender: TObject);
    var
         i: Integer;
    begin
         for i := 1 to 20 do
              ListView1.Items.Add;
    
    end;
    
  5. 設計時にフォームのAutoScrollプロパティをfalseに設定します(AutoScroll = False)。

もちろん、私がしないの後には "RadStudioのバージョンnで修正されています。ただそれを使用してください" 。私は実際の修正(もしあれば)を探しています。これには、CodeGearが最終的に修正したときに、VCLソースに関連する変更を引用することが含まれます。 (それが修正されている場合でも)。

注:PositionpoDesignedからその他に変更しても修正されません。

Workaround

私が使用していた恐ろしい、醜い、ひどい、嫌な、回避策は、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;

しかし、ハックはハックよりも優れています。

36
Ian Boyd

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;

これにより、操作の完了を待たずにウィンドウの表示状態が設定されます。

13
kobik

これはDelphiのバグではなく、WindowsのCreateWindow関数のバグ(または奇妙な動作)だと思います。 CreateWindowを検索してWS_MAXIMIZEが機能していない場合、CreateWindowまたはCreateWindowExを呼び出してスタイルパラメータにWS_MAXIMIZEを渡し、アプリケーションを実行したときに最大化されたウィンドウが表示されないという同様の非常に古いスレッドとディスカッションが見つかります。

古いgamedev.netスレッドからの抜粋

問題は、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;
1
gordy

私が使用するソリューションが他の人を助けることを願っています(既知のウィンドウが最初に設計時サイズで表示されます)。

  • 間隔が1未満のタイマーを追加します(0を入れないでください)。
  • そのためのコード:theTimer.Enabled:=False;WindowState:=wsMaximized;

それは私には決して失敗しません。

フォームが表示され、そのようなショーのすべての保留中のタスクが完了するとすぐに、タイマーがトリガーされ、ウィンドウが最大化されます。

少し前に、最大化ボタンがある場所にマウスクリックを送信するというトリックを使用していましたが、Windows OSのバージョン、プラグイン(Linuxの場合)などを確認すると、状況が非常に難しくなることがわかりました。これは、ユーザーがウィンドウを最大化するように要求する場合とまったく同じように機能しました。

現在使用しているタイマーはまったく同じですが、OSのチェックなどは避けてください。

言うまでもありません。DesignTimeでWindowStateをwsNormalに設定します(wsMinimizedにもwsMaximizedにも設定しないでください)。

0
claudio

うわー!私は投稿を見ませんでした:

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で)、私はそれをテストして確認する必要があることを意味します。それが機能するかどうかは、今まで使用していたものを大幅に改善するでしょう。

0
claudio