Form2のみ、常に、他のソフトの上にするには?

解決


さやかな  2009-11-12 09:15:21  No: 36147

いろいろと試してみたのですが、よく分かりません。
Form1や他のソフトの上に、Form2を常に上に表示したいんですが・・・

単純に

SetWindowPos(Form2.Handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE+SWP_NOSIZE);

で出来ると、思ったんですが、どうもうまくいかないのです。
上に出来たと思っても、別のアプリを交互にクリックすると、Form2が下に隠れてしまったり。

Delphi6なんですが、知っている方がいましたら、お願い致します。


これは?  2009-11-12 11:10:04  No: 36148

如何?...

Form2.formstyle := fsStayOnTop;
SetWindowPos(Form2.Handle,HWND_TOP,0,0,0,0,SWP_NOMOVE+SWP_NOSIZE);
FormU2.Showmodal;

いろいろ手はありますが・・・


さやかな  2009-11-12 11:48:20  No: 36149

回答ありがとうございます。
まず、
実行すると、エラーになり、
>表示されているウィンドウをモーダルにすることはできません。
とでます。

//これは、アプリの中で一番上にするって事ですよね。
Form2.formstyle := fsStayOnTop;
//これが、ハンドルを指定して、上にする。
SetWindowPos(Form2.Handle,HWND_TOP,0,0,0,0,SWP_NOMOVE+SWP_NOSIZE);
//モーダルで表示する。
Form2.Showmodal;

モーダルってのが分からなかったので、調べてみました。
使えるメソッドなのですが、一つは、Form2を非表示にしていないとエラーが起きるのと、これでも、他のアプリの上にはなりません。

っていうか、普通同一アプリ?内なら、fsStayOnTopだけでいいのでは?
そうではなくて、Form2のみを、別のソフトやフォルダ表示も含めて、一番上にしたいのですが。

一応、試しにForm2.formstyle := fsStayOnTop;にして、
Timerで1秒ごとに、SetWindowPos(Form2.Handle,するのも考えたのですが、Form2が常にアクティブになるために、Form1の操作が不能になりました。
Form1をSetWindowPosにすれば、非アクティブの状態で、どのソフトの上にもなりますよね?
これをForm2のみにしたいのですが・・・。


Mr.XRAY  2009-11-12 17:17:42  No: 36150

お早うございます.Mr.XRAYです.

>これをForm2のみにしたいのですが・・・。

Form2が該当アプリのメインフォームでない場合は難しいですね.
以下は,表示するForm2のWindowProcのサブクラス化でやる方法です.
ただし,他のアプリが同じことをやっていると,動作は保障できまません.

>いろいろ手はありますが・・・

ということなので,方法,考え方の1つです.
同じDelphi6(Windows XP SP3)でテストしてみました.
Vistaでは正常動作しない場合もあります(アプリの構成による).

なお,

>Form2が常にアクティブになるために、Form1の操作が不能になりました。

----- メインフォーム(ここではForm1)からForm2を呼出すコード -----

procedure TForm1.Button1Click(Sender: TObject);
begin
    Form2.Show;
end;

---- Form2のコード -----

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
    OriginalProc:TWndMethod;
    procedure SubClassProc(var Message:TMessage);
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

//=============================================================================
//  元のWindowsProcを退避して新しいWindowProcを定義
//=============================================================================
procedure TForm2.FormCreate(Sender: TObject);
begin
  OriginalProc    := Self.WindowProc;
  Self.WindowProc := SubClassProc;
end;
//=============================================================================
//  アプリのメインフォームではないのでWindowsProcを元に戻しておく
//  Form2を表示開始時にCreateする場合は不要
//=============================================================================
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Self.WindowProc := OriginalProc;
end;
//=============================================================================
//  WindowProcのサブクラス
//=============================================================================
procedure TForm2.SubClassProc(var Message: TMessage);

  //Targetが最前面かを判定する関数
  function IsTopMost(Target: HWND): boolean;
  begin
    Result := ((GetWindowLong(Target, GWL_EXSTYLE) and WS_EX_TOPMOST) <> 0);
  end;
  //---------------------------------------------------------------------------
begin
  OriginalProc(Message);

  //このフォームが最前面でなければ最前面にする
  if IsTopMost(Self.Handle)=False then begin
    SetWindowPos(Self.Handle, HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOOWNERZORDER);
  end;
end;

end.

サブクラス化の参考ページ
http://mrxray.on.coocan.jp/Halbow/Notes/N004.html


Mr.XRAY  2009-11-12 17:23:33  No: 36151

>Form2が常にアクティブになるために、Form1の操作が不能になりました。

上記のコードでは,ということはないです.
Form1をクリック等してActiveにすれば操作可能です.
ただし,この場合でもForm2は最前面のままです.


Mr.XRAY  2009-11-13 02:23:43  No: 36152

大変失礼しました.
WindowsProcを元に戻すのはOnDestroyですね.OnCloseではなく.

procedure TForm2.FormDestroy(Sender: TObject);
begin
  Self.WindowProc := OriginalProc;
end;


さやかな  2009-11-13 06:55:59  No: 36153

やはり、難しそうですね。
メインとサブを逆にすれば、もっと楽なんです。

Mr.XRAYさんの回答を試してみようと思います。
ありがとうございました。


さやかな  2009-11-13 07:34:22  No: 36154

解決です。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加