說明
本功能就是直接點擊cad圖元獲取vla函數,快速知道圖元對應的方法和屬性(存在可用的).
小賤賤他復刻了一個高版本用的vlisp小助手,因為他調用了高版本函數,導致沒有Acad08版,我很郁悶,然后就在他的基礎上造了一個net全版本通用的...
至於貓老師曾經實現過的,通過幫助文件實現參數獲取,我懶得做了,要新建數據庫做快速索引才行,還要對數據庫整理...
動圖演示
制作過程
亂碼
Acad08測試時候:
以下操作不加T表示僅看vlisp支持的屬性,加T表示加看vlisp支持的方法,而加T時候會有亂碼信息.
(if (setq ent (entsel))(progn (vlax-dump-object (vlax-ename->vla-object(car ent))T)))
它會將";支持的方法:" 會隨機變成 ";?С值姆椒?"...等等含有"椒"字的字符串,由於直接使用Acad08獲取都有,
所以這無法通過改變字符串編碼修改,懷疑是Win10系統中文和Acad08編譯環境不同導致.
處理方法詳情見代碼SplitMethod內,這可能僅發生在Acad08或者net35下,因為我用Acad21測試並沒有這樣的問題.
如果是lisp寫小助手,恐怕每次獲取都是不一樣的碼值(lisp的解釋器有bug),無法用eq/equal對比,因為圖層亂碼是導致我學c#原因之一...
這可能就是不死貓老師vlisp小助手會出現有的能用,有的不能用的問題.
對話框模式和發送命令
代碼同時支持調用winform的模態窗口和非模態窗口兩種方式,可自己修改為自己喜歡的.
首先要說明: 先要發送復制命令歷史命令,再從剪貼板獲取歷史.
1: 當發送命令時,此時要同步處理剪貼板,那么需要同步命令,但是非模態不能發送同步命令,否則出現Acap.DocumentManager.IsApplicationContext == true 命令上下文的報錯.
2: 異步命令會導致先獲取剪貼板,之后才發送了復制命令歷史.而cad異步命令又沒有執行完成后的回調.
在我一籌莫展的時候,edata給了我個建議:
寫一個自己的同步命令,在命令內發送復制命令歷史命令,再在剪貼板獲取命令,並且修改窗體信息.
然后點擊圖元時候發送異步命令,調用這個自寫的同步命令,這樣執行順序就是正常的,窗體也能得到信息.
簡直妙到不行,有一種用魔法打敗魔法的感覺.
命令
using Autodesk.AutoCAD.Runtime;
namespace JoinBox.CommandLisp.Vlisp
{
public class VlispCmd
{
public VlispForm vlisp = null;
//用戶調用的命令
[CommandMethod("Lisp")]
public void Lisp()
{
if (vlisp == null || vlisp.IsDisposed)
{
vlisp = new VlispForm();
}
#if true //兩種模式我都調整好了,均可用!
vlisp.Show();
Win32API.WinApi.SetFocus(vlisp.Handle);
#else
vlisp.ShowDialog();
#endif
}
/* 此命令並不是由用戶調用,而是點選的時候自動調用.
因為在非模態窗口發送同步命令會失敗.
所以制作了一個同步命令來
進行獲取命令歷史,加入剪貼板.
*/
public const string Cmd_copyhist = "JJbox_Lisp_copyhist";
[CommandMethod(Cmd_copyhist)]
public void Cmd_copyhist_method()
{
VlispTool.SendCmd();
if (vlisp != null)
{
VlispTool.ClipboardData(cmdLines =>
{
//發送的最后一行是發送的命令,移除掉
cmdLines.Remove(Cmd_copyhist);
vlisp.SplitMethod(cmdLines);
});
}
}
}
}
工具類
using Autodesk.AutoCAD.DatabaseServices;
using System.Diagnostics;
using System.Windows.Forms;
using System;
using System.Collections.Generic;
namespace JoinBox.CommandLisp.Vlisp
{
public static class VlispTool
{
/// <summary>
/// 發送命令獲取剪貼板歷史
/// </summary>
public static void SendCmd()
{
const string cps = "_.copyhist";
var rb = new ResultBuffer
{
new TypedValue((int)EnumBufCode.Text, cps)
};
int cnum = CSendSynchronization.AcedCmd(rb);
if (cnum == 0)
{
Debug.WriteLine($"{cps}發送命令失敗!");
}
}
/// <summary>
/// 獲取剪貼板數據
/// </summary>
/// <param name="action"></param>
public static void ClipboardData(Action<List<string>> action)
{
// 此處還需要保存原來的剪貼板,再進行獲取,再還原.
// 剪貼板內容
var iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text))
{
string clipboardText = (string)iData.GetData(DataFormats.Text);
if (!string.IsNullOrEmpty(clipboardText))
{
//將剪貼板的東西賦值給窗體
var aa = clipboardText.Split('\r', '\n');
List<string> _cmdLines = new();
_cmdLines.AddRange(aa);
_cmdLines.RemoveAll(str => str == string.Empty);
action(_cmdLines);
}
}
}
}
}
發送命令類
/// <summary>
/// 非模態對話框切換焦點回cad
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32.dll", EntryPoint = "SetFocus")]
public static extern int SetFocus(IntPtr hWnd);
public partial class CSendSynchronization
{
//發送同步命令
//由於cad2016里AcedCmd改成了AcedCmdS,Accore.dll也是2013版本后才開始改的。
//調用AutoCAD命令,ARX原型:int acedCmdS(const struct resbuf * rbp);
#if NET35 || NET40
[DllImport("acad.exe", EntryPoint = "acedCmd", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
#else
[DllImport("accore.dll", EntryPoint = "acedCmdS", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
#endif
private static extern int AcedCmd(IntPtr rbp);
/// <summary>
/// 調用C++的acedCmdS函數
/// </summary>
/// <param name="args">命令參數列表</param>
/// <returns>返回命令執行的狀態</returns>
public static int AcedCmd(ResultBuffer args)
{
if (!Acap.DocumentManager.IsApplicationContext)
return AcedCmd(args.UnmanagedObject);
else
return 0;
}
}
窗體
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
using static JoinBox.CommandLisp.LSend;
using JoinBox.CommandLisp.Vlisp;
namespace JoinBox
{
public partial class VlispForm : Form
{
StringBuilder _sb;
const string _dump = "(if (setq ent (entsel))(progn (vlax-dump-object (vlax-ename->vla-object(car ent))T)))";
public VlispForm()
{
InitializeComponent();
RunLisp("(vl-load-com)");
_sb = new();
for (int i = 0; i < 2048; i++) //最高命令行數
{
_sb.Append("\n");
}
}
/// <summary>
/// 點擊圖元按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button3_Click(object sender, EventArgs e)
{
ModalAction(ed =>
{
ed.WriteMessage(_sb.ToString()); //清空命令歷史
ResultBuffer dump = null;
dump = RunLisp(_dump);
if (dump == null || !dump.AutoDelete)
{
return;
}
ed.WriteMessage("\n");
SendCmdGetClipboard();
});
}
/// <summary>
/// 判斷模態和非模態進入不同的處理
/// </summary>
/// <param name="action"></param>
private void ModalAction(Action<Editor> action)
{
var doc = Acap.DocumentManager.MdiActiveDocument;
var ed = doc.Editor;
if (this.Modal)
{
using (ed.StartUserInteraction(this))//啟用用戶交互
{
action.Invoke(ed);
}
}
else
{
Win32API.WinApi.SetFocus(Acap.MainWindow.Handle);
using (doc.LockDocument())
{
action.Invoke(ed);
}
Win32API.WinApi.SetFocus(this.Handle);
}
}
/// <summary>
/// 發送命令及獲取剪貼板
/// </summary>
private void SendCmdGetClipboard()
{
/*
Acad2016的函數,我就為了仿照此處讓Acad2008+都用上
_cmdLines = Autodesk.AutoCAD.Internal.Utils.GetLastCommandLines(500, false);
*/
if (this.Modal)
{
//同步命令
VlispTool.SendCmd();
VlispTool.ClipboardData(cmdLines =>
{
SplitMethod(cmdLines);
});
}
else
{
//異步命令
string cmd = VlispCmd.Cmd_copyhist + "\n";
var doc = Acap.DocumentManager.MdiActiveDocument;
doc.SendStringToExecute(cmd, false, true, true);
}
}
/// <summary>
/// 切割字符串加入對話框
/// </summary>
/// <param name="cmdLines"></param>
public void SplitMethod(List<string> cmdLines)
{
MethodList.Items.Clear();
MethodList.TopIndex = MethodList.Items.Count - 1;
AttributesList.Items.Clear();
AttributesList.TopIndex = AttributesList.Items.Count - 1;
//為什么運行了一次就可以呢?
const string stra = ";支持的方法:";
const string strd = "椒";//Acad2008亂碼
var sNum = cmdLines.IndexOf(stra);
if (sNum == -1)
{
for (int i = 0; i < cmdLines.Count; i++)
{
if (cmdLines[i].Contains(strd))
{
sNum = i;
break;
}
}
}
if (sNum != -1)
{
var sNuma = sNum + 1;
var cc = cmdLines.GetRange(sNuma, cmdLines.Count - sNuma);
this.BeginInvoke(new Action(() =>
{
foreach (var item in cc)
{
MethodList.Items.Add(item.Replace("; ", ""));
}
}));
}
var eNum = cmdLines.IndexOf(";特性值:");
if (eNum != -1)
{
++eNum;
List<string> cc;
if (sNum != -1)
{
cc = cmdLines.GetRange(eNum, sNum - eNum);
}
else
{
//這里是 _dump 沒有T參數時候
cc = cmdLines.GetRange(eNum, cmdLines.Count - eNum);
}
this.BeginInvoke(new Action(() =>
{
foreach (var item in cc)
{
AttributesList.Items.Add(item.Replace("; ", ""));
}
}));
}
}
/// <summary>
/// 屬性值單擊顯示 Vlax-Get
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AttributesList_SelectedIndexChanged(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
var text = AttributesList.Text.Split(" ".ToCharArray()).GetValue(0);
CodeText.Text = "(Vlax-Get (Vlax-Ename->Vla-Object (Car (Entsel))) '" + text.ToString() + " )";
}));
}
/// <summary>
/// 屬性值雙擊顯示 Vlax-Put
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void AttributesList_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.BeginInvoke(new Action(() =>
{
var text = AttributesList.Text.Split(" ".ToCharArray()).GetValue(0);
CodeText.Text = "(Vlax-Put (Vlax-Ename->Vla-Object (Car (Entsel))) '" + text.ToString() + " 參數)";
}));
}
/// <summary>
/// 方法選擇動作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MethodList_SelectedIndexChanged(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
var text = MethodList.Text.Split(" ".ToCharArray());
var t1 = text.GetValue(0).ToString();
var t2 = text.GetValue(1).ToString().Split((new char[] { '(', ')' }));
int num = 1;
if (t2.GetValue(1).ToString() != "")
{
num = Convert.ToInt16(t2.GetValue(1));
}
string canshu = "";
for (int i = 0; i < num; i++)
{
canshu = "參數 " + canshu;
}
CodeText.Text = "(Vlax-Invoke-Method (Vlax-Ename->Vla-Object (Car(Entsel))) '" + t1 + " " + canshu + ")";
}));
}
/// <summary>
/// 數據復制到粘貼板
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button2_Click(object sender, EventArgs e)
{
try
{
Clipboard.SetDataObject(CodeText.Text);
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 自動拷貝
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void CodeText_TextChanged(object sender, EventArgs e)
{
Clipboard.SetDataObject(CodeText.Text);
}
/// <summary>
/// 變量賦值
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TextBox2_Leave(object sender, EventArgs e)
{
this.BeginInvoke(new Action(() =>
{
CodeText.Text = $"(setq {VariableText.Text} {CodeText.Text})";
}));
}
/// <summary>
/// 加載按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button1_Click(object sender, EventArgs e)
{
ModalAction(ed =>
{
ed.WriteMessage("\n\n");
ed.WriteMessage(CodeText.Text + "\n");
ResultBuffer aa = RunLisp(CodeText.Text);
var bb = aa.AsArray();
ed.WriteMessage(bb[0].Value.ToString() + "\n");
});
}
}
public static class LResultBufferTool
{
public static object GetValue(this ResultBuffer res)
{
var arr = res.AsArray();
object ret = arr[0].Value;
return ret;
}
}
}
窗體設計
namespace JoinBox
{
partial class VlispForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.AttributesList = new System.Windows.Forms.ListBox();
this.MethodList = new System.Windows.Forms.ListBox();
this.label3 = new System.Windows.Forms.Label();
this.CodeText = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.label4 = new System.Windows.Forms.Label();
this.FeaturesText = new System.Windows.Forms.TextBox();
this.label5 = new System.Windows.Forms.Label();
this.MethodText = new System.Windows.Forms.TextBox();
this.label6 = new System.Windows.Forms.Label();
this.VariableText = new System.Windows.Forms.TextBox();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// AttributesList
//
this.AttributesList.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.AttributesList.FormattingEnabled = true;
this.AttributesList.ItemHeight = 12;
this.AttributesList.Location = new System.Drawing.Point(6, 20);
this.AttributesList.Name = "AttributesList";
this.AttributesList.Size = new System.Drawing.Size(546, 424);
this.AttributesList.TabIndex = 0;
this.AttributesList.SelectedIndexChanged += new System.EventHandler(this.AttributesList_SelectedIndexChanged);
this.AttributesList.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.AttributesList_MouseDoubleClick);
//
// MethodList
//
this.MethodList.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.MethodList.FormattingEnabled = true;
this.MethodList.ItemHeight = 12;
this.MethodList.Location = new System.Drawing.Point(6, 20);
this.MethodList.Name = "MethodList";
this.MethodList.Size = new System.Drawing.Size(256, 424);
this.MethodList.TabIndex = 2;
this.MethodList.SelectedIndexChanged += new System.EventHandler(this.MethodList_SelectedIndexChanged);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Enabled = false;
this.label3.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label3.Location = new System.Drawing.Point(8, 530);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(29, 12);
this.label3.TabIndex = 4;
this.label3.Text = "代碼";
//
// CodeText
//
this.CodeText.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.CodeText.Location = new System.Drawing.Point(41, 527);
this.CodeText.Name = "CodeText";
this.CodeText.Size = new System.Drawing.Size(800, 21);
this.CodeText.TabIndex = 5;
this.CodeText.TextChanged += new System.EventHandler(this.CodeText_TextChanged);
//
// button1
//
this.button1.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.button1.Location = new System.Drawing.Point(416, 552);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(117, 27);
this.button1.TabIndex = 6;
this.button1.Text = "加載";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.Button1_Click);
//
// button3
//
this.button3.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.button3.Location = new System.Drawing.Point(293, 552);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(117, 27);
this.button3.TabIndex = 6;
this.button3.Text = "選擇圖元";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.Button3_Click);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Enabled = false;
this.label4.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label4.Location = new System.Drawing.Point(8, 475);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(29, 12);
this.label4.TabIndex = 7;
this.label4.Text = "功能";
//
// FeaturesText
//
this.FeaturesText.Enabled = false;
this.FeaturesText.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.FeaturesText.Location = new System.Drawing.Point(41, 471);
this.FeaturesText.Name = "FeaturesText";
this.FeaturesText.Size = new System.Drawing.Size(800, 21);
this.FeaturesText.TabIndex = 5;
this.FeaturesText.Text = "判斷是在發生命令之前(先選取再執行)或之后選取對象。";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Enabled = false;
this.label5.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label5.Location = new System.Drawing.Point(8, 503);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(29, 12);
this.label5.TabIndex = 4;
this.label5.Text = "方法";
//
// MethodText
//
this.MethodText.Enabled = false;
this.MethodText.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.MethodText.Location = new System.Drawing.Point(41, 499);
this.MethodText.Name = "MethodText";
this.MethodText.Size = new System.Drawing.Size(800, 21);
this.MethodText.TabIndex = 5;
//
// label6
//
this.label6.AutoSize = true;
this.label6.Enabled = false;
this.label6.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.label6.Location = new System.Drawing.Point(8, 559);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(29, 12);
this.label6.TabIndex = 4;
this.label6.Text = "變量";
//
// VariableText
//
this.VariableText.Font = new System.Drawing.Font("宋體", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
this.VariableText.Location = new System.Drawing.Point(41, 555);
this.VariableText.Name = "VariableText";
this.VariableText.Size = new System.Drawing.Size(246, 21);
this.VariableText.TabIndex = 5;
this.VariableText.Leave += new System.EventHandler(this.TextBox2_Leave);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.AttributesList);
this.groupBox1.Location = new System.Drawing.Point(6, 5);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(561, 456);
this.groupBox1.TabIndex = 8;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "屬性";
//
// groupBox2
//
this.groupBox2.Controls.Add(this.MethodList);
this.groupBox2.Location = new System.Drawing.Point(573, 5);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(268, 456);
this.groupBox2.TabIndex = 9;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "方法";
//
// VlispLook
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.ClientSize = new System.Drawing.Size(849, 583);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label4);
this.Controls.Add(this.button3);
this.Controls.Add(this.button1);
this.Controls.Add(this.FeaturesText);
this.Controls.Add(this.VariableText);
this.Controls.Add(this.MethodText);
this.Controls.Add(this.CodeText);
this.Controls.Add(this.label5);
this.Controls.Add(this.label6);
this.Controls.Add(this.label3);
this.Name = "VlispLook";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Vlisp圖元屬性查看器";
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ListBox AttributesList;
private System.Windows.Forms.ListBox MethodList;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox CodeText;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox FeaturesText;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox MethodText;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox VariableText;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
}
}
Arx制作
由於Arx可以通過重寫命令欄的方式攔截命令文本數據,所以不需要像c#一樣在那繞圈圈,
便可以導出命令歷史到窗體上面,不過實現了功能就好啦🌚
后記
實際上我們需求是反射圖元下面所擁有的東西,那么,我們為什么要靠net調用arx反射?
我們net可是有API的啊!所以只需要反射圖元就好了...
(完)