تنشيط Windows متعدد التطبيقات لا يعمل بشكل صحيح
سؤال
لدي تطبيق Delphi يحتوي على متصفح مستند كنموذج رئيسي. عندما يفتح المستخدم مستندًا ، نفتح نافذة محرر. نريد أن يكون كل محرر مع زر على شريط المهام ، وكذلك النموذج الرئيسي. لقد قمت بتطبيق الكود العادي للقيام بذلك (أدناه) ، ولكن عندما أنقر على النموذج الرئيسي بعد استخدام نافذة المحرر ، يتم ترك المحرر في الأعلى ، بينما يكون التركيز على النموذج الرئيسي. أنا غير قادر على معرفة ما يسبب هذا السلوك.
إعداد المرحلة: أفتح النموذج الرئيسي ونموذج المستند.
انقر على تطبيق آخر ، انقر فوق النموذج الرئيسي ، يبقى النموذج الرئيسي مركّزًا. (يتصرف كما هو متوقع.)
انقر فوق نموذج المستند ، انقر فوق النموذج الرئيسي ، ويعود نموذج المستند إلى الأمام ، ولكنه يظهر غير نشط. (تظهر الصورة نتيجة)
alt text http://www.matthew-jones.com/temp_xfer/titlebarfailure.jpg
الخطوة الأولى ، هذه هي Delphi 2007 ، ولدي في المشروع:
Application.MainFormOnTaskBar := True;
للنموذج الرئيسي ، ليس لدي رمز إضافي.
لنموذج المستند ، لدي
procedure TCommonEditForm.CreateParams(var params: TCreateParams);
begin
inherited;
params.WndParent := 0; // GetDeskTopWindow; no diff
end;
لقد حاولت العمل إذا كانت هناك رسالة تجعل هذا يحدث ، لكن لا يمكنني تحديد موقع أي شيء مناسب. لقد بحثت في الرمز عن أي شيء يتعلق بـ "Activate". القرائن ترحيب!
المحلول
يعمل طلبي في الطريقة التي تصف بها. هنا هو النهج الذي اتبعته. كنت أرغب في العثور على نهج أبسط ولكن لم أفعل.
لقد بدأت بقراءة هذه المقالات. هذا الأول هو كتابة رائعة من قبل بيتر أدناه:
http://groups-beta.google.com/group/borland.public.delphi.winapi/msg/e9f75ff48ce960eb؟hl=en
تم العثور على معلومات أخرى هنا أيضًا ، ولكن هذا لم يثبت أنه حل صالح: لاستخدامي: http://blogs.teamb.com/deepakshenoy/archive/2005/04/26/4050.aspx
في النهاية ، هذا ما انتهى بي.
تتضاعف شاشة البداية الخاصة بي كنموذج رئيسي للتطبيق. النموذج الرئيسي لديه ربطة عنق خاصة لكائن التطبيق. استخدام جميع النماذج الثانوية يجعلني السلوك الذي كنت أبحث عنه.
في كل نموذج أريده في شريط المهام ، أتجاوز CreateParams. أفعل ذلك على نماذج التحرير الخاصة بي وما يراه المستخدمون "النموذج الرئيسي"
procedure TUaarSalesMain.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := GetDesktopWindow;
end;
نموذج "الرئيسي" بقدر ما يتعلق الأمر بـ Delphi يحمل النموذج الرئيسي الحقيقي في وظيفة النشاط. يمكنني استخدام متغير عضو لتتبع التنشيط الأول. ثم في نهاية الوظيفة ، أخفي نموذج البداية ، لكن لا تغلقه. كان هذا مهمًا بالنسبة لي لأنه إذا كان المستخدم يقوم بتحرير مستند وأغلق النموذج الرئيسي ، لم أكن أرغب في إغلاق شاشات التحرير في نفس الوقت. بهذه الطريقة يتم التعامل مع جميع النماذج المرئية كما هي.
if FFirstActivate = false then
exit;
FFristActivate := false;
/*
Main Load code here
Update Splash label, repaint
Application.CreateForm
etc.
*/
// I can't change visible here but I can change the size of the window
Self.Height := 0;
Self.Width := 0;
Self.Enabled := false;
// It is tempting to set Self.Visible := false here but that is not
// possible because you can't change the Visible status inside this
// function. So we need to send a message instead.
ShowWindow(Self.Handle, SW_HIDE);
end;
ولكن لا تزال هناك مشكلة. تحتاج إلى إغلاق نافذة Main/Splash عند إغلاق جميع النماذج الأخرى. لديّ فحص إضافي في إجراءات الإغلاق الخاصة بي لـ Parent <> nil لأنني أستخدم النماذج كإضافات (تشكل أغراض بلدي تعمل بشكل أفضل من الإطارات).
لم يعجبني حقًا استخدام حدث الخمول ، لكنني لا ألاحظ أن هذا السحب على وحدة المعالجة المركزية.
{
TApplicationManager.ApplicationEventsIdle
---------------------------------------------------------------------------
}
procedure TApplicationManager.ApplicationEventsIdle(Sender: TObject;
var Done: Boolean);
begin
if Screen.FormCount < 2 then
Close;
end;
{
TApplicationManager.FormCloseQuery
---------------------------------------------------------------------------
}
procedure TApplicationManager.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
var
i: integer;
begin
for i := 0 to Screen.FormCount - 1 do
begin
if Screen.Forms[i] <> self then
begin
// Forms that have a parent will be cleaned up by that parent so
// ignore them here and only attempt to close the parent forms
if Screen.Forms[i].Parent = nil then
begin
if Screen.Forms[i].CloseQuery = false then
begin
CanClose := false;
break;
end;
end;
end;
end;
end;
{
TApplicationManager.FormClose
---------------------------------------------------------------------------
}
procedure TApplicationManager.FormClose(Sender: TObject;
var Action: TCloseAction);
var
i: integer;
begin
for i := Screen.FormCount - 1 downto 0 do
begin
if Screen.Forms[i] <> self then
begin
// Forms that have a parent will be cleaned up by that parent so
// ignore them here and only attempt to close the parent forms
if Screen.Forms[i].Parent = nil then
begin
Screen.Forms[i].Close;
end;
end;
end;
end;
لقد خدمني هذا جيدًا حتى الآن. قمت بإجراء تغيير بسيط لـ Vista لأن أيقونة شاشة "Main/Splash" الخاصة بي كانت لا تزال تظهر. لا أتذكر ما كان عليه. ربما لا أحتاج إلى ضبط العرض والارتفاع والتمكين وإرسال رسالة إخفاء على شاشة الرش. أردت فقط التأكد من عدم ظهوره :-).
كان التعامل مع الأحداث القريبة ضروريًا. إذا كنت أتذكر ذلك بشكل صحيح ، كان هناك حاجة إلى عندما أرسل Windows رسالة إيقاف التشغيل. أعتقد فقط أن النموذج الرئيسي يحصل على هذه الرسالة.
نصائح أخرى
آسف إذا كان هذا غبيًا حقًا ، لكن ليس لديك مجموعة Formstyle على FSStayontop ، أليس كذلك؟ هذا من شأنه أن يفسر هذا السلوك.
ربما أضف هذا في CreateParams
Params.ExStyle := Params.ExStyle OR WS_EX_APPWINDOW;
أو جرب هذا في أي مكان في الكود. أنا أستخدمه في وقت سابق على النماذج. الحدث.
SetWindowLong(Wnd, GWL_EXSTYLE,
GetWindowLong(Wnd, GWL_EXSTYLE) or WS_EX_APPWINDOW) ;
الجانب السلبي من هذا هو أنه إذا تم تقليل النموذج الرئيسي إلى الحد الأدنى من النماذج الأخرى ، فهي تخفي Aswell ، ولكن استعد عندما يكون النموذج الرئيسي.