windows - टास्कबार में सही तरीके से मॉडल तरीके कैसे दिखेंगे?



delphi windows-7 (1)

यह मुझे लगता है कि मूल समस्या यह है कि आपका मुख्य फ़ॉर्म, वीसीएल की आंखों में, आपका मुख्य रूप नहीं है एक बार जब आप इसे ठीक कर लें, तो सारी समस्याएं दूर चली जाती हैं

तुम्हे करना चाहिए:

  1. कॉल Application.CreateForm । वास्तविक फार्म के लिए वास्तव में एक बार फार्म करें। यह पालन करने के लिए एक अच्छा नियम है Application.CreateForm के काम पर विचार करें। Create Form अपने आवेदन का मुख्य फॉर्म बनाने के लिए।
  2. लॉगिन फॉर्म बनाएं और इसके WndParent को 0 सेट करें। यह सुनिश्चित करता है कि यह टास्कबार पर दिखाई देता है। फिर इसे modally दिखाएं
  3. Application.CreateForm को कॉल करके सामान्य तरीके से मुख्य फ़ॉर्म बनाएं। क्रेफ़फ़ॉर्म।
  4. सेट करने के लिए MainFormOnTaskbar को True
  5. WndParent फॉर्म के लिए WndParent 0 सेट करें।

और बस। यहां एक पूर्ण उदाहरण है:

Project1.dpr

program Project1;

uses
  Vcl.Forms,
  uMain in 'uMain.pas' {MainForm},
  uLogin in 'uLogin.pas' {LoginForm},
  uModeless in 'uModeless.pas' {ModelessForm};

{$R *.res}

begin
  Application.Initialize;
  Application.ShowHint := True;
  Application.MainFormOnTaskbar := True;
  with TLoginForm.Create(Application) do begin
    ShowModal;
    Free;
  end;
  Application.CreateForm(TMainForm, MainForm);
  Application.Run;
end.

uLogin.pas

unit uLogin;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs;

type
  TLoginForm = class(TForm)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

implementation

{$R *.dfm}

procedure TLoginForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.WndParent := 0;
end;

end.

uLogin.dfm

object LoginForm: TLoginForm
  Left = 0
  Top = 0
  Caption = 'LoginForm'
  ClientHeight = 300
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
end

uMain.pas

unit uMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, uModeless;

type
  TMainForm = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.Button1Click(Sender: TObject);
begin
  with TModelessForm.Create(Self) do begin
    Show;
  end;
end;

end.

uMain.dfm

object MainForm: TMainForm
  Left = 0
  Top = 0
  Caption = 'MainForm'
  ClientHeight = 300
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 288
    Top = 160
    Width = 75
    Height = 23
    Caption = 'Button1'
    TabOrder = 0
    OnClick = Button1Click
  end
end

uModeless.pas

unit uModeless;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TModelessForm = class(TForm)
    Label1: TLabel;
  protected
    procedure CreateParams(var Params: TCreateParams); override;
  end;

implementation

{$R *.dfm}

procedure TModelessForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.WndParent := 0;
end;

end.

uModeless.dfm

object ModelessForm: TModelessForm
  Left = 0
  Top = 0
  Caption = 'ModelessForm'
  ClientHeight = 300
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  ShowHint = True
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 312
    Top = 160
    Width = 98
    Height = 13
    Hint = 'This is a hint'
    Caption = 'I'#39'm a label with a hint'
  end
end

यदि आप बल्कि TModelessForm.CreateParams फॉर्म मुख्य रूप के स्वामित्व में होते हैं, तो आप इसे प्राप्त कर सकते हैं: TModelessForm.CreateParams को बदलकर:

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

मैं एक पुराना डेल्फी सपना हासिल करने की कोशिश कर रहा हूं, जिसमें एक मॉडेलसेशन फार्म टास्कबार में दिखाई देता है।

टास्कबार में एक मॉडल के रूप को दिखाने का सही तरीका क्या है?

अनुसंधान प्रयास

ये समस्या को सुलझाने का मेरा प्रयास है I इसे सही ढंग से व्यवहार करने के लिए बहुत सी चीजें जरूरी हैं - बस कार्यपट्टी पर एक बटन दिखाई देने पर समाधान नहीं होता है। विंडोज़ एप्लिकेशन के रूप में सही ढंग से व्यवहार करना विंडोज़ एप्लिकेशन होना चाहिए मेरा लक्ष्य।

जो लोग मुझे जानते हैं, और मेरे "शोध प्रयासों को दिखाता है" कितना गहरा हो जाता है, क्योंकि यह एक खरगोश छेद नीचे जंगली सवारी होगी

सवाल शीर्षक में है, साथ ही उपरोक्त क्षैतिज रेखा से ऊपर है। केवल नीचे दिखाए गए सब कुछ यह दिखाता है कि कुछ बार-बार किए गए सुझाव गलत क्यों हैं।

खिड़कियां केवल उजाड़ खिड़कियों के लिए टास्कबार बटन के रूप में बनाता है

प्रारंभ में मेरे पास मेरा "मेन फॉर्म" है , इस से मैं इस अन्य मॉडल को दिखाता हूं:

procedure TfrmMain.Button2Click(Sender: TObject);
begin
    if frmModeless = nil then
        Application.CreateForm(TfrmModeless, frmModeless);

    frmModeless.Show;
end;

यह सही ढंग से नया रूप दिखाता है, लेकिन कोई नया बटन टास्कबार पर नहीं दिखाई देता है:

कारण कोई टास्कबार बटन नहीं बनाया गया है क्योंकि यह डिज़ाइन द्वारा है। Windows केवल एक खिड़की के लिए एक टास्कबार बटन दिखाएगा जो "अनूठा" हो । यह मॉडल डेल्फी फॉर्म सबसे अधिक स्वामित्व वाली है । मेरे मामले में यह Application.Handle स्वामित्व में है। Application.Handle :

मेरा प्रोजेक्ट का नाम ModelessFormFail.dpr , जो कि मालिक के साथ जुड़े Windows वर्ग के नाम Modelessformfail का मूल है।

सौभाग्य से एक खिड़की के लिए एक टास्कबार बटन बनाने के लिए विंडोज को लागू करने का एक तरीका है, भले ही विंडो स्वामित्व है:

बस WS_EX_APPWINDOW उपयोग WS_EX_APPWINDOW

WS_EX_APPWINDOW एमएसडीएन दस्तावेज का कहना है:

WS_EX_APPWINDOW 0x00040000L विंडो दिखाई देने पर टास्कबार पर एक शीर्ष-स्तरीय विंडो को मजबूर 0x00040000L है।

यह CreateParams को ओवरराइड करने के लिए एक प्रसिद्ध डेल्फी चाल और मैन्युअल रूप से WS_EX_APPWINDOW शैली को WS_EX_APPWINDOW है:

procedure TfrmModeless.CreateParams(var Params: TCreateParams);
begin
    inherited;

    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; //force owned window to appear in taskbar
end;

जब हम इसे चलाते हैं, नव निर्मित मॉडलसे फॉर्म को वास्तव में अपना टास्कबार बटन मिलता है:

और हम कर रहे हैं? नहीं, क्योंकि यह सही ढंग से व्यवहार नहीं करता है

यदि उपयोगकर्ता frmMain टास्कबार बटन पर क्लिक करता है, तो उस विंडो को आगे नहीं लाया जाता है इसके बजाय अन्य रूप ( एफएमएमडलेस ) को आगे बढ़ाया गया है:

एक बार जब आप विंडोज़ की स्वामित्व की अवधारणा समझते हैं, तो यह समझ में आता है। विंडोज, डिज़ाइन द्वारा, किसी भी बच्चे के स्वामित्व वाले फॉर्म को अग्रेषित करेगा। यह स्वामित्व का पूरा उद्देश्य था - अपने स्वामियों के शीर्ष पर स्वामित्व वाले रूपों को रखने के लिए

फॉर्म को वास्तव में अनूठा बनाओ

समाधान, जैसा कि आप में से कुछ जानते हैं कि टास्कबार उत्थान और खिड़कियों के खिलाफ लड़ना नहीं है। यदि मुझे इस प्रपत्र को अकारण होना चाहिए, तो इसे अनूठा बनाएं

यह (काफी) सरल है CreateParam में CreateParam विंडो को null करने के लिए मजबूर करता है:

procedure TfrmModeless.CreateParams(var Params: TCreateParams);
begin
    inherited;

    //Doesn't work, because the form is still owned
//  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; //force owned windows to appear in taskbar

    //Make the form actually unonwed; it's what we want
    Params.WndParent := 0; //unowned. Unowned windows naturally appear on the taskbar.
          //There may be a way to simulate this with PopupParent and PopupMode.
end;

एक तरफ के रूप में, मैं PopupMode चाहता था कि PopupMode और PopupParent गुणों का उपयोग करने के लिए एक खिड़की PopupMode लिए एक रास्ता था मैं कसम खाता हूँ मैं एक टिप्पणी (आप से दाऊद) पर कहीं कह रही है कि अगर आप PopupParent रूप में Self पारित, जैसे:

procedure TfrmMain.Button1Click(Sender: TObject);
begin
    if frmModeless = nil then
    begin
        Application.CreateForm(TfrmModeless, frmModeless);
        frmModeless.PopupParent := frmModeless; //The super-secret way to say "unowned"? I swear David Heffernan mentioned it somewhere on SO, but be damned if i can find it now.
        frmModeless.PopupMode := pmExplicit; //happens automatically when you set a PopupParent, but you get the idea
    end;

    frmModeless.Show;
end;

यह डेल्फी को इंगित करने का सुपर-गुप्त तरीका माना जाता था कि आप "कोई स्वामी नहीं" बनाने के लिए बनाना चाहते हैं लेकिन मुझे अब कहीं भी टिप्पणी नहीं मिली है। दुर्भाग्य से, PopupParent और PopupMode का कोई संयोजन वास्तव में संयुक्त राष्ट्र के स्वामित्व में नहीं है:

  • पॉपअपमोड: pmNone
    • स्वामी एचडब्ल्यूडी: Application.Handle/Application.MainForm.Handle हेंडल Application.Handle/Application.MainForm.Handle
  • पॉपअपमोड: pmAuto
    • स्वामी Screen.ActiveForm.Handle : Screen.ActiveForm.Handle
  • पॉपअपमोड: pmExplicit
    • पॉपअप जनक: शून्य
      • स्वामी एचवीएनडी: आवेदन.मैनफॉर्म.हैंडल
    • पॉपअप जनक: AForm
      • स्वामी AForm.Handle : AForm.Handle
    • पॉपअपपारेंट: स्वयं
      • स्वामी एचवीएनडी: आवेदन.मैनफॉर्म.हैंडल

मैं जो कुछ भी कर सकता हूं वह वास्तव में कोई स्वामी नहीं हो सकता (प्रत्येक बार जासूस ++ के साथ जांच कर रहा है)

WndParent दौरान मैन्युअल रूप से WndParent सेटिंग:

  • प्रपत्र को अयोग्य बना देता है
  • इसमें एक टास्कबार बटन है
  • और दोनों टास्कबार बटन सही ढंग से व्यवहार करते हैं:

और हम कर चुके हैं, है ना? मुझे ऐसा लगा। मैंने इस नई तकनीक का उपयोग करने के लिए सब कुछ बदल दिया।

मेरे फिक्स के साथ समस्याओं को छोड़कर अन्य समस्याएं पैदा हो सकती हैं - डेल्फी ने मुझे एक फॉर्म के स्वामित्व में बदलना पसंद नहीं किया।

संकेत विंडोज

मेरी मॉडल खिड़की पर नियंत्रण में से एक में टूलटॉप है:

समस्या यह है कि जब यह टूलटिप विंडो प्रकट होती है, तो यह आगे आने के लिए अन्य फॉर्म ( एफएमएमइन , मोडल वन) का कारण बनता है। यह सक्रियण फ़ोकस प्राप्त नहीं करता है; लेकिन यह अब जिस तरह से मैं देख रहा था अस्पष्ट था:

कारण शायद तर्कसंगत है डेल्फी हिंटवंडो का या तो Application.Handle द्वारा स्वामित्व है। हंडल या Application.MainForm.Handleमेनफॉर्म.हाण्डल , उस प्रपत्र के स्वामित्व में रहने के बजाय, जिसका स्वामित्व होना चाहिए:

मैं इसे डेल्फी के भाग पर एक बग मानता। गलत मालिक का उपयोग कर

वास्तविक ऐप लेआउट देखने के लिए मोड़

अब यह ज़रूरी है कि मैं यह दिखाने के लिए एक क्षण लेता हूं कि मेरा आवेदन एक मुख्य रूप और एक मॉडल स्वरूप नहीं है:

यह वास्तव में है:

  • एक लॉगिन स्क्रीन (एक बलि के मुख्य स्वरूप जो छुपा हो जाता है)
  • एक मुख्य स्क्रीन
  • एक मंडल नियंत्रण कक्ष
  • जो मॉडलसे फॉर्म को दर्शाता है

एप्लिकेशन लेआउट की वास्तविकता के साथ भी, हिंट विंडो स्वामित्व को छोड़कर सब कुछ काम करता है। दो टास्कबार बटन हैं, और उन पर क्लिक करने से उचित फॉर्म लाया जा सकता है:

लेकिन हम अभी भी हिंटवंडो के स्वामित्व की समस्या को गलत रूप से आगे बढ़ाए हैं:

ShowMainFormOnTaskbar

यह तब था जब मैं समस्या का पुनरुत्पादन करने के लिए एक न्यूनतम एप्लिकेशन बनाने का प्रयास कर रहा था जब मुझे पता चला कि मैं नहीं कर सकता था। कुछ अलग था:

  • मेरे डेल्फी 5 एप्लिकेशन के बीच XE6 को पोर्ट किया गया
  • XE6 में एक नया एप्लिकेशन बनाया गया

सब कुछ की तुलना करने के बाद, मैं अंत में यह पता लगाया कि XE6 में नए अनुप्रयोगों में मेनफॉर्मऑनटैस्कबार जोड़ता है MainFormOnTaskbar := True किसी भी नई परियोजना में डिफ़ॉल्ट रूप से (संभवतः मौजूदा अनुप्रयोगों को तोड़ने के लिए नहीं):

program ModelessFormFail;
//...
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TfrmSacrificialMain, frmSacrificialMain);
  //Application.CreateForm(TfrmMain, frmMain);
  Application.Run;
end.

जब मैंने यह विकल्प जोड़ा, तो टूलटिप का स्वरूप गलत रूप से आगे नहीं आया!

सफलता! सिवाय, जो लोग जानते हैं कि क्या आ रहा है पता है कि क्या आ रहा है । मेरा "बलि" मुख्य लॉगिन फॉर्म "असली" मुख्य रूप दिखाता है, जो खुद को छुपाता है:

procedure TfrmSacrificialMain.Button1Click(Sender: TObject);
var
    frmMain: TfrmMain;
begin
    frmMain := TfrmMain.Create(Application);
    Self.Hide;
    try
        frmMain.ShowModal;
    finally
        Self.Show;
    end;
end;

जब ऐसा होता है, और मैं "लॉगिन" करता हूं, तो मेरा टास्कबार आइकन पूरी तरह से निराश करता है:

ऐसा इसलिए होता है क्योंकि:

  • गैर स्वामित्व वाली बलि के मुख्य स्वरूप अदृश्य नहीं है: इसलिए बटन इसके साथ चला जाता है
  • वास्तविक मुख्य प्रपत्र स्वामित्व है, इसलिए उसे टूलबार बटन नहीं मिलता है

WS_APP_APPWINDOW का उपयोग करें

अब हमारे पास WS_EX_APPWINDOW का उपयोग करने का अवसर है। मैं अपने मुख्य फॉर्म को मजबूर करना चाहता हूं, जो कि स्वामित्व है, टास्कबार पर दिखाई देता है। इसलिए मैं CreateParams ओवरराइड और इसे टास्कबार पर प्रकट करने के लिए मजबूर करता CreateParams :

procedure TfrmMain.CreateParams(var Params: TCreateParams);
begin
    inherited;

    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW; //force owned window to appear in taskbar
end;

और हम इसे एक चक्कर दे:

बहुत अच्छा लग रहा है!

  • दो टास्कबार बटन
  • टूलटिप गलत स्वामी के फार्म को अग्रेषित नहीं करता है

सिवाय, जब मैं पहली टूलबार बटन पर क्लिक करता हूं, तो गलत फॉर्म ऊपर आता है। यह वर्तमान मोडल frmControlPanel के बजाय, मोडल frmMain दिखाता है :

संभवतः क्योंकि नवनिर्मित frmControlPanel को पॉपअप के लिए आवेदन किया गया था। स्क्रीन के बजाय मुख्य फर्कसक्रियफ़ॉर्म । जासूस ++ में जांचें:

हां, माता-पिता MainForm.Handle यह वीसीएल में एक और बग की वजह से निकला है यदि फ़ॉर्म का PopupMode है:

  • pmAuto
  • pmNone (यदि यह एक मॉडल फॉर्म है)

वीसीएल Application.ActiveFormHandle का उपयोग करने का प्रयास करता है। hWndParent को hWndParent रूप में दुर्भाग्य से यह तो जांचता है कि क्या मॉडल फॉर्म का अभिभावक सक्षम है:

if (WndParent <> 0) and (
      IsIconic(WndParent) or 
      not IsWindowVisible(WndParent) or
      not IsWindowEnabled(WndParent)) then

बेशक, मोडल फॉर्म के माता-पिता सक्षम नहीं हैं। अगर ऐसा होता है, तो यह एक मौलिक रूप नहीं होगा। तो वीसीएल का उपयोग करने के लिए वापस आ जाता है:

WndParent := Application.MainFormHandle;

मैनुअल पेरेंटिंग

इसका मतलब है कि मुझे मैन्युअल रूप से (?) पॉपअप पेरेंटिंग सेट करना है?

procedure TfrmMain.Button2Click(Sender: TObject);
var
    frmControlPanel: TfrmControlPanel;
begin
    frmControlPanel := TfrmControlPanel.Create(Application);
    try
        frmControlPanel.PopupParent := Self;
        frmControlPanel.PopupMode := pmExplicit; //Automatically set to pmExplicit when you set PopupParent. But you get the idea.
        frmControlPanel.ShowModal;
    finally
        frmControlPanel.Free;
    end;
end;

सिवाय इसके कि या तो काम नहीं किया। पहले टास्कबार बटन पर क्लिक करने से गलत फॉर्म सक्रिय होता है:

इस समय मैं पूरी तरह से भ्रमित हूँ मेरे मॉडल फॉर्म के माता-पिता को फ्रॉम मैन होना चाहिए, और यह है!

तो अब क्या?

मुझे पता चल गया है कि क्या हो रहा है।

यह टास्कबार बटन frmMain का एक प्रतिनिधित्व है। विंडोज़ आगे बढ़ने के लिए ला रहा है

सिवाय इसके कि वह सही तरीके से व्यवहार करता है जब MainFormOnTaskbar को झूठी पर सेट किया गया था।

डेल्फी वीसीएल में कुछ जादू होना चाहिए जो इससे पहले सही हो गया, लेकिन मेनफॉर्मऑनटैस्कबार के साथ निष्क्रिय हो गया : = सत्य , लेकिन यह क्या है?

मैं पहले व्यक्ति नहीं हूं जो डेल्फी आवेदन को विंडोज 95 टूलबार के साथ अच्छी तरह व्यवहार करने के लिए चाहता हूं। और मैंने इस प्रश्न को अतीत में पूछा है, लेकिन उन उत्तर हमेशा डेल्फी 5 की दिशा में तैयार थे और यह पुरानी केंद्रीय मार्ग विंडो है

मुझे बताया गया है कि डेल्फी 2007 समय-सीमा के आसपास सब कुछ ठीक हो गया था।

तो सही समाधान क्या है?

बोनस रीडिंग





windows-95