【问题标题】:Delphi remap key to multi charactersDelphi 将键重新映射到多个字符
【发布时间】:2016-05-25 21:21:28
【问题描述】:

我希望当我按下 Mm 字符时,000000 会在特定的 TEdit 框中输入:

procedure Tfrm.FormKeyPress(Sender: TObject; var Key: Char) ;
var
  i : integer;
begin
  if Key in ['m'] + ['M'] then Key := '0';
end;

使用此代码,我可以将“M”键重新映射到单个字符。如何将“M”重新映射到 TEdit 框的多个字符?

【问题讨论】:

  • 为什么不使用TEdit 事件呢?
  • any 控件接收到M/m 时,是否要将000000 输入到TEdit?还是仅在同一TEdit 收到时?您是否希望M/m 仍由接收它的控件处理,还是要丢弃它?
  • 我想在收到 m/M 时,将 000000 输入到 Tedit,例如当输入 1m 到 Tedit 时,Tedit 看起来值 1000000(m 表示百万)。我没有在 TEdit 组件中使用 m char

标签: delphi delphi-7 keyboard-events vcl


【解决方案1】:

使用TEdit 本身的OnKeyPress 事件,而不是父TFormOnKeyPress 事件。将Key 参数设置为#0 将其吞下,然后在TEdit 中插入6 个单独的'0' 字符:

procedure Tfrm.Edit1KeyPress(Sender: TObject; var Key: Char);
var
  i : integer;
begin
  if Key in ['m', 'M'] then
  begin
    Key := #0;
    for I := 1 to 6 do
      Edit1.Perform(WM_CHAR, Ord('0'), $80000001);
  end;
end;

或者:

procedure Tfrm.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if Key in ['m', 'M'] then
  begin
    Key := #0;
    Edit1.SelText := '000000';
  end;
end;

【讨论】:

  • 为什么不使用Edit1.SelText := '000000'(或者更好的是TEdit(Sender).SelText := '000000')?
【解决方案2】:

你确实不能“重新映射”

但您可以终止该特定字符(将其设置为 #0)并使用标准 Windows 消息传递 API(SendMessage,而不是 PostMessage)注入所需的零

类似的东西:

procedure Tfrm.FormKeyPress(Sender: TObject; var Key: Char);
var i : integer;
begin
    if ActiveControl = Edit1 then
      if Key in ['m'] + ['M'] then begin 
         Key := #0; // zero-out the real key so it would not be handled by the editbox
         for i := 1 to 6 do
             ActiveControl.Perform( WM_CHAR, Ord( '0' ), $80000001);
             // or you may reference the specific editbox directly
             //  like Edit1.Perform(....);
      end;
end;

这还需要设置表单以拦截其控件的键。

http://docwiki.embarcadero.com/Libraries/XE2/en/Vcl.Forms.TCustomForm.KeyPreview

如果您想一次劫持多个编辑框,这是有道理的。如果不是,你最好是编辑框本身的事件,而不是表单的事件。

procedure Tfrm.Edit1KeyPress(Sender: TObject; var Key: Char);
var i : integer;
begin
   if Key in ['m'] + ['M'] then begin 
      Key := ^@; // zero-out the real key so it would not be handled by the editbox
      for i := 1 to 6 do
          Edit1.Perform( WM_CHAR, Ord( '0' ), $80000001);
          // or you may reference the specific editbox directly
          //  like Edit1.Perform(....);
   end;
end;

【讨论】:

  • 如果Tfrm 表单上有任何组件(TEdit、TButton、TMemo 等),它将不会通过FormKeyPress 事件运行!!
  • @moskito-x 有 KeysPreview 属性。但是,我尝试与 topicstarter 代码保持密切联系(因此最清楚的是我添加到他制作的“样板”中的内容)相信他的“我可以使用此代码将 'M' 键重新映射到单个字符”评估。一般来说,我同意为了使代码稳定,要么添加检查“它到底是哪个编辑框”,要么使用编辑框自己的事件。
  • 附言。我很可能会在接下来的几天里离线,所以如果问题会被新的细节/问题扩展/变形,其他人可以添加他们的答案或修改我的这个答案。
  • @Arioch'The:如果我真的想吹毛求疵,我也会将['m'] + ['M'] 更改为['m', 'M'],并将逻辑移至TEdit 自己的OnKeyPress 事件而不是表单的事件。特别是在 Form 的 事件中,Sender 是 Form 本身,而不是接收到 Key 的控件。
  • @RemyLebeau 第一个也会吹毛求疵,因为它也在将常量“更改”为自身。后者会使代码不同,因此将是真正的编辑。
【解决方案3】:

如果您希望为所有TEdits 配备此行为,则将所有其他TEdits KeyPress 事件设置为Edit1KeyPress

procedure Tfrm.Edit1KeyPress(Sender: TObject; var Key: Char);
var
xEdit: TEdit;
begin
if Key in ['m','M'] then begin
       Key := #0;
       xEdit := Sender as TEdit;
       xEdit.Text := xEdit.Text +'000000';
    end;
end;

或短版

procedure Tfrm.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key in ['m','M'] then begin
   Key := #0;
   TEdit(Sender).Text := TEdit(Sender).Text+'000000';
end;
end;

【讨论】:

  • 在这种情况下,使用许多每个编辑器事件可能并不比使用表单的事件更好。虽然如果表单的 WM 相关事件已经被冗长而复杂的逻辑超载可能会更好,但这里几乎不是这种情况
  • @Arioch'The :从您的代码:if ActiveControl = Edit1 then 您必须始终将 = Edit1 更改为 TEdits 名称。
  • 如果有多个框,它将变为if (ActiveControl = Edit1) or (ActiveControl = Edit2) or .... then ...,而ActiveControl仍将用于注入消息
  • 你可以改用这个:if (ActiveControl is TEdit) then TEdit(ActiveControl).Text ...;
猜你喜欢
  • 2013-07-22
  • 1970-01-01
  • 1970-01-01
  • 2013-12-09
  • 2017-10-27
  • 2018-12-31
  • 1970-01-01
  • 2013-03-12
  • 2019-05-05
相关资源
最近更新 更多