2012-09-19 276 views
5

Tengo que mostrar algún valor 'enmascarado' modificado en un VCL TDBGrid (Delphi XE2), es decir: cambiar 'contraseña' a 'xxxxxxxx' o 'pasar' en mayúscula a 'PASE' u otras personas. Como mis campos están dinámicamente creados (pero el nombre está codificado, sé cómo y cuándo ocultarlos, por ejemplo: xxxx_PASSW para campos de contraseña) No puedo usar el evento (Creo que) OnGetText.Cómo modificar un valor de celda en Delphi TDBGrid

Entonces, ¿cuál es la forma más eficiente de hacer esto (ya que todavía uso OnDrawColumnCell para algunas modificaciones de presentación preferiría usarlo)?

+0

Hay 3 formas de hacerlo. 1. Cree un campo calculado para la contraseña en el conjunto de datos utilizado por dbgrid. 2. Cree un campo calculado para la contraseña en la declaración de selección sql. o 3. use el evento onDrawColumCell/Data de dbgrid, como usted indicó anteriormente. Pero personalmente me gusta NO almacenar la contraseña en la base de datos, sino la versión codificada con hash de la contraseña. Como el código hash es una función unidireccional (es decir, no se puede obtener la contraseña original del código hash), y solo la contraseña correcta puede producir el mismo código hash, es más seguro usarlo.] – Hendra

+0

@Hendra Claro, la contraseña era un ejemplo, mis necesidades son demasiado complicadas para explicar con claridad. Pero sé cómo cambiar la presentación de una celda, con onDrawColumCell, pero no el contenido de texto, ningún ejemplo o tuto? – philnext

Respuesta

10

Existen al menos 3 formas de hacerlo, lo ilustrare enmascarando un campo de contraseña de una base de datos. Estoy usando el servidor sql para el dialecto sql.

1. Defina un campo calculado en la cadena sql.

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

A continuación, haga clic en el DBGrid, elija el editor de columnas. Dentro del editor de columnas de dbgrid, simplemente seleccione la columna maskedPwd en lugar de la columna de contraseña real. Ahora el dbgrid mostrará el valor enmascarado en lugar de la contraseña.

o

2. Definir un campo calculado en el conjunto de datos utilizado por el DBGrid.

Simplemente haga clic con el botón derecho en el conjunto de datos y use el editor de campos para crear un nuevo campo calculado (por ejemplo, maskedPwd2). Entonces onCalcField caso del conjunto de datos, escribir código para establecer el valor de maskedPwd2, es decir

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

Asegúrese de incluir maskedPwd2 en el editor de columnas del DBGrid.

o

3. Escribir texto personalizado en el caso OnDrawColumnCell del 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; 

Tenga en cuenta que el código anterior sólo muestra el valor enmascarado, pero si la red es editable, el valor real de la contraseña será visible cuando la célula se centra/editado.

Para solucionar esto, coloque un TEdit en el formulario, borre la propiedad de texto, establezca la propiedad PpasswordChar en '*' y visible en falso. Ahora está listo para usarse como reemplazo del editor incorporado para la celda. Ahora, necesitamos algo de lógica encolado, es decir

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; 

Tenga en cuenta que el código anterior no es perfecto, sin embargo, pero la esencia está ahí. Te lo dejo para hacer ejercicio.

+0

Respuesta clara y completa. – philnext

6

que iba a escribir un OnGetText para el campo de contraseña en mi conjunto de datos, el valor del campo no debe mostrarse en ningún control en absoluto

+0

Claro, pero mi pregunta no estaba completa (lo siento), mis DBGrids se crean dinámicamente y puedo tener diferentes campos de TF, por lo que no puedo asignar OnGetText. Considero OnDrawColumnCell en su lugar. – philnext

+0

Nunca lo he intentado. Supongo que podrías usar esto: 'con (Sender como TDBGrid). Las ranuras comienzan Font.Color: = clWhite; Brush.Color: = clWhite; Brush.Style: = bsSolid; end; 'para ocultar el valor que desea, pero no estoy seguro de cómo cambiar el texto real de un campo allí. ¿No sería más fácil asignar un 'OnGetText' a varios' TField's? –

+0

Ahora veo por qué no puede usar 'OnGetText', pero puede asignar fácilmente el mismo color a' font' y 'brush' en' OnDrawColumnCell' para su columna _password_. –

2

¿Tiene para enmascarar todos los valores en una columna entera? En ese caso, si sabe para qué TField (o nombre de campo) debe hacer esto: intente crear dinámicamente un campo calculado con los valores modificados y mostrarlo en la columna.

+0

¿Puede ser más preciso? – philnext

+0

No tengo tiempo para trabajar un ejemplo. En el momento en que cree los campos de protección que necesita enmascaramiento, también haga TFields.Add para agregar un campo calculado. Pase por TDBGrid.Columns, reemplace el campo usado por esa columna. También debe conectar un controlador de eventos OnCalcFields a su conjunto de datos, por supuesto (tal vez ya tenga uno). Espero que esto te haga comenzar. –

+0

Más claro gracias. – philnext

1

Modifico el código anterior para mostrar y ocultar la contraseña. Si el usuario hace clic en la celda Contraseña lo mostrará, cuando haga clic en la celda, la ocultará nuevamente.

// 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; 

No tomó mucho trabajo para convertirlo en un campo de contraseña fresco.

Olvidé una cosa en el evento DBGrid Draw Column Cell, debe cambiar Edit1.Clear; a Edit1.Text: = Your_Table_Name.FieldByName ('Password'). AsString;

Cuestiones relacionadas