2012-10-23 15 views
6

Ho un componente di terze parti che visualizza un modulo di anteprima di stampa. Vorrei cambiare la didascalia del modulo di anteprima in qualcosa di più appropriato. Purtroppo non ho la fonte per il componente di terze parti e il componente non fornisce la funzionalità.Come posso modificare la didascalia di un modulo modale senza accesso alla fonte?

È possibile in qualche modo catturare il modulo modale mentre viene visualizzato e impostarne le proprietà prima che venga visualizzato?

+4

Solo un altro esempio del perché non si dovrebbero mai utilizzare componenti di terze parti per i quali non si dispone della fonte se esiste un'opzione disponibile per ottenerlo. :-) Puoi specificare quale componente di terze parti stai utilizzando, in modo che se esiste una soluzione nota relativa a quel set di componenti, qualcuno può fornirla. –

+2

@Ken: TeeChart. Potrei aggiornare la versione 'with source', ma è difficile giustificare un minimo di 250 dollari solo per cambiare la didascalia di un modulo: o) – norgepaul

+0

Il problema è che qualcosa cambia (o smettono di includere TeeChart nel prossimo versione di Delphi), tutto il codice che lo utilizza non può essere spostato alla versione successiva del compilatore. Se si dispone di codice che dipende da componenti di terze parti, è necessario disporre della fonte per proteggersi in futuro. È una delle primissime cose che dovresti imparare dopo aver imparato Delphi: l'architettura aperta è ottima per le estensioni di terze parti, ma usarle senza ingannare la fonte quando le cose cambiano in futuro e non puoi risolvere da soli i problemi. –

risposta

10

Il modulo modale causa la disattivazione del modulo di chiamata, è possibile ascoltare i messaggi WM_ACTIVATE nel modulo che è attivo prima che venga visualizzato il modulo modale. Avrai l'handle della finestra di attivazione nel gestore di messaggi, puoi testarlo se è di una forma del tipo del modulo modale. Sotto test di esempio per il nome della classe, che puoi ottenere con qualcosa come Spy ++. Si noti che la disattivazione avviene brevemente dopo che la forma modale è diventata visibile, ma non penso che sarebbe possibile notare la didascalia diversa.

type 
    TForm1 = class(TForm) 
    .. 
    protected 
    procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE; 
    end; 

procedure TForm1.WMActivate(var Message: TWMActivate); 
var 
    Form: TWinControl; 
begin 
    if Message.Active = WA_INACTIVE then begin 
    Form := FindControl(Message.ActiveWindow); 
    if Form is TCustomForm then begin 
     if TCustomForm(Form).ClassName = 'TThirdPartyModalForm' then 
     TCustomForm(Form).Caption := 'My caption'; 
    end; 
    end; 
    inherited; 
end; 
+1

Funziona perfettamente. Grazie Sertac. – norgepaul

+1

Che dire dell'utilizzo dell'evento 'TScreen.OnActiveFormChange' con la proprietà' TScreen.ActiveCustomForm' o 'TScreen.ActiveForm', invece di gestire' WM_ACTIVATE' direttamente e cercando il 'TForm' attivo? –

+0

@Remy - Viene attivato poco più tardi quando la forma modale viene attivata durante il cambio della messa a fuoco, dovrebbe andare bene. Ma FindControl è piuttosto veloce se questo è il problema, infatti viene chiamato durante Application.ProcessMessage con ogni messaggio in coda. –

2

È possibile installare un gancio WH_CBT utilizzando la funzione SetWindowsHookEx.

var 
hhk: HHOOK; 


function CBT_FUNC(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; 
const 
    ClassNameBufferSize = 1024; 
var 
hTemp : HWND; 
i  : Integer; 
RetVal : Integer; 
ClassNameBuffer: Array[0..ClassNameBufferSize-1] of Char; 
begin 
    case nCode of 
    HCBT_ACTIVATE: 
    begin 
     hTemp := HWND(wParam); 
     if (Screen<>nil) and (hTemp>0) then 
     begin 
      RetVal := GetClassName(wParam, ClassNameBuffer, SizeOf(ClassNameBuffer)); 
      //check for the class 
      if (RetVal>0) and SameText(ClassNameBuffer,'TForm2') then 
      begin 
      Assert(RetVal < ClassNameBufferSize, 'Class name larger than fixed buffer size'); 
      for i := 0 to Screen.FormCount-1 do 
      if Screen.Forms[i].Handle=hTemp then 
       begin 
        //set the caption 
        Screen.Forms[i].Caption:='Hello'; 
        Break; 
       end; 
      end; 
     end; 
    end; 
    end; 
    Result := CallNextHookEx(hhk, nCode, wParam, lParam); 
end; 

Procedure InitHook(); 
var 
    dwThreadID : DWORD; 
begin 
    dwThreadID := GetCurrentThreadId; 
    hhk := SetWindowsHookEx(WH_CBT, @CBT_FUNC, hInstance, dwThreadID); 
    if hhk=0 then RaiseLastOSError; 
end; 


Procedure KillHook(); 
begin 
    if (hhk <> 0) then 
    UnhookWindowsHookEx(hhk); 
end; 


initialization 
    InitHook(); 

finalization 
    KillHook(); 
end. 
2

Ecco un codice "pseudo" si potrebbe provare (non testato):

const 
    MY_PRINT_PREVIEW_MSG = WM_USER + 200; 

type 
    TForm1 = class(TForm) 
    procedure MyPrintPreviewMsg(var Msg: TMessage); message MY_PRINT_PREVIEW_MSG; 
    procedure MyPrintPreview; 
    end; 
... 
procedure TForm1.MyPrintPreviewMsg(var Msg: TMessage); 
var 
    h: HWND; 
begin 
    h := Screen.Forms[0].Handle; // if the modal dialog is VCL dialog (verify it with spy++) 
    // h := FindWindow(<class name>, <caption>); // non VCL window 
    if (h <> 0) then 
    begin 
    SetWindowText(h, 'new caption'); 
    end; 
end; 

procedure TForm1.MyPrintPreview; 
begin 
    PostMessage(Handle, MY_PRINT_PREVIEW_MSG, 0, 0); 
    ThirdPartyPrintPreview; 
end; 
6

Provare a utilizzare l'evento TScreen.OnActiveFormChange, utilizzando la proprietà TScreen.ActiveCustomForm o TScreen.ActiveForm per sapere quale TForm ha il focus:

procedure TMainForm.DoSomething; 
begin 
    Screen.OnActiveFormChange := ActiveFormChanged; 
    try 
    // do something that triggers the modal form ... 
    finally 
    Screen.OnActiveFormChange := nil; 
    end; 
end; 

procedure TMainForm.ActiveFormChanged(Sender: TObject); 
var 
    Form: TCustomForm; 
begin 
    Form := Screen.ActiveCustomForm; 
    if (Form <> nil) and (Form.ClassName = 'TModalFormClassName') then 
    Form.Caption := 'My caption'; 
end; 
Problemi correlati