如何在Delphi TDBGrid中修改单元格值

如何在Delphi TDBGrid中修改单元格值,delphi,delphi-xe2,tdbgrid,Delphi,Delphi Xe2,Tdbgrid,我必须在VCL TDBGrid(Delphi XE2)中显示一些修改后的“屏蔽”值,即:将“密码”更改为“xxxxxxxx”,或将大写“pass”更改为“pass”或其他。 由于我的字段是动态创建的(但名称是编码的,因此我知道如何以及何时屏蔽它们,即:xxxx_PASSW用于密码字段),因此我不能使用(我认为)OnGetText事件 那么,最有效的方法是什么(我现在使用OnDrawColumnCell进行一些演示文稿修改,我更愿意使用它)?我会为数据集中的密码字段编写一个OnGetText,由于

我必须在VCL TDBGrid(Delphi XE2)中显示一些修改后的“屏蔽”值,即:将“密码”更改为“xxxxxxxx”,或将大写“pass”更改为“pass”或其他。 由于我的字段是动态创建的(但名称是编码的,因此我知道如何以及何时屏蔽它们,即:xxxx_PASSW用于密码字段),因此我不能使用(我认为)OnGetText事件


那么,最有效的方法是什么(我现在使用OnDrawColumnCell进行一些演示文稿修改,我更愿意使用它)?

我会为数据集中的密码字段编写一个
OnGetText
,由于字段的值根本不应显示在任何控件中

您必须屏蔽整列中的所有值吗?在这种情况下,如果您知道要为哪个TField(或fieldname)执行此操作:尝试使用修改后的值动态创建一个计算字段,并将其显示在列中。

至少有3种方法可以做到这一点,我将通过从数据库屏蔽密码字段来说明。我正在使用sql server作为sql方言

1。在sql字符串上定义计算字段。

select field1, field2, '********' as maskedPwd from table1;
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;
然后,右键单击dbgrid,选择columns编辑器。在dbgrid的columns编辑器中,只需选择maskedPwd列而不是real password列。现在dbgrid将显示屏蔽值,而不是密码

2。在dbgrid使用的数据集上定义计算字段。

select field1, field2, '********' as maskedPwd from table1;
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;
只需在数据集上单击鼠标右键,然后使用字段编辑器创建一个新的计算字段(例如maskedPwd2)。然后在dataset的Calcfield事件上,编写代码来设置maskedPwd2的值,即

procedure TForm1.ADOQuery1CalcFields(DataSet: TDataSet);
begin
  DataSet.FieldByName('maskedPwd2').AsString := '********';
end;
确保在dbgrid的列编辑器中包含maskedPwd2

3。在dbgrid的onDrawColumnCell事件上写入自定义文本。

select field1, field2, '********' as maskedPwd from table1;
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;
请注意,上面的代码仅显示屏蔽值,但如果网格是可编辑的,则在聚焦/编辑单元格时,真实密码值将可见

要处理此问题,请在表单上放置一个TEdit,清除text属性,将PpasswordChar属性设置为“*”,并将visible设置为false。现在,它可以用来替代单元格的内置编辑器。现在,我们需要一些粘合逻辑,即

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;

请注意,上面的代码还不是完美的,但本质是存在的。我将把它留给您练习。

我修改了上面的代码以显示和隐藏密码。如果用户单击密码单元格,它将显示密码,当用户单击关闭该单元格时,它将再次隐藏密码

// 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; 
并没有花太多的工作,使它成为一个冷静的密码领域


在DBGrid Draw Column单元格事件中忘记了一件事,您应该更改Edit1.Clear;编辑1.Text:=Your_Table_Name.FieldByName('Password').AsString

当然,但我的问题不完整(对不起),我的DBGrids是动态创建的,我可能有不同的TField,因此我无法分配OnGetText。我考虑改为使用Ondrawcell。我从未尝试过。我想你可以使用这个:
和(发送者作为TDBGrid)。Canvas do begin Font.Color:=clWhite;画笔颜色:=白色;画笔样式:=bsSolid;结束
隐藏所需的值,但我不确定如何更改字段的实际文本。将一个
OnGetText
分配给多个
t字段
s不是更容易吗?现在我明白了为什么不能使用
OnGetText
,但您可以轻松地将相同的颜色分配给
font
ondrawcolumnscell
中的
brush
作为密码列。是的,但密码只是一个例子,我想对显示的值应用一个函数,它可能是密码的掩码,但可能是大写或其他任何形式。@phil-您可以为动态创建的对象分配一个事件处理程序
MyField.OnGetText:=PassFieldGetText
其中PassFieldGetText是具有签名的某个类的过程
(发送方:TField;变量文本:string;显示文本:Boolean)我没有时间做一个例子。在创建需要屏蔽的TFields时,也要执行TFields.Add以添加计算字段。检查TDBGrid.Columns,替换该列使用的字段。当然,您还必须将OnCalcFields事件处理程序挂接到数据集(可能您已经有了一个)。希望这能让你开始。有三种方法可以做到这一点。1.在dbgrid使用的数据集上为密码创建计算字段。2.在sql select语句中为密码创建计算字段。或3。使用dbgrid的onDrawColumCell/Data事件,如上面所述。但我个人不喜欢将密码存储在数据库中,而是将密码的哈希编码版本存储在数据库中。因为散列码是一个单向函数(即无法从散列码中获取原始密码),只有正确的密码才能生成相同的散列码,所以使用起来更安全。]@Hendra当然,密码就是一个例子,我的需求太复杂,无法清楚地解释。但我知道如何用onDrawColumCell改变单元格的表示方式,但不知道文本内容,有什么例子或图图吗?