- 积分
- 24557
- 明经币
- 个
- 注册时间
- 2004-3-17
- 在线时间
- 小时
- 威望
-
- 金钱
- 个
- 贡献
-
- 激情
-
|
楼主 |
发表于 2010-2-3 22:15:00
|
显示全部楼层
十三、在工具面板中动态加入项目
Adding items to an AutoCAD tool palette using .NET
This post carries directly on from the last one, which implemented a rudimentary “Quick SaveAs” capability in AutoCAD. Much of the explanation behind the design of today’s code is there, so please do read it first (if you haven’t already).- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.DatabaseServices;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.Runtime;
- using Autodesk.AutoCAD.Windows.ToolPalette;
- using System.Runtime.InteropServices;
- using System.IO;
- using System;
- namespace QuickSaveAs
- {
- public class Commands
- {
- // Set up static variable for the path to our folder
- // of drawings, as well as the base filename and a
- // counter to make the unique filename
- static string _path = "",
- _base = "";
- static int _count = 0;
- // Various filename and path-related constants
- const string sfxSep = " ",
- extSep = ".",
- pthSep = "\",
- lspSep = "/",
- dwgExt = ".dwg",
- scrExt = ".txt",
- bmpExt = ".bmp",
- bmpLoc = "Images",
- scrLoc = "Scripts";
- // Our QuickSaveAs command
- [CommandMethod("QSAVEAS")]
- public void QuickSaveAs()
- {
- Document doc =
- Application.DocumentManager.MdiActiveDocument;
- Editor ed = doc.Editor;
- Database db = doc.Database;
- // If this is the first time run...
- if (_path == "" || _base == "")
- {
- // Ask the user for a base file location
- PromptSaveFileOptions opts =
- new PromptSaveFileOptions(
- "Select location to save first drawing file"
- );
- opts.Filter = "Drawing (*.dwg)|*.dwg";
- PromptFileNameResult pr =
- ed.GetFileNameForSave(opts);
- // Delete the file, if it exists
- // (may be a problem if the file is in use)
-
- if (File.Exists(pr.StringResult))
- {
- try
- {
- File.Delete(pr.StringResult);
- }
- catch { }
- }
- if (pr.Status == PromptStatus.OK)
- {
- // If a file was selected, and it contains a path...
- if (pr.StringResult.Contains(pthSep))
- {
- // Separate the path from the file name
- int idx = pr.StringResult.LastIndexOf(pthSep);
- _path =
- pr.StringResult.Substring(0, idx);
- string fullname =
- pr.StringResult.Substring(idx+1);
-
- // If the path has an extension (this should always
- // be the case), extract the base file name
- if (fullname.Contains(extSep))
- {
- _base =
- fullname.Substring(
- 0,
- fullname.LastIndexOf(extSep)
- );
- // Create folders for our icons and our scripts
- Directory.CreateDirectory(
- _path + pthSep + bmpLoc
- );
- Directory.CreateDirectory(
- _path + pthSep + scrLoc
- );
- }
- }
- }
- }
- // Assuming the path and name were set appropriately...
- if (_path != "" && _base != "")
- {
- string name = _base;
- // Add our suffix if not the first time run
- if (_count > 0)
- name += sfxSep + _count.ToString();
- // Our drawing is located in the base path
- string dwgPath = _path + pthSep + name + dwgExt;
-
- // While our script is in a sub-folder
- string scrPath =
- _path + pthSep + scrLoc + pthSep + name + scrExt;
- // Create a dummy script, so we can make sure we pick
- // up the contents in our dummy execute command
- File.WriteAllText(
- scrPath,
- "This is a dummy script for " + name + "."
- );
- // Now we want to save our drawing and use the image
- // for our tool icon
- // Using either COM or .NET doesn't generate a
- // thumbnail in the resultant file (or its Database)
- // .NET:
- // db.SaveAs(dwgPath, false, DwgVersion.Current, null);
-
- // COM:
- // AcadDocument adoc = (AcadDocument)doc.AcadDocument;
- // adoc.SaveAs(dwgPath, AcSaveAsType.acNative, null);
- // So we'll send commands to the command-line
- // We'll use LISP, to avoid having to set FILEDIA to 0
- object ocmd = Application.GetSystemVariable("CMDECHO");
- string dwgPath2 = dwgPath.Replace(pthSep, lspSep);
- string scrPath2 = scrPath.Replace(pthSep, lspSep);
- string c1 =
- "(setvar "CMDECHO" 0)" +
- "(command "_.SAVEAS" "" "" + dwgPath2 + "")";
- string c2 =
- "(setvar "CMDECHO" " + ocmd.ToString() + ")" +
- "(tp-create "" + name + "" "" + scrPath2 + "")" +
- "(princ) ";
- string cmd = c1 + c2;
- if (cmd.Length <= 255)
- {
- doc.SendStringToExecute(cmd, false, false, false);
- }
- else
- {
- doc.SendStringToExecute(c1+" ", false, false, false);
- doc.SendStringToExecute(c2, false, false, false);
- }
- // Print a confirmation message for the DWG save
- // (which actually gets displayed before the queued
- // string gets executed, but anyway)
- ed.WriteMessage("\nSaved to: "" + dwgPath + """);
- _count++;
- }
- }
- // Our LISP-registered continuation function to create a
- // command tool on our tool palette
- [LispFunction("TP-CREATE")]
- public ResultBuffer CreateToolPaletteCommand(
- ResultBuffer rb
- )
- {
- const int RTSTR = 5005;
- Document doc =
- Application.DocumentManager.MdiActiveDocument;
- Editor ed = doc.Editor;
- if (rb == null)
- {
- ed.WriteMessage("\nError: too few arguments.");
- }
- else
- {
- // We're only interested in the first two arguments
- Array args = rb.AsArray();
- if (args.Length != 2)
- {
- ed.WriteMessage(
- "\nError: wrong number of arguments."
- );
- }
- else
- {
- // First argument is the name, second is the path
- // to the script
- TypedValue tv1 = (TypedValue)args.GetValue(0);
- TypedValue tv2 = (TypedValue)args.GetValue(1);
- if (tv1 != null && tv1.TypeCode == RTSTR &&
- tv2 != null && tv2.TypeCode == RTSTR)
- {
- string name = Convert.ToString(tv1.Value);
- string lspScrPath = Convert.ToString(tv2.Value);
- string scrPath =
- lspScrPath.Replace(lspSep, pthSep);
- bool success =
- CreateCommand(doc.Database, name, scrPath);
- return
- (success ?
- new ResultBuffer(
- new TypedValue(RTSTR, tv1.Value)
- )
- : null);
- }
- }
- }
- return null;
- }
- // Function to add a command tool to our tool palette to
- // execute the script
- private bool CreateCommand(
- Database db,
- string name,
- string scrPath
- )
- {
- const string catName = "ScriptCatalog";
- const string palName = "Scripts";
- ToolPaletteManager tpm = ToolPaletteManager.Manager;
- // Get the GUID of our dummy custom tool
- Type t = typeof(DummyTool);
- GuidAttribute ga =
- (GuidAttribute)t.GetCustomAttributes(
- typeof(GuidAttribute), false)[0];
- Guid g = new Guid(ga.Value);
- // Instanciate our dummy tool - this will allow us to use
- // its helper functions
- DummyTool tool = new DummyTool();
- Catalog cat;
- Palette pal = null;
- // First we check whether our GUID is in a catalog
- CatalogItem ci = tpm.StockToolCatalogs.Find(g);
- if (ci != null)
- {
- // If it is, search each catalog for our palette
- foreach(CatalogItem ci2 in tpm.Catalogs)
- {
- for (int i = 0; i < ci2.ChildCount; i++)
- {
- CatalogItem ci3 = ci2.GetChild(i);
- if (ci3 != null && ci3.Name == palName)
- {
- pal = ci3 as Palette;
- break;
- }
- }
- if (pal != null)
- break;
- }
- }
- // If we didn't find our palette, create it
- if (pal == null)
- {
- cat = tool.CreateStockTool(catName);
- pal = tool.CreatePalette(cat, palName);
- }
- // To add our command tool instance we need an icon
- ImageInfo ii = new ImageInfo();
- if (db.ThumbnailBitmap != null)
- {
- // Which we create from the Database's thumbnail
- string bmpPath =
- _path + pthSep + bmpLoc + pthSep + name + bmpExt;
- db.ThumbnailBitmap.Save(bmpPath);
- ii.ResourceFile = bmpPath;
- }
- ii.Size = new System.Drawing.Size(65, 65);
- // And then we use our dummy tool to create the
- // command tool
- tool.CreateCommandTool(
- pal,
- name,
- ii,
- "_EXECSCR "" + scrPath.Replace(pthSep, lspSep) + """
- );
-
- // Finally we reload the catalogs to display the change
- tpm.LoadCatalogs();
-
- return true;
- }
- // A dummy command to simulate the execution of our script
- // (which simply reads the contents and displays them on
- // the command-line)
- [CommandMethod("EXECSCR")]
- public void ExecuteScript()
- {
- Document doc =
- Application.DocumentManager.MdiActiveDocument;
- Editor ed = doc.Editor;
- PromptResult pr =
- ed.GetString(
- "\nEnter location of script to execute: "
- );
- if (pr.Status == PromptStatus.OK)
- {
- string path =
- pr.StringResult.Replace(lspSep, pthSep);
- if (File.Exists(path))
- {
- string contents = File.ReadAllText(path);
- ed.WriteMessage(
- "\nDummy script contained: "{0}"",
- contents
- );
- }
- }
- }
- }
- // Our dummy tool which simply derives from CustomToolBase
- // (there may be a more straightforward way to get access
- // to the helpers in CustomToolBase, but anyway)
- [Guid("3B725500-0451-4081-A1BB-B37CE6A65767")]
- [Tool("MyDummyTool", "IDB_TOOL")]
- [ClassInterface(ClassInterfaceType.AutoDual)]
- public class DummyTool : CustomToolBase
- {
- }
- }
Today we’re taking the code further by automatically creating an item on a tool palette with the thumbnail of the recently-saved drawing which, when used, will run a script created when we saved the drawing.
Some notes on the changes:
Lines 5, 6 and 8 add some additional namespaces.
It's worth noting that you'll need to add an assembly reference to AcTcMgd (depending on the version of AutoCAD you're using), for the updated code to build.
Lines 28-32 add some additional constants related to scripts and icon images.
Lines 95-102 create additional directories for our scripts and images.
Lines 123-134 create a dummy script when we save a drawing.
Lines 154-173 deal with a limitation we have with sending strings to the command-line:
AutoCAD’s command-line input buffer is only 255 characters in size, so if our string is longer (because of a deep file path), we send it in two pieces, terminating the first with a space character. It’s still possible that really deep paths could cause a problem with this code, but splitting the string further is left as an exercise for the reader. :-)
The string also calls a new continuation function (registered via LISP, see below) to create an item on our tool palette.
Lines 185-241 register a continuation function via LISP, so we can get control back in our code once the SAVEAS command has completed.
Lines 243-332 define a function to create an item on our tool palette. This function is called from the above LISP function.
Lines 334-363 simulate the execution of a script, so that when our tool palette is used, something happens.
The command simply reads in the contents of the "script" file and prints the contents to the command-line.
Lines 365-374 define a dummy custom tool, which we use as a shortcut for certain tool palette-related operations.
Now let’s take a look at the results of running this. In the last post we saw an example where a number of drawings get created in a particular folder. If we perform the same operations with this code, the same things happen (no need to show the drawings or the command-line output, they should be the same), but in addition we see a tool palette populated with images of our model at various stages:
You may have to right-click the stacked tool palette tabs to locate the “Scripts” tool palette (I haven’t found a way of doing this automatically, as it wasn’t really essential for my particular application).
When we select the items on the tool palette in sequence, we see our EXECSCR command is called with the location of the script created for each DWG file, which then gets read and printed to the command-line:- Command: _EXECSCR
- Enter location of script to execute:
- "C:/QSaveAs Test/Scripts/Solid model.txt"
- Dummy script contained: "This is a dummy script for Solid model."
- Command: _EXECSCR
- Enter location of script to execute:
- "C:/QSaveAs Test/Scripts/Solid model 1.txt"
- Dummy script contained: "This is a dummy script for Solid model 1."
- Command: _EXECSCR
- Enter location of script to execute:
- "C:/QSaveAs Test/Scripts/Solid model 2.txt"
- Dummy script contained: "This is a dummy script for Solid model 2."
- Command: _EXECSCR
- Enter location of script to execute:
- "C:/QSaveAs Test/Scripts/Solid model 3.txt"
- Dummy script contained: "This is a dummy script for Solid model 3."
- Command: _EXECSCR
- Enter location of script to execute:
- "C:/QSaveAs Test/Scripts/Solid model 4.txt"
- Dummy script contained: "This is a dummy script for Solid model 4."
- Command: _EXECSCR
- Enter location of script to execute:
- "C:/QSaveAs Test/Scripts/Solid model 5.txt"
- Dummy script contained: "This is a dummy script for Solid model 5."
复制代码 While clearly not actually doing anything useful, the script file that we’ve created (and I don’t mean script in the AutoCAD sense of the term – I’m using it in a more generic sense) could actually be regenerating the drawing contents (for instance). With a little more work. :-)
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?注册
x
|