2009-08-13 7 views
0

私はPeter Below's PBThreadedSplashFormを使用して、アプリケーションの起動時に表示しています。これは、データモジュールの作成中(メインフォームが作成される直前)にさまざまなデータベースが開かれると更新されます。Peter以下のスレッドスプラッシュ画面とモーダルダイアログ

問題は、データモジュールの作成中に行われる特定のことが存在するかどうかを確認することです。それらの項目のいずれかが見つからない場合は、項目を作成するかアプリケーションを閉じることができるようにモーダルダイアログが表示されます。 (欠落している項目は通常インデックスで、ダイアログは主にデータベースのインデックスを再作成するときに使用されるため、通常のユーザーではなく開発者を対象としています)。ただし、スプラッシュ画面の後ろにモーダルダイアログが表示されます。キャプションが変更されると、フォーカスされたウィンドウのように見えますが、スプラッシュ画面の後ろに表示されます。

スプラッシュ画面は、次のコードを使用して、メインのプロセスとは異なるスレッドからのWindows APIのCreateWindowEx()を使用して作成されます。

procedure TPBSplashThread.CreateSplashWindow; 
const 
    TopmostStyle: Array [Boolean] of DWORD = (0, WS_EX_TOPMOST); 
    NoActivateStyle : Array [Boolean] of DWORD = (0, WS_EX_NOACTIVATE); 
var 
    wsize: TSize; 
begin 
    wsize.cx := FSurface.Width + GetSystemMetrics(SM_CXEDGE) * 2; 
    wsize.cy := FSurface.Height + GetSystemMetrics(SM_CYEDGE) * 2; 
    FWnd := CreateWindowEx(
      TopmostStyle[ FTopmost ] or WS_EX_TOOLWINDOW 
      or WS_EX_STATICEDGE or WS_EX_CLIENTEDGE 
      or NoActivateStyle[ Win32MajorVersion >= 5 ], 
      MakeIntResource(FWndClass), 
      nil, 
      WS_POPUP or WS_BORDER, 
      Forigin.x, Forigin.y, 
      wsize.cx, wsize.cy, 
      0, 0, hInstance, self); 
    If FWnd = 0 Then 
    raise exception.create('TPBSplashThread.CreateSplashWindow: CreateWindowEx failed'); 
end; 

FTopmostは決してありません(明確な意味を持つ)プロパティですクラスの構築時にデフォルトの初期化が行われるため、Falseです。 (私は明示的にそれをFalseに設定しようとしましたが効果がありません)また、モーダルダイアログのOnShowイベント中にSetForegroundWindow()とSetWindowPos()を使用してみました。

これを引き起こしている原因は何ですか?

答えて

3

最後に問題を解決しました。これは、CreateWindowEx()の呼び出しでWS_EX_NOACTIVATEフラグが原因で発生したようです。それを取り除くためにそれを変更すると、問題を解決するようです。モーダルダイアログがスプラッシュ画面の上に表示されます。モーダルなので、スプラッシュ画面を上に置くことはできません。

作業コードは次のとおりです。


    FWnd := CreateWindowEx(
      TopmostStyle[ FTopmost ] or WS_EX_TOOLWINDOW 
      or WS_EX_STATICEDGE or WS_EX_CLIENTEDGE, 
      MakeIntResource(FWndClass), 
      nil, 
      WS_POPUP or WS_BORDER, 
      Forigin.x, Forigin.y, 
      wsize.cx, wsize.cy, 
      0, 0, hInstance, self); 

おかげで、ロブとクレイグ、努力のため。

0

あなたが説明を探しているなら、私はあなたを助けることができません。

ソリューションをお探しの場合は、初めてではありません。 Eddie Shipman encountered this same problem in May.彼の提案した解決策は、スプラッシュ画面で隠れているダイアログを最上位のウィンドウにすることでしたが、アプリケーションが他のウィンドウを表示する前にスプラッシュ画面を隠すことで、最終的に問題を回避しました。

もう1つの提案は、スプラッシュ画面にコマンドを投稿して、にすることです。メッセージボックスを表示するにはにしてください。このダイアログは、スプラッシュ画面の親となることがあります。しかし、VCLの贅沢品は、メインスレッドの外側では動作しないため、これ以上の余裕がないため、難しいです。

+0

私はEddieの投稿を見ました。問題は、スプラッシュフォームを知らないTDataSetの子孫によってダイアログが実際に作成されることです。スプラッシュフォームは、ShowSplashScreen()を使用してDPRで作成され、Application.CreateForm()は2回呼び出されます(データモジュールでは1回、メインフォームでは1回)、スプラッシュフォームはHideSplashForm()を使用して解放されます。データモジュールのOnCreateイベントでは、TDataSet。Openメソッドは欠落しているインデックスをチェックし、モーダルダイアログを表示するメソッドを呼び出します。その時点で誰がOpenを呼び出したのか、親プロセスのどこでそれが起こっているのか分かりません。 –

0

これを解決するには、ダイアログをスプラッシュ画面にペアレンタルする必要があります。スプラッシュ画面のHWNDをグローバル変数に割り当て、ダイアログのCreateParamsメソッドをオーバーライドします。グローバルHWNDに値がある場合、CreateParamsが渡すParams.WndParent変数にその値を代入します。異なるスレッドから来ているということは、VCLオブジェクトではなくHWNDを処理しているだけであり、Windowsは同期を処理します。

+0

アイデアありがとう。それは問題のダイアログが*コンポーネント*によって表示されているという事実を除いて、おそらくうまくいくでしょう。コンポーネントはスプラッシュスクリーンについて何も知らない。実際、コンポーネントを使用するほとんどのアプリケーションでスプラッシュ画面が表示されません。これは、かなりの数のテーブルを開くためです(UIの主な部分は、ルックアップフィールドとMasterSource/MasterFieldsを介して接続された他のテーブルを持つDBGridです)。したがって、コンポーネントはあまり変更できません。ダイアログのFormStyleをfsStayOnTopに変更しようとしましたが、何もしませんでした。 –

関連する問題