我可以让插入符号停止闪烁后再次闪烁吗?

Can I make the caret blink again after it stopped blinking?

Windows10 中插入符号的正常行为似乎是,只要支持插入符号的控件获得焦点,插入符号就会闪烁约 5 秒,然后稳定(不闪烁)。每当按下左或右箭头键时,它都会移动插入符号,然后它会再次开始闪烁 5 秒,依此类推。

我无法在我的自定义控件上获得相同的行为。插入符号的创建、显示、移动和销毁似乎工作正常,但它只会在获得焦点后闪烁 5 秒,并且在使用箭头键移动它时可能会再闪烁一次,但之后再也不会闪烁。每次我用箭头键移动插入符号时,它都会保持稳定(不闪烁)。

如果控件失去焦点并重新获得焦点,它将再次闪烁。

我注意到另一个第 3 方控件的源代码,作者使用了 SetCaretBlinkTime api 调用,我想知道这是否能达到预期的效果,但 SetCaretBlinkTime's 文档鼓励开发人员仅在实际想要设置与键盘控制面板小程序类似的闪烁率时才使用它。

我的自定义控件:

const
CCharWidth = 8;
CWidth = 200;
CInsideMargin = 2;
CCharsPerLine = (CWidth - (CInsideMargin * 2)) div CCharWidth;

type
TEditPane = class(TCustomControl)
private
  FCaretPosX : Integer;

  procedure SetCaretPosition(AXPos : Integer);

  procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
  procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
protected
  procedure Paint; override;
public
end;

implementation

procedure TEditPane.Paint;
begin
  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := clWindow;
  Canvas.FillRect(Rect(0,0,Width,Height));
end;

procedure TEditPane.SetCaretPosition(AXPos : Integer);
begin
  If AXPos < CInsideMargin then
    AXPos := CInsideMargin;

  If AXPos > CInsideMargin + (CCharsPerLine * CCharWidth) then
    AXPos := CInsideMargin + (CCharsPerLine * CCharWidth);

  FCaretPosX := AXPos;
  SetCaretPos(FCaretPosX,CInsideMargin);
end;

procedure TEditPane.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  Message.Result := Message.Result or DLGC_WANTARROWS;
end;

procedure TEditPane.WMKeyDown(var Message: TWMKeyDown);
begin
  inherited;
  Case Message.CharCode of
    VK_LEFT :
      SetCaretPosition(FCaretPosX - CCharWidth);
    VK_RIGHT :
      SetCaretPosition(FCaretPosX + CCharWidth);
  end;
end;

procedure TEditPane.WMKillFocus(var Message: TWMKillFocus);
begin
  inherited;
  HideCaret(Handle);
  DestroyCaret;
end;

procedure TEditPane.WMLButtonDown(var Message: TWMLButtonDown);
begin
  inherited;
  SetFocus;
end;

procedure TEditPane.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  CreateCaret(Handle,0,1,13);
  SetCaretPosition(CInsideMargin);
  ShowCaret(Handle);
end;

显示插入符号后将恢复闪烁。所以你可以

HideCaret(Handle); { assuming that show counter is 1 }
ShowCaret(Handle);

或重复您的代码形式 WMSetFocus

CreateCaret(Handle,0,1,13);
SetCaretPosition(CInsideMargin);
ShowCaret(Handle);

闪烁也会在 BeginPaintEndPaint 之后恢复,因为它会隐式隐藏并在可见时显示插入符号,但这是副作用,不应依赖。