36

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

ここに画像の説明を入力

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

そして2006年に再び:

そして2008年に再び:

2012 年に Embarcadero フォーラムで誰かが質問しました。

18 年前のバグを Stackoverflow に移植するときが来ました。誰かが最終的に回避策を見つけたのかもしれません。

再現手順:

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

  • LabelaとEdita をフォームにドロップします。

    ここに画像の説明を入力

  • OnEnter次のイベントを追加しTEditます。

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

    • WindowStatewsMaximized
    • AutoScroll

そしてバジンガ、失敗。

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 ソースへの関連する変更を引用することが含まれる可能性があります。(それが修正されている場合)。

注: poDesignedPositionから他のものに変更しても、問題は解決しません。

回避策

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

時々、私OnAfterShowは Delphi が決してしなかったイベントを発明します:

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;

しかし、ハックよりも優れたハックはありません。

4

5 に答える 5

0

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

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

それは私に失敗することはありません。

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

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

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

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

于 2016-10-18T12:41:51.090 に答える
0

わお!私はポストに表示されませんでした:

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% コード ソリューション。

どうもありがとう!

PD: Linux で動作しますか? つまり、コードが (Lazarus で) Linux 用にコンパイルされたら、それをテストして確認する必要があります。それが機能する場合は、今まで使用していたものが大幅に改善されるでしょう。

于 2016-10-19T06:48:15.513 に答える