5

私は、アプリケーションでいくつかのモードレスフォームをタスクバーに表示しようとしています-Windows7の新しい便利なタスクバーを利用しています。

VCLには多くの問題があり、タスクバーにフォームが存在する前に元に戻す必要があります。

ただし、最後の問題は、VCLがメインフォームに指定したフォームを最小化すると、アプリケーション内のすべてのウィンドウが消えることです。

10年前、PeterBelow(TeamB)はこれらの問題を文書化し、それらを回避しようと試みました。しかし、解決できない問題がいくつかあります。問題はVCL自体の奥深くで発生するため、Delphiアプリケーションを適切に動作させることは事実上不可能です。

これはすべて、ツールバーに表示されるボタンがアプリケーションのウィンドウを表していないという事実に起因しています。TApplicationsそれは隠されていて決して見られない窓を表しています。そして、アプリケーションのがあります。これには、最小化された場合にアプリケーションに非表示にするように指示する特別MainFormな機能が組み込まれています。

できれば

Application.MainForm := nil;

そうすれば、これらのバグはすべてなくなります。アプリケーションは非表示のウィンドウを持つことができ、その間、メインフォームを含むアプリケーション内の他のすべてのフォームを次のようにオーバーライドします。

procedure TForm2.CreateParams(var params: TCreateParams ); 
begin 
   inherited CreateParams(params); 
   params.ExStyle := params.ExStyle or WS_EX_APPWINDOW; 
end; 

ただし、Delphiでは、Application.MainFormプロパティは読み取り専用です。

MainFormDelphiでを使用できないのはどうしてですか?

も参照してください

4

6 に答える 6

10

MainFormが割り当てられていない状態でGUIプロジェクトを実行することはできません。メインメッセージループは、1つがないとすぐに終了します。ただし、これはMainFormがUIを実行する必要があるという意味ではありません。割り当てられたMainFormとして空白の非表示のTFormを使用してから、実際のMainFormをセカンダリTFormとしてインスタンス化することができます。例えば:

HiddenMainFormApp.dpr:

project HiddenMainFormApp;

uses
  ..., Forms, HiddenMainForm;

begin
  Application.Initialize;
  Application.CreateForm(THiddenMainForm, MainForm);
  Application.ShowMainForm := False;
  Application.Run;
end.

HiddenMainForm.cpp:

uses
  ..., RealMainForm;

procedure THiddenMainForm.FormCreate(Sender: TObject);
begin
  RealMainForm := TRealMainForm.Create(Self);
  RealMainForm.Show;
end;

RealMainForm.cpp:

procedure TRealMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  Application.Terminate;
end;

または:

HiddenMainFormApp.dpr:

project HiddenMainFormApp;

uses
  ..., Forms, HiddenMainForm, RealMainForm;

begin
  Application.Initialize;
  Application.CreateForm(THiddenMainForm, MainForm);
  Application.ShowMainForm := False;

  RealMainForm := TRealMainForm.Create(Application);
  RealMainForm.Show;
  RealMainForm.Update;

  Application.Run;
end.

RealMainForm.cpp:

procedure TRealMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  Application.Terminate;
end;
于 2010-10-21T19:38:45.540 に答える
5

特に Delphi 5 ではできません。

TApplicationウィンドウがタスクバーに表示されるというあなたの引用は、現在、いくつかのDelphiバージョンでは当てはまりません(D2007が変更したと思います)。

Delphi 5 を使用しているため、Delphi の古いコピーを使用しています。現在のバージョンには、あなたが書いていることはほとんどありません。新しいバージョンの Delphi にアップグレードすることをお勧めします (D5 は非常に古いものです)。Unicode を避ける必要がある場合は Delphi 2007、VCL と RTL で Unicode サポートを使用できる場合 (または使用してもかまわない場合) は Delphi XE。

あなたが説明していることはバグではありません、ところで。これらは、Delphi 1 の設計時に行われた意図的な設計上の決定であり、Delphi 7 を通じて、利用可能な Windows のバージョンで問題なく動作しました。それ以降のバージョンの Windows (XP/Vista/Win7 および同等のサーバー バージョン) での変更により、そのアーキテクチャの変更が必要になりました。これらの変更は、Delphi が Windows とともに進歩するにつれて行われました。Delphi のバージョンを最新の状態に保つために進行しないことを選択したからといって、書いた内容が魔法のようにバグになるわけではありません。:-)

于 2010-10-21T14:09:56.587 に答える
3

ここでは、MainForm を最小化しながらタスクバーに別のモードレス フォームを表示するために、Application.MainForm を割り当てても問題ないようです。

Project1.dpr:

program Project1;

uses
  Forms,
  Windows,
  Unit1 in 'Unit1.pas' {MainForm},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.res}

var
  MainForm: TMainForm;

begin
  Application.Initialize;
  Application.CreateForm(TMainForm, MainForm);
  ShowWindow(Application.Handle, SW_HIDE);
  Application.Run;
end.

Unit1.パス:

unit Unit1;

interface

uses
  Windows, Messages, Classes, Controls, Forms, StdCtrls, Unit2;

type
  TMainForm = class(TForm)
    ShowForm2Button: TButton;
    ShowForm2ModalButton: TButton;
    procedure ShowForm2ButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ShowForm2ModalButtonClick(Sender: TObject);
  private
    FForm2: TForm2;
    procedure ApplicationActivate(Sender: TObject);
    procedure Form2Close(Sender: TObject; var Action: TCloseAction);
    procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

implementation

{$R *.dfm}

procedure TMainForm.FormCreate(Sender: TObject);
begin
  Visible := True; //Required only for MainForm, can be set designtime
  Application.OnActivate := ApplicationActivate;
end;

procedure TMainForm.ApplicationActivate(Sender: TObject);
{ Necessary in case of any modal windows dialog or modal Form active }
var
  TopWindow: HWND;
  I: Integer;
begin
  TopWindow := 0;
  for I := 0 to Screen.FormCount - 1 do
  begin
    Screen.Forms[I].BringToFront;
    if fsModal in Screen.Forms[I].FormState then
      TopWindow := Screen.Forms[I].Handle;
  end;
  Application.RestoreTopMosts;
  if TopWindow = 0 then
    Application.BringToFront
  else
    SetForegroundWindow(TopWindow);
end;

procedure TMainForm.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
  begin
    ExStyle := ExStyle or WS_EX_APPWINDOW;
    WndParent := GetDesktopWindow;
  end;
end;

procedure TMainForm.WMSysCommand(var Msg: TWMSysCommand);
begin
  if Msg.CmdType = SC_MINIMIZE then
    ShowWindow(Handle, SW_MINIMIZE)
  else
    inherited;
end;

{ Testing code from here }

procedure TMainForm.ShowForm2ButtonClick(Sender: TObject);
begin
  if FForm2 = nil then
  begin
    FForm2 := TForm2.Create(Application); //Or: AOwner = nil, or Self
    FForm2.OnClose := Form2Close;
  end;
  ShowWindow(FForm2.Handle, SW_RESTORE);
  FForm2.BringToFront;
end;

procedure TMainForm.Form2Close(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
  FForm2 := nil;
end;

procedure TMainForm.ShowForm2ModalButtonClick(Sender: TObject);
begin
  with TForm2.Create(nil) do
    try
      ShowModal;
    finally
      Free;
    end;
end;

end.

Unit2.パス:

unit Unit2;

interface

uses
  Windows, Messages, Classes, Controls, Forms;

type
  TForm2 = class(TForm)
  private
    procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

implementation

{$R *.dfm}

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do
  begin
    ExStyle := ExStyle or WS_EX_APPWINDOW;
    WndParent := GetDesktopWindow;
  end;
end;

procedure TForm2.WMSysCommand(var Msg: TWMSysCommand);
begin
  if Msg.CmdType = SC_MINIMIZE then
    ShowWindow(Handle, SW_MINIMIZE)
  else
    inherited;
end;

end.

(XP および Win7 で D5 および D7 を使用してテスト済み)。

(そして、そうではありません。まだ MainForm があります。しかし、これが質問の背後にある質問に答えていると思いたいです...)

于 2011-06-03T16:36:42.557 に答える
2

Delphi 5 について話すことはできませんが、Delphi 7 では、手を汚しても構わないと思っているのであれば、メインフォームなしで確実に実行できます。ここで別の回答で多くの詳細を説明しました。

Delphi 5 には MainFormOnTaskbar プロパティがないため、dpr で次の操作を行う必要があります。

// Hide application's taskbar entry
WasVisible := IsWindowVisible(Application.Handle);
if WasVisible then
  ShowWindow(Application.Handle, SW_HIDE);
SetWindowLong(Application.Handle, GWL_EXSTYLE,
  GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
if WasVisible then
  ShowWindow(Application.Handle, SW_SHOW);
// Hide the hidden app window window from the Task Manager's
// "Applications" tab.  Don't change Application.Title since
// it might get read elsewhere.
SetWindowText(Application.Handle, '');

これにより、アプリケーション ウィンドウが非表示になり、フォームのCreateParamsをオーバーライドしてそれぞれを設定する限りParams.WndParent := 0、独自のタスクバー エントリが作成されます。Application.MainForm は割り当てられていないため、最小化のオーバーライドなどは問題になりませんが、MainForm が有効であると想定するコードには注意する必要があります。

于 2011-06-03T18:46:06.657 に答える
0

実際、あなたが不平を言っていることのほとんどは、実際には VCL ではなく Windows の設計です。詳細については、 Windows の機能を参照してください。

問題の核心は所有者のプロパティです。つまり、VCL の所有者ではなく、Windows の所有者です。

所有されているウィンドウは、所有者が最小化されると非表示になります。

他のウィンドウを非表示にせずにメイン フォームを最小化できるようにしたい場合は、所有されているウィンドウがどのように機能するかを理解する必要があります。

于 2011-06-03T17:35:55.690 に答える
0

モードレス フォームを dll に入れると、ほとんど単独で動作します。(それらを作成するときに dll の Application インスタンスを使用しない場合 (Application.CreateForm)、Application.Mainform は dll で nil になります)。

もちろん、フォームが何をする必要があるかによっては、これは実行できない場合があります。

于 2010-10-21T14:51:30.250 に答える