TheSwamp
Code Red => .NET => Topic started by: dugk on August 25, 2010, 11:04:48 AM
-
I spent some time trying to code a better highlight method. My goal was to make it run for a period of time and blink the entity in some way.
I tried alternating the highlight property in successive passes of a for loop and I included a call to Thread.Sleep(1000) but it was not visibly recognizable when run.
In another trial on a line entity I tried drawing a series of polylines with width over top and then change their color during a for loop but it too was not visibly recognizable when run.
Any suggestions?
Thanks!
Doug
-
change their color during a for loop but it too was not visibly recognizable when run.
Any suggestions?
Care to post the code?
-
You can look into TransientGraphics object, which is designed for doing, well, "transient graphics" in Acad editor to provide visual hint to the user.
I have 2 blog articles on this topic with short video clips attached http://drive-cad-with-code.blogspot.com/2009/07/help-autocad-users-visually-with.html (http://drive-cad-with-code.blogspot.com/2009/07/help-autocad-users-visually-with.html). From the sample code I am sure you can easily figure out a way to have "better entity highlight".
-
Norman,
Thanks for you post and the interesting examples that you posted on your blog! I've added your blog to my RSS feeds. :)
I think your example will prove to be a good resource. I'll post my code soon.
Thanks,
Doug
-
That was neat Norman
I saw something by Fenton Webb and he used the pointMoniterEvents (I believe that right)
You check that out.
-
dugk,
I was thinking in terms when you said that your color changes were not showing up in real time
that you were not using QueueForGraphicsFlush during the transaction.
Here's how I change the colors of the entities in a Group:
using (Transaction trans = doc.TransactionManager.StartTransaction())
{
Group EntGrpDic = (Group)trans.GetObject(GID, OpenMode.ForRead);
ObjectId[] Eids = EntGrpDic.GetAllEntityIds();
foreach (ObjectId eid in Eids)
{
Entity ent = trans.GetObject(eid, OpenMode.ForWrite) as Entity;
ent.RecordGraphicsModified(true);
trans.TransactionManager.QueueForGraphicsFlush();
if (flag == 1)
{
colorIndex = (short)3;
ent.ColorIndex = colorIndex;
}
else
{
colorIndex = (short)256;
ent.ColorIndex = colorIndex;
}
}
trans.Commit();
ed.UpdateScreen();
}
-
Norman,
Your code helped me create what I was hoping to create. Here is the code I created with your help:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using AcApSrvApp = Autodesk.AutoCAD.ApplicationServices.Application;
using AcApDbSrv = Autodesk.AutoCAD.DatabaseServices;
using System;
namespace transientGraphics
{
public class tgLineJig
{
private AcApDbSrv.Polyline mTGPolyline = null;
private AcApDbSrv.Line mTargetLine;
private Editor mEditor;
private Database mDB;
private Document mDoc;
private Point3d mBasePoint;
private int mColorIndex = 1;
private Plane planeXY = new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis);
public tgLineJig(Document doc)
{
mDoc = doc;
mDB = doc.Database;
mEditor = doc.Editor;
}
public void ShowTGJig()
{
transientGraphics.Methods.setOsMode(0);
//Option to pick the target polyline
PromptEntityOptions eOpt = new PromptEntityOptions("\nPick a line:");
//Only allow to pick line
eOpt.SetRejectMessage("\nYou must pick a line:");
eOpt.AddAllowedClass(typeof(AcApDbSrv.Line), true);
//Do the pick
PromptEntityResult eRes = mEditor.GetEntity(eOpt);
if (eRes.Status != PromptStatus.OK) return;
//Get the target polyline
ObjectId targetId = eRes.ObjectId;
AcApDbSrv.Line target = GetLine(targetId);
if (target == null) return;
mTargetLine = target;
//Set base point
mBasePoint = mTargetLine.StartPoint;
//Set base point for second pick so that a rubberband will be shown when mouse is moving
PromptPointOptions opt2 = new PromptPointOptions("\nClick anywhere to exit:");
opt2.AllowArbitraryInput = true;
//Start monitoring pointer move
mEditor.PointMonitor += new PointMonitorEventHandler(mEditor_PointMonitor);
//Start asking user to do second pick (exit) so that the "jig" image will move with mouse
mEditor.GetPoint(opt2);
//Once the second point is picked, clear the transient graphic "jig". After this, since
//a new point is obtained with the jig;s visual help, one can then do copy/move/insert...
ClearTGPolyline();
//End pointer move monitoring
mEditor.PointMonitor -= new PointMonitorEventHandler(mEditor_PointMonitor);
}
private void mEditor_PointMonitor(object sender, PointMonitorEventArgs e)
{
//Whenever point moves, draw a new transient graphic image at mouse point
DrawTGPolyline(e.Context.RawPoint);
//iterate colorindex, so the jig's color changes with mouse move, thus more eye-catching
mColorIndex += 1;
if (mColorIndex > 8) mColorIndex = 1;
}
private AcApDbSrv.Line GetLine(ObjectId id)
{
AcApDbSrv.Line ln = null;
using (Transaction tran = mDB.TransactionManager.StartOpenCloseTransaction())
{
ln = tran.GetObject(id, OpenMode.ForRead) as AcApDbSrv.Line;
tran.Commit();
}
return ln;
}
private void DrawTGPolyline(Point3d movePoint)
{
//Clear existing transient graphic image
ClearTGPolyline();
//Create a polyline for the transient graphics
mTGPolyline = new AcApDbSrv.Polyline(2);
mTGPolyline.AddVertexAt(0, mTargetLine.StartPoint.Convert2d(planeXY), 0.0, 1.0, 1.0);
mTGPolyline.AddVertexAt(0, mTargetLine.EndPoint.Convert2d(planeXY), 0.0, 1.0, 1.0);
mTGPolyline.SetDatabaseDefaults();
//Set color
mTGPolyline.ColorIndex = mColorIndex;
mTGPolyline.ConstantWidth = transientGraphics.Methods.screenAspectRatio(Convert.ToByte(10.0 * mColorIndex));
//Add transient graphics
IntegerCollection col = new IntegerCollection();
TransientManager.CurrentTransientManager.AddTransient(mTGPolyline, TransientDrawingMode.DirectShortTerm, 128, col);
}
private void ClearTGPolyline()
{
if (mTGPolyline != null)
{
//Remove transient graphic effect
IntegerCollection intCol = new IntegerCollection();
TransientManager.CurrentTransientManager.EraseTransient(mTGPolyline, intCol);
//dispose the polyline used to show transient graphic effect
mTGPolyline.Dispose();
mTGPolyline = null;
}
}
}
}
Here is a video demonstrating my code: http://screencast.com/t/MzgxOWE5MDIt
I've also demonstrated your code from your blog post: http://drive-cad-with-code.blogspot.com/2009/07/help-autocad-users-visually-with_24.html
I've also attached the Visual Studio project and compile DLL. I hope it is OK that I included your code from that blog post.
I'm not completely happy with the results as it is very radical from the entity highlight property but you code certainly provides many opportunities. As you'll see I added code to change the width, based on the screen zoom ratio, as the user moves the cursor.
Thanks for you help!
Doug
-
Glad if my code is of any help. No problem if you quoted/used some of the code.
In my code, I made the entity color change with the mouse moving. It is just to show a possibility of making different visual hint. But in your particular case, seeing from your video clip, the color changing might be a bit annoying to user :-(
Norman,
Your code helped me create what I was hoping to create. Here is the code I created with your help:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using AcApSrvApp = Autodesk.AutoCAD.ApplicationServices.Application;
using AcApDbSrv = Autodesk.AutoCAD.DatabaseServices;
using System;
namespace transientGraphics
{
public class tgLineJig
{
private AcApDbSrv.Polyline mTGPolyline = null;
private AcApDbSrv.Line mTargetLine;
private Editor mEditor;
private Database mDB;
private Document mDoc;
private Point3d mBasePoint;
private int mColorIndex = 1;
private Plane planeXY = new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis);
public tgLineJig(Document doc)
{
mDoc = doc;
mDB = doc.Database;
mEditor = doc.Editor;
}
public void ShowTGJig()
{
transientGraphics.Methods.setOsMode(0);
//Option to pick the target polyline
PromptEntityOptions eOpt = new PromptEntityOptions("\nPick a line:");
//Only allow to pick line
eOpt.SetRejectMessage("\nYou must pick a line:");
eOpt.AddAllowedClass(typeof(AcApDbSrv.Line), true);
//Do the pick
PromptEntityResult eRes = mEditor.GetEntity(eOpt);
if (eRes.Status != PromptStatus.OK) return;
//Get the target polyline
ObjectId targetId = eRes.ObjectId;
AcApDbSrv.Line target = GetLine(targetId);
if (target == null) return;
mTargetLine = target;
//Set base point
mBasePoint = mTargetLine.StartPoint;
//Set base point for second pick so that a rubberband will be shown when mouse is moving
PromptPointOptions opt2 = new PromptPointOptions("\nClick anywhere to exit:");
opt2.AllowArbitraryInput = true;
//Start monitoring pointer move
mEditor.PointMonitor += new PointMonitorEventHandler(mEditor_PointMonitor);
//Start asking user to do second pick (exit) so that the "jig" image will move with mouse
mEditor.GetPoint(opt2);
//Once the second point is picked, clear the transient graphic "jig". After this, since
//a new point is obtained with the jig;s visual help, one can then do copy/move/insert...
ClearTGPolyline();
//End pointer move monitoring
mEditor.PointMonitor -= new PointMonitorEventHandler(mEditor_PointMonitor);
}
private void mEditor_PointMonitor(object sender, PointMonitorEventArgs e)
{
//Whenever point moves, draw a new transient graphic image at mouse point
DrawTGPolyline(e.Context.RawPoint);
//iterate colorindex, so the jig's color changes with mouse move, thus more eye-catching
mColorIndex += 1;
if (mColorIndex > 8) mColorIndex = 1;
}
private AcApDbSrv.Line GetLine(ObjectId id)
{
AcApDbSrv.Line ln = null;
using (Transaction tran = mDB.TransactionManager.StartOpenCloseTransaction())
{
ln = tran.GetObject(id, OpenMode.ForRead) as AcApDbSrv.Line;
tran.Commit();
}
return ln;
}
private void DrawTGPolyline(Point3d movePoint)
{
//Clear existing transient graphic image
ClearTGPolyline();
//Create a polyline for the transient graphics
mTGPolyline = new AcApDbSrv.Polyline(2);
mTGPolyline.AddVertexAt(0, mTargetLine.StartPoint.Convert2d(planeXY), 0.0, 1.0, 1.0);
mTGPolyline.AddVertexAt(0, mTargetLine.EndPoint.Convert2d(planeXY), 0.0, 1.0, 1.0);
mTGPolyline.SetDatabaseDefaults();
//Set color
mTGPolyline.ColorIndex = mColorIndex;
mTGPolyline.ConstantWidth = transientGraphics.Methods.screenAspectRatio(Convert.ToByte(10.0 * mColorIndex));
//Add transient graphics
IntegerCollection col = new IntegerCollection();
TransientManager.CurrentTransientManager.AddTransient(mTGPolyline, TransientDrawingMode.DirectShortTerm, 128, col);
}
private void ClearTGPolyline()
{
if (mTGPolyline != null)
{
//Remove transient graphic effect
IntegerCollection intCol = new IntegerCollection();
TransientManager.CurrentTransientManager.EraseTransient(mTGPolyline, intCol);
//dispose the polyline used to show transient graphic effect
mTGPolyline.Dispose();
mTGPolyline = null;
}
}
}
}
Here is a video demonstrating my code: http://screencast.com/t/MzgxOWE5MDIt
I've also demonstrated your code from your blog post: http://drive-cad-with-code.blogspot.com/2009/07/help-autocad-users-visually-with_24.html
I've also attached the Visual Studio project and compile DLL. I hope it is OK that I included your code from that blog post.
I'm not completely happy with the results as it is very radical from the entity highlight property but you code certainly provides many opportunities. As you'll see I added code to change the width, based on the screen zoom ratio, as the user moves the cursor.
Thanks for you help!
Doug
-
I agree that the user probably won't like my result. I don't much either.
I was thinking of dividing the line down into multiple lines and then coloring them to create a "piano"ing effect. It shouldn't be too difficult. Any other creative ideas for the UI would be appreciated.
And if someone wants to suggest now to make it a timed sequence as opposed to the PointMonitorEventHandler/getPoint method I would like to incorporate that as well.
Thanks!
Doug
-
I've gotten another version for you to take a look at: http://screencast.com/t/NWMyMDkyN
This version uses multiple polylines and is animated as the mouse moves.
Let me know what you think of this version.
Here is the main code and I've attached the Visual Studio project.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using AcApSrvApp = Autodesk.AutoCAD.ApplicationServices.Application;
using AcApDbSrv = Autodesk.AutoCAD.DatabaseServices;
using System;
namespace transientGraphics
{
public class tgLineJig2
{
private static AcApDbSrv.Line mTargetLine;
private static AcApDbSrv.Polyline[] tgPolylines = new AcApDbSrv.Polyline[0];
private static double screenRatio;
private static double nPlines;
private static double plineLength;
private static double lineAngle;
private static int widthIndex = 1;
private static Plane planeXY = new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis);
private static Editor mEditor;
private static Database mDB;
public tgLineJig2(Document doc)
{
mDB = doc.Database;
mEditor = doc.Editor;
}
public void ShowTGJig()
{
//Option to pick the target polyline
PromptEntityOptions eOpt = new PromptEntityOptions("\nPick a line:");
//Only allow to pick line
eOpt.SetRejectMessage("\nYou must pick a line:");
eOpt.AddAllowedClass(typeof(AcApDbSrv.Line), true);
//Do the pick
PromptEntityResult eRes = mEditor.GetEntity(eOpt);
if (eRes.Status != PromptStatus.OK) return;
//Get the target polyline
ObjectId targetId = eRes.ObjectId;
AcApDbSrv.Line target = Methods.GetLine(mDB, targetId);
if (target == null) return;
mTargetLine = target;
lineAngle = mTargetLine.Angle;
Methods.setOsMode(0);
//Set base point for second pick so that a rubberband will be shown when mouse is moving
PromptPointOptions opt2 = new PromptPointOptions("\nClick anywhere to exit:");
opt2.AllowArbitraryInput = true;
//Start monitoring pointer move
mEditor.PointMonitor += new PointMonitorEventHandler(mEditor_PointMonitor);
//Start asking user to do second pick (exit) so that the "jig" image will move with mouse
mEditor.GetPoint(opt2);
//Once the second point is picked, clear the transient graphic "jig". After this, since
//a new point is obtained with the jig;s visual help, one can then do copy/move/insert...
ClearTGPolyline();
//End pointer move monitoring
mEditor.PointMonitor -= new PointMonitorEventHandler(mEditor_PointMonitor);
}
private static void mEditor_PointMonitor(object sender, PointMonitorEventArgs e)
{
//Whenever point moves, draw a new transient graphic image at mouse point
DrawTGPolyline(e.Context.RawPoint);
}
private static void DrawTGPolyline(Point3d movePoint)
{
//Clear existing transient graphic image
ClearTGPolyline();
tgPolylines = new AcApDbSrv.Polyline[0];
screenRatio = Methods.screenAspectRatio();
nPlines = (int)Math.Truncate(mTargetLine.Length / screenRatio) / 4;
plineLength = mTargetLine.Length / nPlines;
Point3d sp = mTargetLine.StartPoint;
Point3d ep = Methods.Polar(sp, lineAngle, plineLength);
for (int i = 0; i < nPlines; i++)
{
if (widthIndex % 8 == 0)
{
//Create a polyline for the transient graphics
AcApDbSrv.Polyline tgPolyline = new AcApDbSrv.Polyline(2);
tgPolyline.AddVertexAt(0, sp.Convert2d(planeXY), 0.0, 1.0, 1.0);
tgPolyline.AddVertexAt(0, ep.Convert2d(planeXY), 0.0, 1.0, 1.0);
tgPolyline.SetDatabaseDefaults();
//Set width
tgPolyline.ConstantWidth = Methods.screenAspectRatio(Convert.ToByte(5));
//Add transient graphics
IntegerCollection col = new IntegerCollection();
TransientManager.CurrentTransientManager.AddTransient(tgPolyline, TransientDrawingMode.DirectShortTerm, 128, col);
tgPolylines = (AcApDbSrv.Polyline[])Methods.ResizeArray(tgPolylines, tgPolylines.Length + 1);
tgPolylines[tgPolylines.Length - 1] = tgPolyline;
}
sp = Methods.Polar(sp, lineAngle, plineLength);
ep = Methods.Polar(ep, lineAngle, plineLength);
widthIndex++;
if (widthIndex > 8)
widthIndex = 1;
}
}
private static void ClearTGPolyline()
{
if (tgPolylines.Length > 0)
{
IntegerCollection intCol = new IntegerCollection();
for (int i = 0; i < tgPolylines.Length; i++)
{
//Remove transient graphic effect
TransientManager.CurrentTransientManager.EraseTransient(tgPolylines[i], intCol);
//dispose the polyline used to show transient graphic effect
tgPolylines[i].Dispose();
}
}
}
}
}
-
Here is my unsuccessful attempt at getting it to run for a certain amount of time and not based on the movement of the mouse and a getPoint:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using AcApSrvApp = Autodesk.AutoCAD.ApplicationServices.Application;
using AcApDbSrv = Autodesk.AutoCAD.DatabaseServices;
using System;
using System.Threading;
namespace transientGraphics
{
public class tgLineJig3
{
private static AcApDbSrv.Line mTargetLine;
private static AcApDbSrv.Polyline[] tgPolylines = new AcApDbSrv.Polyline[0];
private static double screenRatio;
private static double nPlines;
private static double plineLength;
private static double lineAngle;
private static int widthIndex = 1;
private static Plane planeXY = new Plane(new Point3d(0, 0, 0), Vector3d.ZAxis);
private static Editor mEditor;
private static Database mDB;
public tgLineJig3(Document doc)
{
mDB = doc.Database;
mEditor = doc.Editor;
}
public void ShowTGJig()
{
//Option to pick the target polyline
PromptEntityOptions eOpt = new PromptEntityOptions("\nPick a line:");
//Only allow to pick line
eOpt.SetRejectMessage("\nYou must pick a line:");
eOpt.AddAllowedClass(typeof(AcApDbSrv.Line), true);
//Do the pick
PromptEntityResult eRes = mEditor.GetEntity(eOpt);
if (eRes.Status != PromptStatus.OK) return;
//Get the target polyline
ObjectId targetId = eRes.ObjectId;
AcApDbSrv.Line target = Methods.GetLine(mDB, targetId);
if (target == null) return;
mTargetLine = target;
lineAngle = mTargetLine.Angle;
for (int i = 0; i < 100; i++)
{
DrawTGPolylines();
Thread.Sleep(100);
}
//Once the second point is picked, clear the transient graphic "jig". After this, since
//a new point is obtained with the jig;s visual help, one can then do copy/move/insert...
ClearTGPolyline();
}
private static void DrawTGPolylines()
{
//Clear existing transient graphic image
ClearTGPolyline();
tgPolylines = new AcApDbSrv.Polyline[0];
screenRatio = Methods.screenAspectRatio();
nPlines = (int)Math.Truncate(mTargetLine.Length / screenRatio) / 4;
plineLength = mTargetLine.Length / nPlines;
Point3d sp = mTargetLine.StartPoint;
Point3d ep = Methods.Polar(sp, lineAngle, plineLength);
for (int i = 0; i < nPlines; i++)
{
if (widthIndex % 8 == 0)
{
//Create a polyline for the transient graphics
AcApDbSrv.Polyline tgPolyline = new AcApDbSrv.Polyline(2);
tgPolyline.AddVertexAt(0, sp.Convert2d(planeXY), 0.0, 1.0, 1.0);
tgPolyline.AddVertexAt(0, ep.Convert2d(planeXY), 0.0, 1.0, 1.0);
tgPolyline.SetDatabaseDefaults();
//Set width
tgPolyline.ConstantWidth = Methods.screenAspectRatio(Convert.ToByte(5));
//Add transient graphics
IntegerCollection col = new IntegerCollection();
TransientManager.CurrentTransientManager.AddTransient(tgPolyline, TransientDrawingMode.DirectShortTerm, 128, col);
tgPolylines = (AcApDbSrv.Polyline[])Methods.ResizeArray(tgPolylines, tgPolylines.Length + 1);
tgPolylines[tgPolylines.Length - 1] = tgPolyline;
}
sp = Methods.Polar(sp, lineAngle, plineLength);
ep = Methods.Polar(ep, lineAngle, plineLength);
widthIndex++;
if (widthIndex > 8)
widthIndex = 1;
}
}
private static void ClearTGPolyline()
{
if (tgPolylines.Length > 0)
{
IntegerCollection intCol = new IntegerCollection();
for (int i = 0; i < tgPolylines.Length; i++)
{
//Remove transient graphic effect
TransientManager.CurrentTransientManager.EraseTransient(tgPolylines[i], intCol);
//dispose the polyline used to show transient graphic effect
tgPolylines[i].Dispose();
}
}
}
}
}
Suggestions on how to make it work are appreciated. :)
-
Another possible approach you can look into: HighlightOverrule.
I just posted some simple code on this here:
http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html (http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html)
It might open your mind for more choices.
-
Hi Norman,
Thanks for adding that example as well!!!
Doug
-
Another possible approach you can look into: HighlightOverrule.
I just posted some simple code on this here:
http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html (http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html)
Hi Norman,
wonder why it's necessary to lock the document, since the operation is on the current doc.
Hope you dont't mind that I've ported your example to f#, which allows a succinct expression of the singleton pattern required in Overrule and avoids the pitfalls associated with properties on uninitialized objects. What happens if you execute HLColor before MyHLOn? <evil grin>
// Originally c# by Norman Yuan
// http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Runtime
type acApp = Autodesk.AutoCAD.ApplicationServices.Application
type MyHighlightOverrule() as this =
inherit HighlightOverrule()
let mutable _colorIndex = 1
let mutable _oldColorIndex = 1
do MyHighlightOverrule.AddOverrule(
RXClass.GetClass typeof<Polyline>, this, true )
member x.ColorIndex
with set v = _colorIndex <- v
and get() = _colorIndex
override x.Highlight(entity, subId, highlightAll) =
match entity with
| :? Polyline as pline ->
let doc = acApp.DocumentManager.MdiActiveDocument
use dl = doc.LockDocument()
use tr = doc.TransactionManager.StartTransaction()
pline.UpgradeOpen()
_oldColorIndex <- pline.ColorIndex
pline.ColorIndex <- _colorIndex
pline.DowngradeOpen()
base.Highlight(entity, subId, highlightAll)
| _ -> ()
override x.Unhighlight(entity, subId, highlightAll) =
match entity with
| :? Polyline as pline ->
let doc = acApp.DocumentManager.MdiActiveDocument
use dl = doc.LockDocument()
use tr = doc.TransactionManager.StartTransaction()
pline.UpgradeOpen()
pline.ColorIndex <- _oldColorIndex
pline.DowngradeOpen()
base.Unhighlight(entity, subId, highlightAll)
| _ -> ()
module Commands =
let hlOverRule = lazy(new MyHighlightOverrule())
[<CommandMethod "MyHLOn">]
let TurnOnMyHighlight() =
hlOverRule.Force() |> ignore
MyHighlightOverrule.Overruling <- true
[<CommandMethod "MyHLOff">]
let TurnOffMyHighlight() =
hlOverRule.Force() |> ignore
MyHighlightOverrule.Overruling <- false
[<CommandMethod "HLColor">]
let SetHighlightColor() =
let ed = acApp.DocumentManager.MdiActiveDocument.Editor
let pir =
new PromptIntegerOptions(
"\nEnter color index (a number form 1 to 7):",
LowerLimit = 1,
UpperLimit = 7 )
|> ed.GetInteger
if pir.Status = PromptStatus.OK then
hlOverRule.Value.ColorIndex <- pir.Value
Cheers, Thorsten
-
1. Yes, that is a bug that if you execute "HLColor" before "MyHLOn". IN the "HLColor" command method, I am supposed to start with something like below as the first line of code:
If (_hlOverrule==null) return;
2. Locking document. SInce the custom HighlightOverrule might be used in other programs, such as a modeless window, where locking document might be required, so I simply do the locking inside the Highlight/Unhighlight, so that the other programs that use this component would not have to lock document just because of the custom highlight/unhighlight. Of course if the other programs need to lock document because of their own process, there would be nested locking, and there may be penalties on Acad performance, but it would be safer and easier for the other programs to use this component.
Another possible approach you can look into: HighlightOverrule.
I just posted some simple code on this here:
http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html (http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html)
Hi Norman,
wonder why it's necessary to lock the document, since the operation is on the current doc.
Hope you dont't mind that I've ported your example to f#, which allows a succinct expression of the singleton pattern required in Overrule and avoids the pitfalls associated with properties on uninitialized objects. What happens if you execute HLColor before MyHLOn? <evil grin>
// Originally c# by Norman Yuan
// http://drive-cad-with-code.blogspot.com/2010/09/highlight-autocad-entity-in-your-own.html
open Autodesk.AutoCAD.DatabaseServices
open Autodesk.AutoCAD.EditorInput
open Autodesk.AutoCAD.Runtime
type acApp = Autodesk.AutoCAD.ApplicationServices.Application
type MyHighlightOverrule() as this =
inherit HighlightOverrule()
let mutable _colorIndex = 1
let mutable _oldColorIndex = 1
do MyHighlightOverrule.AddOverrule(
RXClass.GetClass typeof<Polyline>, this, true )
member x.ColorIndex
with set v = _colorIndex <- v
and get() = _colorIndex
override x.Highlight(entity, subId, highlightAll) =
match entity with
| :? Polyline as pline ->
let doc = acApp.DocumentManager.MdiActiveDocument
use dl = doc.LockDocument()
use tr = doc.TransactionManager.StartTransaction()
pline.UpgradeOpen()
_oldColorIndex <- pline.ColorIndex
pline.ColorIndex <- _colorIndex
pline.DowngradeOpen()
base.Highlight(entity, subId, highlightAll)
| _ -> ()
override x.Unhighlight(entity, subId, highlightAll) =
match entity with
| :? Polyline as pline ->
let doc = acApp.DocumentManager.MdiActiveDocument
use dl = doc.LockDocument()
use tr = doc.TransactionManager.StartTransaction()
pline.UpgradeOpen()
pline.ColorIndex <- _oldColorIndex
pline.DowngradeOpen()
base.Unhighlight(entity, subId, highlightAll)
| _ -> ()
module Commands =
let hlOverRule = lazy(new MyHighlightOverrule())
[<CommandMethod "MyHLOn">]
let TurnOnMyHighlight() =
hlOverRule.Force() |> ignore
MyHighlightOverrule.Overruling <- true
[<CommandMethod "MyHLOff">]
let TurnOffMyHighlight() =
hlOverRule.Force() |> ignore
MyHighlightOverrule.Overruling <- false
[<CommandMethod "HLColor">]
let SetHighlightColor() =
let ed = acApp.DocumentManager.MdiActiveDocument.Editor
let pir =
new PromptIntegerOptions(
"\nEnter color index (a number form 1 to 7):",
LowerLimit = 1,
UpperLimit = 7 )
|> ed.GetInteger
if pir.Status = PromptStatus.OK then
hlOverRule.Value.ColorIndex <- pir.Value
Cheers, Thorsten