2012-06-23 14 views
7

miei Delphi-7 applicazione visualizza:Utilizzando tscreen in Delphi 7

Screen.DesktopWidth 
Screen.DesktopHeight 
Screen.Monitors[0].Width 
Screen.Monitors[0].Height 

e, se c'è un secondo monitor selezionato, anche:

Screen.Monitors[1].Width 
Screen.Monitors[1].Height 

Con l'applicazione in esecuzione sul mio WinXP-Pro PC , Vado su Pannello di controllo/Display/Impostazioni e cambio le impostazioni per il secondo monitor (aggiungilo o rimuovilo).

Quindi faccio clic su un pulsante Aggiorna per visualizzare i nuovi valori dei 4 (o 6) parametri e succede qualcosa di inaspettato: Screen.DesktopWidth e Screen.DesktopHeight mostrano i nuovi valori corretti, ma i valori degli altri 2 (o 4) i parametri sono molto sbagliati.

Come Screen.Monitors [0] .Width = 5586935, mentre dovrebbe essere 1680.

Esistono alcune regole speciali per l'utilizzo di TScreen in Delphi 7?

+1

Non riesco a simularlo dato che ho un monitor e Delphi 2009 ma suppongo che il problema potrebbe essere con l'aggiornamento dell'elenco dei monitor (in Delphi 2009 questo viene eseguito tramite la procedura privata 'Screen.GetMonitors'). Immagino che ottieni i valori corretti quando riavvii la tua applicazione, vero? E se ricordo bene, forse Sertac ha scritto da qualche parte che è sicuro distruggere l'istanza di 'Screen' e crearla di nuovo. E se è così, allora il seguente dovrebbe aggiornare questi dati 'Screen.Free; Screen: = TScreen.Create (nil); ', ma davvero non so quanto sia sicura questa azione. – TLama

+0

Stai prendendo un riferimento all'istanza di TMonitor Screen.Monitors [0] o ricevi Screen.Monitors [0] ogni volta? –

+0

@TLama "Immagino di avere i valori corretti quando riavvii l'applicazione, vero?" Giusto . E ottengo anche i valori corretti quando c'è una dichiarazione ShowMessage solo ** prima ** le istruzioni che mostrano i 4 (o 6) parametri. – AthenaAtDelphi

risposta

0

Grazie a TLama, ho trovato un modo per risolvere il problema di TScreen in Delphi 7.

Il codice originale che 'causato' il problema:

LabMon1.Caption := ' Mon 1: ' + IntToStr (Screen.Monitors[0].Width) + 
        ' x ' + IntToStr (Screen.Monitors[0].Height); 

if (Screen.MonitorCount = 1) 
then LabMon2.Caption := ' Mon 2: -' 
else LabMon2.Caption := ' Mon 2: ' + IntToStr (Screen.Monitors[1].Width) + 
         ' x ' + IntToStr (Screen.Monitors[1].Height); 

ho avuto solo aggiungere 1 riga di codice per risolverlo:

LabMon1.Caption := ' Mon 1: ' + IntToStr (Monitor.Width) + 
        ' x ' + IntToStr (Monitor.Height) ; 

LabMon1.Caption := ' Mon 1: ' + IntToStr (Screen.Monitors[0].Width) + 
        ' x ' + IntToStr (Screen.Monitors[0].Height); 

if (Screen.MonitorCount = 1) 
then LabMon2.Caption := ' Mon 2: -' 
else LabMon2.Caption := ' Mon 2: ' + IntToStr (Screen.Monitors[1].Width) + 
         ' x ' + IntToStr (Screen.Monitors[1].Height); 

Quindi grazie ancora TLama, per la vostra grandi contributi a questa discussione di domande!

+2

Prego! In realtà, non è necessario utilizzare 'Monitor.Width' o' Monitor.Height' o assegnare i loro valori da qualche parte. È sufficiente * toccare * la proprietà ['Monitor'] (http://docwiki.embarcadero.com/Libraries/en/Vcl.Forms.TCustomForm.Monitor) il cui getter aggiorna l'elenco' Screen.Monitors' quando l'handle del monitor principale non si trova in quella lista. L'ho usato solo per il controllo della larghezza. Se sei fortunato e il compilatore non elimina tale affermazione, potrebbe essere sufficiente usare solo "Monitor": cosa potrebbe costringere il getter a fare ciò che ho descritto. Comunque in qualche modo è ancora sporco. – TLama

0

La stessa cosa accade se si cambia utente durante l'esecuzione del programma. Dopo aver cambiato l'array Screen.Monitors contengono valori non validi. Usiamo questa riga di codice

Screen.MonitorFromWindow(0, mdNull); 

per forzare l'oggetto Schermo ad aggiornare gli elenchi.

0

È venuto qui a causa del problema di aggiornamento (bug) di TScreen quando si collega o scollega un monitor o un dispositivo di visualizzazione USB. La risposta di @ Dave82 non funziona per me. Il risultato della funzione MonitorFromWindow deve restituire un altro valore (valore sconosciuto/non valido) per forzare un aggiornamento dell'oggetto TScreen.

Questo trucco sotto fa il trucco:

Assicurarsi MultiMon è nel utilizza clausola:

uses 
multimon; 

Aggiungere questo alla parte interfaccia (della forma)

protected 
procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE; 

Aggiungi a implementazione parte (del modulo)

function cheatMonitorFromWindow(hWnd: HWND; dwFlags: DWORD): HMONITOR; stdcall; 
    begin 
     // Does nothing, returns zero to force invalidate 
    Result:=0; 
    end; 

    procedure TForm1.WMDeviceChange(var Msg: TMessage); 
    var 
    iCurrDisplayCount : LongInt; 
    iNewDisplayCount  : LongInt; 
    pMonitorFromWinProc : TMonitorFromWindow; 

    begin 
    iCurrDisplayCount:=Screen.MonitorCount; 
    // Force monitor update, fix bug in customform, won't update at display change. 
    // This a hack/cheat to multimon MonitorFromWindow func, it's fakes the result. 
    // This is required to tell customform.getMonitor() to update the TScreen object. 
    pMonitorFromWinProc:=MonitorFromWindow;  // Backup pointer to dynamic assigned DLL func 
    MonitorFromWindow:=cheatMonitorFromWindow; // Assign cheat func 
    monitor;          // call the monitor property that calls customform.getMonitor and cheatfunc 
    MonitorFromWindow:=pMonitorFromWinProc;  // restore the original func 
    // ========== 
    iNewDisplayCount:=Screen.MonitorCount; 
    if(iCurrDisplayCount <> iNewDisplayCount) then 
    begin 
     // Display count change! 
    end; 
end; 

Cosa succede all'interno di customform (codice in Forms.pas)?

function TCustomForm.GetMonitor: TMonitor; 
var 
    HM: HMonitor; 
    I: Integer; 
begin 
    Result := nil; 
    HM := MonitorFromWindow(Handle, MONITOR_DEFAULTTONEAREST); 
    for I := 0 to Screen.MonitorCount - 1 do 
    if Screen.Monitors[I].Handle = HM then 
    begin 
     Result := Screen.Monitors[I]; 
     Exit; 
    end; 

    //if we get here, the Monitors array has changed, so we need to clear and reinitialize it 
    for i := 0 to Screen.MonitorCount-1 do 
    TMonitor(Screen.FMonitors[i]).Free; 
    Screen.FMonitors.Clear; 
    EnumDisplayMonitors(0, nil, @EnumMonitorsProc, LongInt(Screen.FMonitors)); 
    for I := 0 to Screen.MonitorCount - 1 do 
    if Screen.Monitors[I].Handle = HM then 
    begin 
     Result := Screen.Monitors[I]; 
     Exit; 
    end;  
end; 

Le speranze sono utili quando qualcuno lo sta cercando. Quando si desidera rilevare le modifiche alle impostazioni del dispositivo di visualizzazione (risoluzione e orientamento), prendere invece l'evento WM_DISPLAYCHANGE.