You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为TSynEdit中的SQL对象名添加交互链接功能?

实现TSynEdit中SQL对象名的交互功能

当然有可行的实现方法!我之前开发SQL编辑器时也做过类似的需求,下面分两步给你详细拆解实现思路和代码:

a) 鼠标悬停时切换为手型光标

要实现这个效果,我们需要利用TSynEdit的OnMouseMove事件,实时检测鼠标位置对应的文本是否是你标记的对象名(表、存储过程等),然后切换光标样式:

  1. 获取鼠标位置对应的行和列:通过RowColAtPos方法将屏幕坐标转换为编辑框内的行列位置
  2. 判断当前文本是否为目标对象名:借助语法高亮器的GetTokenAtRowCol方法获取当前位置的Token信息,再检查该Token是否存在于你的Tablenames/存储过程列表中
  3. 切换光标样式:如果是目标对象名,将光标设为crHandPoint,否则恢复默认的crDefault

代码示例:

procedure TYourForm.SynEdit1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  Row, Col: Integer;
  Token: TSynToken;
  SQLSyn: TSynSQLSyn;
begin
  // 确保语法高亮器是TSynSQLSyn(如果用的是自定义高亮器,替换成对应类型)
  if not (SynEdit1.SyntaxHighlighter is TSynSQLSyn) then Exit;
  
  SQLSyn := TSynSQLSyn(SynEdit1.SyntaxHighlighter);
  // 转换鼠标坐标为编辑框内的行列
  SynEdit1.RowColAtPos(SynEdit1.ScreenToClient(Point(X, Y)), Row, Col);
  // 获取当前位置的Token
  SQLSyn.GetTokenAtRowCol(Row, Col, Token);
  
  // 检查Token是否属于我们的目标对象名(表、存储过程、域等)
  if (Token.TokenType = tkIdentifier) and 
     (SQLSyn.Tablenames.IndexOf(Token.Content) <> -1 or
      SQLSyn.Procedures.IndexOf(Token.Content) <> -1 or
      SQLSyn.Domains.IndexOf(Token.Content) <> -1) then
    SynEdit1.Cursor := crHandPoint
  else
    SynEdit1.Cursor := crDefault;
end;

// 别忘了处理鼠标移出编辑框的情况,恢复默认光标
procedure TYourForm.SynEdit1MouseLeave(Sender: TObject);
begin
  SynEdit1.Cursor := crDefault;
end;

b) 点击对象名触发打开事件

点击事件的实现思路和悬停类似,我们可以用OnMouseDown事件(比OnClick更精准,能区分左键点击),获取点击位置的对象名后,触发自定义的打开逻辑:

代码示例:

// 可以先定义一个自定义事件,方便外部调用(可选)
type
  TObjectClickEvent = procedure(Sender: TObject; const ObjectName, ObjectType: string) of object;

type
  TYourForm = class(TForm)
    SynEdit1: TSynEdit;
    // ...其他组件
  private
    FOnObjectClick: TObjectClickEvent;
    function GetObjectType(const ObjName: string): string;
  public
    property OnObjectClick: TObjectClickEvent read FOnObjectClick write FOnObjectClick;
    // ...其他方法
  end;

// 辅助函数:判断对象类型(表、存储过程等)
function TYourForm.GetObjectType(const ObjName: string): string;
var
  SQLSyn: TSynSQLSyn;
begin
  SQLSyn := TSynSQLSyn(SynEdit1.SyntaxHighlighter);
  if SQLSyn.Tablenames.IndexOf(ObjName) <> -1 then
    Result := 'Table'
  else if SQLSyn.Procedures.IndexOf(ObjName) <> -1 then
    Result := 'Procedure'
  else if SQLSyn.Domains.IndexOf(ObjName) <> -1 then
    Result := 'Domain'
  else
    Result := '';
end;

// 鼠标点击事件处理
procedure TYourForm.SynEdit1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Row, Col: Integer;
  Token: TSynToken;
  ObjName, ObjType: string;
  SQLSyn: TSynSQLSyn;
begin
  if Button <> mbLeft then Exit;
  if not (SynEdit1.SyntaxHighlighter is TSynSQLSyn) then Exit;
  
  SQLSyn := TSynSQLSyn(SynEdit1.SyntaxHighlighter);
  SynEdit1.RowColAtPos(SynEdit1.ScreenToClient(Point(X, Y)), Row, Col);
  SQLSyn.GetTokenAtRowCol(Row, Col, Token);
  
  ObjName := Token.Content;
  ObjType := GetObjectType(ObjName);
  
  if ObjType <> '' then
  begin
    // 触发自定义事件,让外部处理打开逻辑
    if Assigned(FOnObjectClick) then
      FOnObjectClick(Self, ObjName, ObjType)
    else
      // 如果没有自定义事件,直接执行打开逻辑(示例)
      ShowMessage(Format('打开%s: %s', [ObjType, ObjName]));
  end;
end;

额外注意事项

  • 如果你的语法高亮器不是默认的TSynSQLSyn,需要替换成你使用的高亮器类型,并调整对应的对象列表属性(比如自定义的MyObjectNames列表)
  • 为了提升性能,可以缓存对象名列表,避免每次鼠标移动都做索引查找
  • 可以结合TSynEdit的ToolTip功能,在悬停时显示对象的额外信息(比如表的注释、存储过程的参数等),增强用户体验

内容的提问来源于stack exchange,提问作者Franky Brandt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:38:32