2012-09-19 69 views
5

Devo visualizzare un valore "mascherato" modificato in un TDBGrid VCL (Delphi XE2), vale a dire: cambiare "password" in "xxxxxxxx" o "passaggio" maiuscolo in "PASS" o altri. Come i miei Campi sono creati dinamicamente (ma il Nome è codificato quindi so come e quando li maschera cioè: xxxx_PASSW per i campi password) Non posso usare l'evento OnGetText (I Think).Come modificare un valore di cella in Delphi TDBGrid

Quindi qual è il modo più efficiente per farlo (dato che utilizzo ancora OnDrawColumnCell per alcune modifiche alla presentazione, preferirei utilizzarlo)?

+0

Ci sono 3 modi per farlo. 1. Creare un campo calcolato per la password sul set di dati utilizzato da dbgrid. 2. Creare un campo calcolato per la password nell'istruzione select di sql. o 3. utilizzare l'evento onDrawColumCell/Data di dbgrid, come indicato sopra. Ma personalmente mi piace NON memorizzare la password nel database, ma la versione codificata della password. Poiché il codice hash è una funzione unidirezionale (ovvero non è possibile ottenere la password originale dal codice hash) e solo la password corretta può produrre lo stesso codice hash, è più sicuro da usare.] – Hendra

+0

@ Hendra Sure, la password è stata un esempio, i miei bisogni sono troppo complicati per spiegare chiaramente. Ma so come cambiare la presentazione di una cella, con onDrawColumCell, ma non il contenuto del testo, nessun esempio o tuto? – philnext

risposta

10

Ci sono almeno 3 modi per farlo, illustrerò mascherando un campo password da un database. Sto usando SQL Server per il dialetto SQL.

1. Definire un campo calcolato sulla stringa sql.

select field1, field2, '********' as maskedPwd from table1; 

Poi, fare clic destro sul DBGrid, scegliete l'editor colonne. All'interno dell'editor delle colonne di dbgrid, è sufficiente selezionare la colonna maskedPwd invece della colonna della password reale. Ora il dbgrid mostrerà il valore mascherato invece della password.

o

2. Definire un campo calcolato sul set di dati utilizzata dal DBGrid.

Fare semplicemente clic con il pulsante destro del mouse sul set di dati e utilizzare l'editor campi per creare un nuovo campo calcolato (ad esempio maskedPwd2). Poi onCalcField evento del set di dati, scrivere il codice per impostare il valore di maskedPwd2, vale a dire

procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet); 
begin 
    DataSet.FieldByName('maskedPwd2').AsString := '********'; 
end; 

assicurarsi di includere maskedPwd2 nell'editor colonna della DBGrid.

o

3. Scrivere il testo personalizzato sull'evento onDrawColumnCell della DBGrid.

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; 
    DataCol: Integer; Column: TColumn; State: TGridDrawState); 
var 
    grid : TDBGrid; 
    maskValue : String; 
    aRect : TRect; 
begin 
    maskValue := '********'; 
    aRect := Rect; 
    grid := sender as TDBGrid; 

    if column.FieldName = 'password' then 
    begin 
    grid.Canvas.FillRect(Rect); 
    DrawText(grid.Canvas.Handle, PChar(maskValue), Length(maskValue), aRect, 
     DT_SINGLELINE or DT_LEFT or DT_VCENTER); 
    end; 
end; 

Si noti che il codice di cui sopra solo la visualizzazione del valore mascherato, ma se la griglia è modificabile, il valore della password vera e propria sarà visibile quando la cellula si concentra/modificato.

Per risolvere questo problema, rilascia un TEdit nel modulo, deseleziona la proprietà text, imposta la proprietà PpasswordChar su "*" e visibile su false. Ora è pronto per essere utilizzato come sostituto dell'editor integrato per la cella. Ora, abbiamo bisogno di una logica di incollaggio, vale a dire

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect; 
    DataCol: Integer; Column: TColumn; State: TGridDrawState); 
var 
    grid : TDBGrid; 
    maskValue : String; 
    aRect : TRect; 
begin 
    maskValue := '********'; 
    aRect := Rect; 
    grid := sender as TDBGrid; 

    if column.FieldName = 'password' then 
    if gdfocused in State then 
     begin 
     Edit1.Left := Rect.Left + grid.Left + 1; 
     Edit1.Top := rect.Top + grid.Top + 1; 
     Edit1.Width := Rect.Right - Rect.Left + 2; 
     Edit1.Height := Rect.Bottom - Rect.Top + 2; 
     Edit1.Clear; 
     Edit1.Visible := True; 
     end 
    else 
     begin 
     grid.Canvas.FillRect(Rect); 
     DrawText(grid.Canvas.Handle, PChar(maskValue), Length(maskValue), aRect, 
      DT_SINGLELINE or DT_LEFT or DT_VCENTER); 
     end 
    else 
    grid.DefaultDrawColumnCell(Rect, DataCol, Column, state); 
end; 

procedure TForm1.DBGrid1ColExit(Sender: TObject); 
begin 
    Edit1.Visible := False; 
end; 

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char); 
begin 
    if Key = Chr(9) then Exit; 

    if (Sender as TDBGrid).SelectedField.FieldName = 'password' then 
    begin 
    Edit1.SetFocus; 
    SendMessage(Edit1.Handle, WM_CHAR, word(Key), 0); 
    end; 
end; 

procedure TForm1.Edit1Change(Sender: TObject); 
begin 
    if DBGrid1.DataSource.State in [dsEdit, dsInsert] then 
    DBGrid1.DataSource.DataSet.FieldByName('password').AsString := Edit1.Text; 
end; 

procedure TForm1.Edit1Enter(Sender: TObject); 
begin 
    DBGrid1.DataSource.Edit; 
end; 

Si noti che il codice di cui sopra non è perfetto, ancora, ma l'essenza è lì. Lo lascerò a te per l'esercizio.

+0

Risposta chiara e completa. – philnext

6

vorrei scrivere un OnGetText per il campo password nel dataset, come valore del campo non deve essere visualizzato in qualsiasi controllo a tutti

+0

Certo ma la mia domanda non era completa (mi dispiace), i miei DBGrid sono creati dinamicamente e potrei avere diversi TField così come non posso assegnare OnGetText. Invece ho OnDrawColumnCell. – philnext

+0

Non l'ho mai provato. Immagino che si possa usare questo: 'con (Sender come TDBGrid) .Canvas inizia Font.Color: = clWhite; Brush.Color: = clWhite; Brush.Style: = bsSolid; fine; 'per nascondere il valore desiderato, ma non sono sicuro di come modificare il testo attuale di un campo. Non sarebbe più facile assegnare uno 'OnGetText' a diversi' TField's? –

+0

Ora capisco perché non è possibile utilizzare 'OnGetText', ma è possibile assegnare facilmente lo stesso colore a' font' e 'brush' in' OnDrawColumnCell' per la colonna _password_. –

2

Avete mascherare tutti i valori di un'intera colonna? In tal caso, se si conosce a cosa serve TField (o fieldname): provare a creare dinamicamente un campo calcolato con i valori modificati e visualizzarlo nella colonna.

+0

Puoi essere più preciso? – philnext

+0

Non ho il tempo di elaborare un esempio. Nel momento in cui crei i TField che richiedono il masking, aggiungi anche TFields.Add per aggiungere un campo calcolato. Passare attraverso TDBGrid.Columns, sostituire il campo utilizzato da quella colonna. Devi anche collegare un gestore di eventi di OnCalcFields al tuo set di dati, ovviamente (forse ne hai già uno). Spero che questo ti possa iniziare. –

+0

Più chiaro grazie. – philnext

1

Modificare il codice precedente per mostrare e nascondere la password. Se l'utente fa clic sulla cella Password lo mostrerà, quando farà clic sulla cella lo nasconderà di nuovo.

// Add a cell click event from the TDBGrid 
procedure TForm1.DBGrid1CellClick(Column: TColumn); 
begin 
if DBGrid1.SelectedField.FieldName = 'password' then 
Edit1.Text := Your_Table_Name.FieldByName('password').AsString; 
Edit1.PasswordChar:=#0; 
end; 

// Change the edit1change event to this 
procedure TForm1.Edit1Change(Sender: TObject); 
begin 
if DBGrid1.DataSource.State in [dsEdit, dsInsert] then 
Your_Table_Name.FieldByName('password').AsString := Edit1.Text; 
Edit1.PasswordChar:=#0; 
end; 

// You should change colexit event to read like this 
procedure TForm1.DBGrid1ColExit(Sender: TObject); 
begin 
if DBGrid1.SelectedField.FieldName = 'password' then 
Edit1.Visible := False; 
end; 

non ci volle molto lavoro per farne un campo password fresco.

Hai dimenticato una cosa nell'evento Cella colonna di Draw DBGrid, devi modificare Edit1.Clear; to Edit1.Text: = Your_Table_Name.FieldByName ('Password'). AsString;