本帖最后由 transteel 于 2025-8-5 23:20 编辑

想用.net实现一个跟随鼠标的菜单代替PromptStringOptions,查了一些资料没找到。哪位大神有例子吗?或者有个思路也行。



感谢惊惊的指导,借助AI提示,基本上实现了(虽然还有bug),效果和代码如下:



  1. Dim promptString As New PromptKeywordOptions(vbCrLf & $"选择管线类型(根据提示输入数字)[SC×1(1)/SC×2(2)/SC×4(3)/SC×6(4)/PE×1(5)/PE×2(6)/PE×4(7)/PE×6(8)/]<{typeindex}>")
  2. promptString.Keywords.Add("SC×1", "1")
  3. promptString.Keywords.Add("SC×2", "2")
  4. promptString.Keywords.Add("SC×4", "3")
  5. promptString.Keywords.Add("SC×6", "4")
  6. promptString.Keywords.Add("PE×1", "5")
  7. promptString.Keywords.Add("PE×2", "6")
  8. promptString.Keywords.Add("PE×4", "7")
  9. promptString.Keywords.Add("PE×6", "8")

  10. ' 获取用户选择的选项
  11. Dim result As PromptResult = ed.GetKeywords(promptString)

  12. If result.Status = PromptStatus.OK Then
  13.     ' 通过选项设置 typeindex
  14.     typeindex = CInt(result.StringResult)
  15. End If




网友答:
transteel 发表于 2025-8-5 23:04
找到动图示例了:

它这个应该只是关键字...你看看getstring参数上面的配置里面是不是有

网友答: 本帖最后由 箭头_Row 于 2025-8-13 12:29 编辑

看動圖大致是下面步驟操作:

第一步獲取座標點,判斷操作:
option:點取點則進行接下來插入操作
option:點右鍵則進行右鍵菜單(關鍵字菜單)選取關鍵字操作
        {
              根據關鍵寫對應的更改參數的邏輯;
        }

注意:獲取點時一定要打開可空輸入!

大致代碼如下:
  1. public static class CsTest
  2. {
  3.     private enum Keywords
  4.     {
  5.         [Description("A")]
  6.         轴类,

  7.         [Description("S")]
  8.         设置,
  9.     }

  10.     [CommandMethod(nameof(Dg))]
  11.     public static void Dg()
  12.     {
  13.         using var doc = Acaop.DocumentManager.MdiActiveDocument;
  14.         var ed = doc.Editor;

  15.         // 以下測試代碼,循環可自行擴展
  16.         PromptPointOptions ppo = new("\n指定第一个点");
  17.         ppo.AllowNone = true; // 打开可空才會右鍵彈關鍵字菜單

  18.         PromptPointResult ppr = Env.Editor.GetPoint(ppo);
  19.         if (ppr.Status == PromptStatus.None)
  20.         {
  21.             PromptKeywordOptions options = new(string.Empty);
  22.             var keywordsMap = ArEnumEx.GetKeywordsMap<Keywords>();
  23.             options.AddKeywords([.. keywordsMap.Keys]);
  24.             options.AppendKeywordsToMessage = false; //不将关键字列表添加到提示信息中
  25.             options.Message = "\n右鍵彈出菜單示例" + keywordsMap.ToMessage();

  26.             PromptResult pr = ed.GetKeywords(options);
  27.             if (pr.Status.CancelPrint())
  28.                 return;

  29.             // 進行更改參數的操作
  30.         }
  31.         else if (ppr.Status != PromptStatus.OK)
  32.             return;

  33.         Point3d ptStart = ppr.Value;
  34.     }
  35. }


  1. /// <summary>
  2. /// 獲取關鍵字字典
  3. /// </summary>
  4. /// <typeparam name="T">關鍵字枚舉</typeparam>
  5. /// <returns> Dictionary 快捷鍵,(描述字_中文,Enum值)</returns>
  6. public static Dictionary<string, (string Key_CN, T enumValue)> GetKeywordsMap<T>()
  7.      where T : Enum
  8. {
  9.      Dictionary<string, (string, T)> keywordsDic = [];
  10.      var type = typeof(T);
  11.      var typeDesc = typeof(DescriptionAttribute);
  12.      foreach (var e in Enum.GetValues(type))
  13.      {
  14.          var name = e.ToString();
  15.          object objArr = type.GetField(name).GetCustomAttributes(typeDesc, true)[0];
  16.          keywordsDic.Add(((DescriptionAttribute)objArr).Description, (name, (T)e));
  17.      }

  18.      return keywordsDic;
  19. }


感謝驚驚提示的源碼及思路:獲取關鍵字字典。

  1. /// <summary>
  2. /// 获取关键字提示信息行。
  3. /// </summary>
  4. /// <param name="keywordsDic">keywords關鍵字字典</typeparam>
  5. /// <param name="defaultKeyword">可选的默认关键字,非空时添加到结果中</param>
  6. /// <returns> 返回格式示例:[字典(D)/板厚(T)/层高(H)/完成面(F)/图层(C)]</returns>
  7. public static StringBuilder ToMessage<T>(
  8.      this Dictionary<string, (string Key_CN, T enumValue)> keywordsDic,
  9.      string defaultKeyword = ""
  10. )
  11.      where T : Enum
  12. {
  13.      int number = 0;
  14.      StringBuilder keywordNotice = new("[");
  15.      foreach (var item in keywordsDic)
  16.      {
  17.          keywordNotice.Append(item.Value.Key_CN);
  18.          keywordNotice.Append('(');
  19.          keywordNotice.Append(item.Key);
  20.          keywordNotice.Append(')');
  21.          if (number < keywordsDic.Count - 1)
  22.              keywordNotice.Append('/');
  23.          number++;
  24.      }

  25.      keywordNotice.Append(']');

  26.      if (defaultKeyword != string.Empty)
  27.          if (keywordsDic.ContainsKey(defaultKeyword))
  28.              keywordNotice.Append($"<{defaultKeyword}>");
  29.          else // 無默認值時報錯提示
  30.              throw new ArgumentException("错误的默认值!");

  31.      return keywordNotice;
  32. }


  1. /// <summary>
  2. /// 檢查提示狀態是否為取消狀態,如果是則打印指定消息並返回 true。
  3. /// </summary>
  4. /// <param name="status">提示狀態。</param>
  5. /// <param name="message">要打印的消息,默認為 "*取消*"。</param>
  6. /// <returns>如果提示狀態不是 OK,則返回 true,否則返回 false。</returns>
  7. public static bool CancelPrint(this PromptStatus status, string message = "*取消*")
  8. {
  9.     if (status == PromptStatus.OK)
  10.         return false;

  11.     message.Print();
  12.     return true;
  13. }






网友答:
你有种再说一遍 发表于 2025-8-5 23:10
它这个应该只是关键字...你看看getstring参数上面的配置里面是不是有

问了下chatgpt大概实现了(虽然还有bug):


  1. Dim promptString As New PromptKeywordOptions(vbCrLf & $"选择管线类型(根据提示输入数字)[SC×1(1)/SC×2(2)/SC×4(3)/SC×6(4)/PE×1(5)/PE×2(6)/PE×4(7)/PE×6(8)/]<{typeindex}>")
  2. promptString.Keywords.Add("SC×1", "1")
  3. promptString.Keywords.Add("SC×2", "2")
  4. promptString.Keywords.Add("SC×4", "3")
  5. promptString.Keywords.Add("SC×6", "4")
  6. promptString.Keywords.Add("PE×1", "5")
  7. promptString.Keywords.Add("PE×2", "6")
  8. promptString.Keywords.Add("PE×4", "7")
  9. promptString.Keywords.Add("PE×6", "8")

  10. ' 获取用户选择的选项
  11. Dim result As PromptResult = ed.GetKeywords(promptString)

  12. If result.Status = PromptStatus.OK Then
  13.     ' 通过选项设置 typeindex
  14.     typeindex = CInt(result.StringResult)
  15. End If




网友答: 跟随鼠标的菜单指的是什么情况下使用的。

网友答: 本帖最后由 你有种再说一遍 于 2025-8-5 22:44 编辑

你要说场景才行,e大曾经做过一个图标跟随在鼠标旁边.

我的场景例子是拉伸填充:
CAD夹点触发时候,没有提供坐标点,我就无法获取位于那个多段线上面.
然后我用鼠标钩子一直更新一个静态字段,一旦夹点触发了,我就可以读取静态字段屏幕坐标转为CAD模型坐标了.
相关代码写在IFox的jing分支

网友答:
edata 发表于 2025-8-5 22:13
跟随鼠标的菜单指的是什么情况下使用的。

实现下面的通过命令行获取输入值的功能:


  1. Dim promptstring As New PromptStringOptions(vbCrLf & $"选择管线类型(根据提示输入数字)[SC×1(1)/SC×2(2)/SC×4(3)/SC×6(4)/PE×1(5)/PE×2(6)/PE×4(7)/PE×6(8)/]<{typeindex}>")
  2. Dim sr As PromptResult = ed.getstring(promptstring)






网友答:
transteel 发表于 2025-8-5 22:44
实现下面的通过命令行获取输入值的功能:

那你是想关键字时候触发自定义右键菜单,然后可以亮显其中选项?

网友答:
你有种再说一遍 发表于 2025-8-5 22:42
你要说场景才行,e大曾经做过一个图标跟随在鼠标旁边.

我的场景例子是拉伸填充:

场景:画直线,选择直线的终点前需要确定线型,目前的实现方式是键入一个数字来判断选择的是哪个线型,也可以使用右键菜单来选择。我想要实现一个跟随鼠标的菜单(选择直线起点后,这个菜单就出现并跟随鼠标移动),代替键入数字确定线型。(下图是右键菜单)




网友答:
transteel 发表于 2025-8-5 22:48
场景:画直线,选择直线的终点前需要确定线型,目前的实现方式是键入一个数字来判断选择的是哪个线型,也 ...

那你不应该用右键菜单,要用非模态面板去做.
也就是此时此刻你虽然触发了"右键"但是你钩子拦截了"右键"唤起了"面板"

网友答:
你有种再说一遍 发表于 2025-8-5 22:52
那你不应该用右键菜单,要用非模态面板去做.
也就是此时此刻你虽然触发了"右键"但是你钩子拦截了"右键"唤 ...

我好像没有说清楚……原谅我的语言匮乏!待我找到个示意动图再来请教!

网友答:
你有种再说一遍 发表于 2025-8-5 22:52
那你不应该用右键菜单,要用非模态面板去做.
也就是此时此刻你虽然触发了"右键"但是你钩子拦截了"右键"唤 ...

找到动图示例了:



  • 上一篇:想过使用.net开发自定义实体没有(一)-源程序
  • 下一篇:没有了