雪山飞狐_lzh 发表于 2009-9-1 22:26:00

Kean专题(15)—User_Interface

http://through-the-interface.typepad.com/through_the_interface/user_interface
一、加载局部CUI,并显示工具栏
November 01, 2006
Loading a partial CUI and making its toolbars visible through .NET
A discussion in the comments on this previous entry seemed worthy of turning into a post.
The problem appears to be that when you load a partial CUI file into AutoCAD, by default the various resources (pull-down menus, toolbars) are not displayed.
This snippet of code shows you how to both load a CUI file into AutoCAD and then loop through the toolbars in your menu-group, making them all visible. You could extend it fairly easily to add the pull-down menus contained in the CUI by using mg.Menus.InsertMenuInMenuBar(). I'm choosing to leave that as an exercise for the reader mainly because the choice of where the various menus go can be quite specific to individual applications... toolbars are much simpler - we're just going to turn them all on. :-)
So here's the code... for convenience I wrote it in VB.NET, but it uses COM Interop to access the menu API in AutoCAD.
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Interop
Public Class ToolbarCmds
<CommandMethod("LoadTBs")> _
Public Sub LoadToolbars()
    Const cuiname As String = "mycuiname"
    Const cuifile As String = "c:\mycuifile.cui"
    Dim mg As AcadMenuGroup
    Try
      'Attempt to access our menugroup
      mg = Application.MenuGroups.Item(cuiname)
    Catch ex As System.Exception
      'Failure simply means we need to load the CUI first
      Application.MenuGroups.Load(cuifile)
      mg = Application.MenuGroups.Item(cuiname)
    End Try
    'Cycle through the toobars, setting them to visible
    Dim i As Integer
    For i = 0 To mg.Toolbars.Count - 1
      mg.Toolbars.Item(i).Visible = True
    Next
End Sub
End Class

雪山飞狐_lzh 发表于 2009-9-1 22:35:00

二、允许用户摆脱长事务
February 28, 2007
Allowing users to escape from long operations in AutoCAD .NET
The bulk of this code was donated by Virupaksha Aithal, a member of our DevTech team in India.
It's fairly common for developers to want to check for user input from time to time during long operations, especially to see whether the user wants to cancel the current activity. In VB you'd use DoEvents() to enable messages to be processed by the application's message loop and in ObjectARX you'd use acedUsrBrk().
So how to do this in .NET?
The answer is to use a message filter. This allows us to check on user-input events... we still call DoEvents, as with previous versions of VB, which allows user input events (such as keystrokes) to flow into our message filter function. We can then detect the events we care about, and filter them out, if necessary.
This C# code filters all keystrokes during a loop operation, and allows the application to respond in its own way to the user hitting the Escape key:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Windows.Forms;
namespace LoopTest
{
public class LoopCommands
{
   
    static public void Loop()
    {
      DocumentCollection dm =
      Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;
      Editor ed =
      dm.MdiActiveDocument.Editor;
      // Create and add our message filter
      MyMessageFilter filter = new MyMessageFilter();
      System.Windows.Forms.Application.AddMessageFilter(filter);
      // Start the loop
      while (true)
      {
      // Check for user input events
      System.Windows.Forms.Application.DoEvents();
      // Check whether the filter has set the flag
      if (filter.bCanceled == true)
      {
          ed.WriteMessage("\nLoop cancelled.");
          break;
      }
      ed.WriteMessage("\nInside while loop...");
      }
      // We're done - remove the message filter
      System.Windows.Forms.Application.RemoveMessageFilter(filter);
    }
    // Our message filter class
    public class MyMessageFilter : IMessageFilter
    {
      public const int WM_KEYDOWN = 0x0100;
      public bool bCanceled = false;
      public bool PreFilterMessage(ref Message m)
      {
      if (m.Msg == WM_KEYDOWN)
      {
          // Check for the Escape keypress
          Keys kc = (Keys)(int)m.WParam & Keys.KeyCode;
          if (m.Msg == WM_KEYDOWN && kc == Keys.Escape)
          {
            bCanceled = true;
          }
          // Return true to filter all keypresses
          return true;
      }
      // Return false to let other messages through
      return false;
      }
    }
}
}

雪山飞狐_lzh 发表于 2009-9-1 22:40:00

本帖最后由 作者 于 2009-9-9 18:44:24 编辑

三、显示填充对话框
March 16, 2007
Showing AutoCAD's hatch dialog from a .NET application
This question was posted by csharpbird:
    How to get the Hatch dialog using .NET? It seems that there is no such class in the .NET API?
It's true there is no public class - or even a published function - to show the hatch dialog inside AutoCAD. It is, however, possible to P/Invoke an unpublished (and therefore unsupported and liable to change without warning) function exported from acad.exe.
Here's some C# code that shows how. The code works for AutoCAD 2007, but will be different for AutoCAD 2006: the function takes and outputs strings, so the change to Unicode in 2007 will have modified the function signature.
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.ApplicationServices;
using System.Reflection;
using System.Runtime.InteropServices;
namespace HatchDialogTest
{
public class Commands
{
    [DllImport(
      "acad.exe",
      EntryPoint =
          "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z",
      CharSet = CharSet.Auto
      )
    ]
    static extern bool acedHatchPalletteDialog(
      string currentPattern,
      bool showcustom,
      out string newpattern
    );
   
    static public void ShowHatchDialog()
    {
      string sHatchType;
      string sNewHatchType;
      bool bRet;
      sHatchType = "ANGLE";
      bRet =
      acedHatchPalletteDialog(
          sHatchType,
          true,
          out sNewHatchType
      );
      if (bRet)
      {
      Editor ed =
          Application.DocumentManager.MdiActiveDocument.Editor;
      ed.WriteMessage(
          "\nHatch type selected: " + sNewHatchType
      );
      }
    }
}
}
Here's what happens when you run the code:
Command: SHD

Hatch type selected: SWAMP
Update
Someone asked me for the VB.NET code for this one (it was quite tricky to marshall the new string being returned). As I'd put it together, I thought I'd post it here:
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput
Imports System.Text
Namespace HatchDialogTest
Public Class Commands
    Private Declare Auto Function acedHatchPalletteDialog _
    Lib "acad.exe" _
    Alias "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z" _
    (ByVal currentPattern As String, _
    ByVal showcustom As Boolean, _
    ByRef newpattern As StringBuilder) As Boolean
    <CommandMethod("SHD")> _
    Public Sub ShowHatchDialog()
      Dim sHatchType As String = "ANGLE"
      Dim sNewHatchType As New StringBuilder
      Dim bRet As Boolean = _
      acedHatchPalletteDialog(sHatchType, _
          True, sNewHatchType)
      If bRet And sNewHatchType.ToString.Length > 0 Then
      Dim ed As Editor
      ed = _
          Application.DocumentManager.MdiActiveDocument.Editor
      ed.WriteMessage( _
          vbLf + "Hatch type selected: " + _
          sNewHatchType.ToString)
      End If
    End Sub
End Class
End NamespaceUpdate 2
I've recently come back to this post at the prompting of a colleague who was struggling to get it working with AutoCAD 2010. Sure enough, the dialog would appear but the marshalling back of the return string to AutoCAD is now causing a problem, for some unknown reason (at least it's unknown to me :-).
Anyway - to address the issue I've updated the code to perform the string marshalling a little more explicitly, and it now works. This may also address the issue one of the people commenting on this post experienced trying to get the code to work with AutoCAD 2009 (although I do remember testing it there and having no issues, which has me scratching my head somewhat).
Here's the updated C# code:using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using System.Runtime.InteropServices;
using System;

namespace HatchDialogTest
{
public class Commands
{
    [DllImport(
      "acad.exe",
      EntryPoint =
          "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z",
      CharSet = CharSet.Auto
      )
    ]
    static extern bool acedHatchPalletteDialog(
      string currentPattern,
      bool showcustom,
      out IntPtr newpattern
    );

   
    static public void ShowHatchDialog()
    {
      string sHatchType = "ANGLE";
      IntPtr ptr;
      bool bRet =
      acedHatchPalletteDialog(
          sHatchType,
          true,
          out ptr
      );
      if (bRet)
      {
      string sNewHatchType = Marshal.PtrToStringAuto(ptr);
      if (sNewHatchType.Length > 0)
      {
          Editor ed =
            Application.DocumentManager.MdiActiveDocument.Editor;
          ed.WriteMessage(
            "\nHatch type selected: " + sNewHatchType
          );
      }
      }
    }
}
}
And here's the updated VB code:Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput
Imports System.Runtime.InteropServices
Imports System

Namespace HatchDialogTest

Public Class Commands

    Private Declare Auto Function acedHatchPalletteDialog _
    Lib "acad.exe" _
    Alias "?acedHatchPalletteDialog@@YA_NPB_W_NAAPA_W@Z" _
    (ByVal currentPattern As String, _
    ByVal showcustom As Boolean, _
    ByRef newpattern As IntPtr) As Boolean

    <CommandMethod("SHD")> _
    Public Sub ShowHatchDialog()

      Dim sHatchType As String = "ANGLE"
      Dim ptr As IntPtr
      Dim bRet As Boolean = _
      acedHatchPalletteDialog(sHatchType, _
          True, ptr)
      If bRet Then
      Dim sNewHatchType As String = _
          Marshal.PtrToStringAuto(ptr)
      If sNewHatchType.ToString.Length > 0 Then
          Dim ed As Editor
          ed = _
            Application.DocumentManager.MdiActiveDocument.Editor
          ed.WriteMessage( _
            vbLf + "Hatch type selected: " + sNewHatchType)
      End If
      End If

    End Sub

End Class

End Namespace

雪山飞狐_lzh 发表于 2009-9-1 22:43:00

四、为图元添加上下文菜单
May 04, 2007
Adding a context menu to AutoCAD objects using .NET
It's been quite a week - between interviews for a DevTech position we're working to fill in Beijing and AU proposals (my team managed to pull together and submit nearly 60 API class proposals at the beginning of the week) life has been extremely hectic.
Thankfully we're now in the middle of the "May Day Golden Week" here in China. The Chinese government schedules threeGolden Weeks every year - one for Spring Festival, one for Labour Day (also known as May Day) and one for the National Day. They're basically week-long holidays formed by a few standard holidays and mandating that people work through an adjacent weekend, grouping together the holidays with the days that are freed up into a contiguous week-long break. These weeks are designed to promote domestic tourism, by allowing people to plan vacations well in advance, and they seem to be working, apparently 25% of domestic tourism in China is due to these three Golden Weeks.
Anyway - I've been working, on and off, as my team isn't all based in China, but I did get to spend some quality time with my family. All this to say it's been a week since my last post, so I'm up late on Friday night to assuage my guilt. :-)
I threw some simple code together to show how to add your own custom context menu to a particular type of AutoCAD object using .NET. The below code adds a new context menu at the "Entity" level, which means that as long as only entities are selected in the editor, the context menu will appear. As objects have to be of type Entity to be selectable, I think it's safe to say the context menu will always be accessible. :-)
You could very easily modify the code to only show the menu for a concrete class of object (Lines, Circles, etc.), of course.
So what does this new context menu do? In this case it simply fires off a command, which then selects our entities by accessing the pickfirst selection set, and does something with the selected entities. The actual command I implemented was very simple, indeed: it simply counts the entities selected and writes a message to the command-line.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using System;
namespace ContextMenuApplication
{
public class Commands : IExtensionApplication
{
    public void Initialize()
    {
      CountMenu.Attach();
    }
    public void Terminate()
    {
      CountMenu.Detach();
    }
   
    static public void CountSelection()
    {
      Editor ed =
      Application.DocumentManager.MdiActiveDocument.Editor;
      PromptSelectionResult psr = ed.GetSelection();
      if (psr.Status == PromptStatus.OK)
      {
      ed.WriteMessage(
          "\nSelected {0} entities.",
          psr.Value.Count
      );
      }
    }
}
public class CountMenu
{
    private static ContextMenuExtension cme;
    public static void Attach()
    {
      cme = new ContextMenuExtension();
      MenuItem mi = new MenuItem("Count");
      mi.Click += new EventHandler(OnCount);
      cme.MenuItems.Add(mi);
      RXClass rxc = Entity.GetClass(typeof(Entity));
      Application.AddObjectContextMenuExtension(rxc, cme);
    }
    public static void Detach()
    {
      RXClass rxc = Entity.GetClass(typeof(Entity));
      Application.RemoveObjectContextMenuExtension(rxc, cme);
    }
    private static void OnCount(Object o, EventArgs e)
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      doc.SendStringToExecute("_.COUNT ", true, false, false);
    }
}
}
And here's what we see when we have our application loaded, right-clicking after selecting some AutoCAD objects:

Followed by the somewhat mundane result:
Selected 10 entities.

雪山飞狐_lzh 发表于 2009-9-7 14:55:00

五、在默认上下文菜单中添加
May 07, 2007
It's all in the context: adding a default menu to your AutoCAD application using .NET
To follow on from the last post, we're now going to take a look at adding custom menu items to the default context menu in AutoCAD. The default menu appears when the user right-clicks on the drawing but has no objects selected. This is a good place to put application commands, for instance.
The approach is very similar to the previous one, although I've added some additional commands to control adding and removing the various menus in addition to relying on the module's initialization callback.
Some other notes:
    * We're not just adding a single menu item, but are using a cascading menu - three menu items underneath a main application menu item.
    * Once again we're using the Autodesk.AutoCAD.Internal namespace (which is unsupported and liable to change, and needs the AcMgdInternal.dll assembly referenced), to use the PostCommandPrompt() function. We would not need this if we called our commands via SendStringToExecute(), of course.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.Internal;
using System;
namespace ContextMenuApplication
{
public class Commands : IExtensionApplication
{
    public void Initialize()
    {
      CountMenu.Attach();
      ApplicationMenu.Attach();
    }
    public void Terminate()
    {
      CountMenu.Detach();
      ApplicationMenu.Detach();
    }
   
    static public void AttachContextMenus()
    {
      CountMenu.Attach();
      ApplicationMenu.Attach();
    }
   
    static public void DetachContextMenus()
    {
      CountMenu.Detach();
      ApplicationMenu.Detach();
    }
   
    static public void CountSelection()
    {
      Editor ed =
      Application.DocumentManager.MdiActiveDocument.Editor;
      PromptSelectionResult psr = ed.GetSelection();
      if (psr.Status == PromptStatus.OK)
      {
      ed.WriteMessage(
          "\nSelected {0} entities.",
          psr.Value.Count
      );
      }
    }
}
public class CountMenu
{
    private static ContextMenuExtension cme;
    public static void Attach()
    {
      if (cme == null)
      {
      cme = new ContextMenuExtension();
      MenuItem mi = new MenuItem("Count");
      mi.Click += new EventHandler(OnCount);
      cme.MenuItems.Add(mi);
      }
      RXClass rxc = Entity.GetClass(typeof(Entity));
      Application.AddObjectContextMenuExtension(rxc, cme);
    }
    public static void Detach()
    {
      RXClass rxc = Entity.GetClass(typeof(Entity));
      Application.RemoveObjectContextMenuExtension(rxc, cme);
    }
    private static void OnCount(Object o, EventArgs e)
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      doc.SendStringToExecute("_.COUNT ", true, false, false);
    }
}
public class ApplicationMenu
{
    private static ContextMenuExtension cme;
    public static void Attach()
    {
      if (cme == null)
      {
      cme = new ContextMenuExtension();
      cme.Title = "Kean's commands";
      MenuItem mi1 = new MenuItem("1st");
      mi1.Click += new EventHandler(On1st);
      cme.MenuItems.Add(mi1);
      MenuItem mi2 = new MenuItem("2nd");
      mi2.Click += new EventHandler(On2nd);
      cme.MenuItems.Add(mi2);
      MenuItem mi3 = new MenuItem("3rd");
      mi3.Click += new EventHandler(On3rd);
      cme.MenuItems.Add(mi3);
      }
      Application.AddDefaultContextMenuExtension(cme);
    }
    public static void Detach()
    {
      Application.RemoveDefaultContextMenuExtension(cme);
    }
    private static void On1st(Object o, EventArgs e)
    {
      Editor ed =
      Application.DocumentManager.MdiActiveDocument.Editor;
      ed.WriteMessage("\nFirst item selected.");
      Utils.PostCommandPrompt();
    }
    private static void On2nd(Object o, EventArgs e)
    {
      Editor ed =
      Application.DocumentManager.MdiActiveDocument.Editor;
      ed.WriteMessage("\nSecond item selected.");
      Utils.PostCommandPrompt();
    }
    private static void On3rd(Object o, EventArgs e)
    {
      Editor ed =
      Application.DocumentManager.MdiActiveDocument.Editor;
      ed.WriteMessage("\nThird item selected.");
      Utils.PostCommandPrompt();
    }
}
}And here are our custom menu items on AutoCAD's default context menu:

雪山飞狐_lzh 发表于 2009-9-7 14:59:00

六、创建局部Cui文件并加载
May 14, 2007
Creating a partial CUI file using .NET and loading it inside AutoCAD
I started to address this topic during this previous post, but it seemed like it was worth coming back to.
This time I'm looking at a different technique: to create our own partial CUI file programmatically using the Autodesk.AutoCAD.Customization functionality, save it to disk and then make sure it's loaded at the beginning of every subsequent AutoCAD session.
I'm not going to focus on adding menus etc. into AutoCAD's list - that's left for a future post - this is mainly about the logic needed to make sure a CUI is created and loaded.
Here's some C# code I put together (with the help of some pointers I took from Wayne Brill, a member of our DevTech Americas team). There's more than one way to skin a cat, as they say, but this seems a reliable way to make sure our partial menu is created and loaded. By the way, you'll need to add AcCui.dll as an assembly reference to your project for this code to build.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Customization;
using System;
using System.Collections.Specialized;
namespace PartialCUI
{
public class Commands : IExtensionApplication
{
    public void Initialize()
    {
      BuildMenuCUI();
    }
    public void Terminate()
    {
    }
   
    public void BuildMenuCUI()
    {
      const string myCuiFile = "c:\\kean.cui";
      const string myCuiFileToSend = "c:/kean.cui";
      const string myCuiSectionName = "Kean";
      Editor ed =
      Application.DocumentManager.MdiActiveDocument.Editor;
      string mainCui =
      Application.GetSystemVariable("MENUNAME") + ".cui";
      CustomizationSection cs =
      new CustomizationSection(mainCui);
      PartialCuiFileCollection pcfc = cs.PartialCuiFiles;
      if (pcfc.Contains(myCuiFile))
      {
      ed.WriteMessage(
          "\nCustomization file \""
          + myCuiFile
          + "\" already loaded."
      );
      }
      else{
      if (System.IO.File.Exists(myCuiFile))
      {
          ed.WriteMessage(
            "\nCustomization file \""
            + myCuiFile
            + "\" exists - loading it."
          );
          LoadMyCui(myCuiFileToSend);
      }
      else
      {
          ed.WriteMessage(
            "\nCustomization file \""
            + myCuiFile
            + "\" does not exist - building it."
          );
          // Create a customization section for our partial menu
          CustomizationSection pcs = new CustomizationSection();
          pcs.MenuGroupName = myCuiSectionName;
          // Let's add a menu group, with two commands
          MacroGroup mg =
            new MacroGroup(myCuiSectionName, pcs.MenuGroup);
          MenuMacro mm1 =
            new MenuMacro(mg, "Cmd 1", "^C^CCmd1", "ID_MyCmd1");
          MenuMacro mm2 =
            new MenuMacro(mg, "Cmd 2", "^C^CCmd2", "ID_MyCmd2");
          // Now let's add a pull-down menu, with two items
          StringCollection sc = new StringCollection();
          sc.Add("POP15");
          PopMenu pm =
            new PopMenu(
            myCuiSectionName,
            sc,
            "ID_MyPop1",
            pcs.MenuGroup
          );
          PopMenuItem pmi1 =
            new PopMenuItem(mm1, "Pop Cmd 1", pm, -1);
          PopMenuItem pmi2 =
            new PopMenuItem(mm2, "Pop Cmd 2", pm, -1);
          // Finally we save the file and load it
          pcs.SaveAs(myCuiFile);
          LoadMyCui(myCuiFileToSend);
      }
      }
    }
    private void LoadMyCui(string cuiFile)
    {
      // This load technique sends a LISP string to the
      // command line (which avoid us having to set FILEDIA
      // to 0) after setting CMDECHO to 0, to minimize
      // what's displayed.
      // We make sure the LISP string resets thevalue of
      // CMDECHO at the end (the string is executed
      // asynchronously, so we don't have the chance to do
      // it in our calling function).
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      object oldCmdEcho = Application.GetSystemVariable("CMDECHO");
      Application.SetSystemVariable("CMDECHO", 0);
      doc.SendStringToExecute(
      "(command \"_.CUILOAD\" \""
      + cuiFile
      + "\")(setvar \"CMDECHO\" "
      + oldCmdEcho
      + ")(princ) "
      , false, false, false
      );
    }
}
}
Here's what happens when we first load our module:
Command: netload
Customization file "c:\kean.cui" does not exist - building it.
Command:
Customization file loaded successfully. Customization Group: KEAN
Command:
Here's what happens when we then run our manual command - "bm" - which calls the same code:
Command: bm
Customization file "c:\kean.cui" already loaded.
Command:
Once created and loaded, the partial menu should be loaded automatically on AutoCAD startup - as shown by the running the CUILOAD command:

If we then unload the file and launch AutoCAD again, loading our module, we see this:
Command: netload
Customization file "c:\kean.cui" exists - loading it.
Command:
Customization file loaded successfully. Customization Group: KEAN
Command:

Update:
The above implementation of the LoadMyCui function has some unfortunate behaviour: it doesn't actually cause the menu to be added to the menu bar. Calling CUILOAD from LISP, should be identical to calling the command directly, but in this case it doesn't appear to be. Thanks to Hongxian Qin, from DevTech China, for analysing the problem. The following implementation works as the code was designed to:
private void LoadMyCui(string cuiFile)
{
Document doc =
    Application.DocumentManager.MdiActiveDocument;
object oldCmdEcho =
    Application.GetSystemVariable("CMDECHO");
object oldFileDia =
    Application.GetSystemVariable("FILEDIA");
Application.SetSystemVariable("CMDECHO", 0);
Application.SetSystemVariable("FILEDIA", 0);
doc.SendStringToExecute(
    "_.cuiload "
    + cuiFile
    + " ",
    false, false, false
);
doc.SendStringToExecute(
    "(setvar \"FILEDIA\" "
    + oldFileDia.ToString()
    + ")(princ) ",
    false, false, false
);
doc.SendStringToExecute(
    "(setvar \"CMDECHO\" "
    + oldCmdEcho.ToString()
    + ")(princ) ",
    false, false, false
);
}

雪山飞狐_lzh 发表于 2009-9-7 15:05:00

七、在长事务中显示状态栏进度条
May 25, 2007
Displaying a progress meter during long operations in AutoCAD using .NET
It's often desirable to show a progress meter during lengthy operations. Although there's currently no public API to make use of AutoCAD's progress meter from .NET, there are nevertheless a couple of approaches to doing so.
In this post I'll show how to do this using P/Invoke (using some code borrowed from Fenton Webb, from DevTech Americas) and in my next post I'll show how to use the "internal" AutoCAD managed assembly.
Here's the C# code that uses P/Invoke, which should work for AutoCAD 2007 and 2008:
using Autodesk.AutoCAD.Runtime;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ProgressMeterTest
{
public class Cmds
{
    [DllImport(
      "acad.exe",
      CharSet = CharSet.Auto,
      CallingConvention = CallingConvention.Cdecl,
      EntryPoint = "?acedSetStatusBarProgressMeter@@YAHPB_WHH@Z"
      //This should work for AutoCAD 2006...
      //EntryPoint = "?acedSetStatusBarProgressMeter@@YAHPBDHH@Z"
)]
    private static extern int
      acedSetStatusBarProgressMeter(
      string label,
      int minPos,
      int maxPos
      );
    [DllImport(
      "acad.exe",
      CharSet = CharSet.Auto,
      CallingConvention = CallingConvention.Cdecl,
      EntryPoint = "?acedSetStatusBarProgressMeterPos@@YAHH@Z"
    )]
    private static extern int
      acedSetStatusBarProgressMeterPos(int pos);
    [DllImport(
      "acad.exe",
      CharSet = CharSet.Auto,
      CallingConvention = CallingConvention.Cdecl,
      EntryPoint = "?acedRestoreStatusBar@@YAXXZ"
    )]
    private static extern int acedRestoreStatusBar();
   
    public void ProgressBar()
    {
      acedSetStatusBarProgressMeter("Testing Progress Bar", 0, 100);
      for (int i = 0; i <= 100; i++)
      {
      for (int j = 0; j <= 10; j++)
      {
          System.Threading.Thread.Sleep(1);
          acedSetStatusBarProgressMeterPos(i);
          // This allows AutoCAD to repaint
          Application.DoEvents();
      }
      }
      acedRestoreStatusBar();
    }
}
}And here's what you see when it runs:

Update:
Thanks to Chris Bray for pointing out the above technique (and the one I was about to show in Part 2) is unnecessary from AutoCAD 2007 onwards. A new class was introduced in AutoCAD 2007 called Autodesk.AutoCAD.Runtime.ProgressMeter.
Here's some C# code that demonstrates the use of this class:
using Autodesk.AutoCAD.Runtime;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ProgressMeterTest
{
public class Cmds
{
   
    public void ProgressBarManaged()
    {
      ProgressMeter pm = new ProgressMeter();
      pm.Start("Testing Progress Bar");
      pm.SetLimit(100);
      // Now our lengthy operation
      for (int i = 0; i <= 100; i++)
      {
      System.Threading.Thread.Sleep(5);
      // Increment Progress Meter...
      pm.MeterProgress();
      // This allows AutoCAD to repaint
      Application.DoEvents();
      }
      pm.Stop();
    }
}
}The original code is still the technique to use for AutoCAD 2005 & 2006, although you will need to uncomment the line in the DllImport attribute for acedSetStatusBarProgressMeter(), to make sure it uses the EntryPoint with the non-Unicode string argument ("?acedSetStatusBarProgressMeter@@YAHPBDHH@Z"). You'll clearly also need to comment out the current EntryPoint assignment, of course.
I'll forego the Part 2 post (and rename this one from Part 1), as there's really no need to look any other technique for this, at this stage.

雪山飞狐_lzh 发表于 2009-9-7 15:17:00

八、显示程序启动画面
June 01, 2007
Showing a splash-screen from your AutoCAD .NET application
Thanks once again to Viru Aithal for the inspiration behind this post, although I did write most of the code, this time. :-)
Adding a splash screen can give a touch of class to your application, assuming it's done non-intrusively. This post focuses on how best to do so within AutoCAD, and use the time it's displayed to perform initialization for your application.
The first thing you need to do is add a Windows Form to your project:

You should select the standard "Windows Form" type, giving an appropriate name (in this case I've used "SplashScreen", imaginatively enough).

Once this is done, you should set the background for the form to be your preferred bitmap image, by browsing to it from the form's BackgroundImage property:

Now we're ready to add some code. Here's some C# code that shows how to show the splash-screen from the Initialize() method:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Prompts; // This is the name of the module
namespace SplashScreenTest
{
public class Startup : IExtensionApplication
{
    public void Initialize()
    {
      SplashScreen ss = new SplashScreen();
      // Rather than trusting these properties to be set
      // at design-time, let's set them here
      ss.StartPosition =
      System.Windows.Forms.FormStartPosition.CenterScreen;
      ss.FormBorderStyle =
      System.Windows.Forms.FormBorderStyle.None;
      ss.Opacity = 0.8;
      ss.TopMost = true;
      ss.ShowInTaskbar = false;
      // Now let's disply the splash-screen
      Application.ShowModelessDialog(
      Application.MainWindow,
      ss,
      false
      );
      ss.Update();
      // This is where your application should initialise,
      // but in our case let's take a 3-second nap
      System.Threading.Thread.Sleep(3000);
      ss.Close();
    }
    public void Terminate()
    {
    }
}
}
Some notes on the code:
    * I used a sample application called "Prompts" - you should change the using directive to refer to your own module name.
    * We're setting a number of properties dynamically (at runtime), rather than stepping through how to set them at design-time.
    * We've set the splash screen to be 80% opaque (or 20% transparent). This is easy to adjust.
    * Some of the additional properties may be redundant, but they seemed sensible to set (at least to me).
Here's the result... I've set up my application to demand-load when I invoke a command, which allowed me to load a DWG first to show off the transparency of the splash-screen (even though the above code doesn't actually define a command - so do expect an "Unknown command" message, if you do exactly the same thing as I have). You may prefer to set the module to load on AutoCAD startup, otherwise.

Update:
Roland Feletic brought it to my attention that this post needed updating for AutoCAD 2010. Thanks, Roland!
I looked into the code, and found that the call to ShowModelessDialog needed changing to this:
      Application.ShowModelessDialog(
      Application.MainWindow.Handle,
      ss,
      false
      );
I also found I had to add an additional assembly reference to PresentationCore (a .NET Framework 3.0 assembly).

雪山飞狐_lzh 发表于 2009-9-7 15:21:00

九、使用AutoCad的文件选择对话框
August 21, 2007
Using AutoCAD's file selection dialog from .NET
Today I started putting together some code showing how to link an Excel sheet to an AutoCAD table (watch this space - there should be something posted later this week). As I was working through it I decided enough was enough, and rather than - yet again - using the command-line to get the name of the file, I'd use the opportunity to demonstrate how to make use of AutoCAD's standard file selection dialog in your applications.
At which point I decided to cut the original post short, as I didn't want this useful (but quite short) topic to get swamped by the broader one.
Here's the C# code that asks the user to select an Excel spreadsheet:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
namespace OpenFiles
{
public class Commands
{
   
    static public void SelectSpreadsheet()
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      Database db = doc.Database;
      Editor ed = doc.Editor;
      OpenFileDialog ofd =
      new OpenFileDialog(
          "Select Excel spreadsheet to link",
          null,
          "xls; xlsx",
          "ExcelFileToLink",
          OpenFileDialog.OpenFileDialogFlags.DoNotTransferRemoteFiles
      );
      System.Windows.Forms.DialogResult dr =
      ofd.ShowDialog();
      if (dr != System.Windows.Forms.DialogResult.OK)
      return;
      ed.WriteMessage(
      "\nFile selected was \"{0}\".",
      ofd.Filename
      );
    }
}
}
A few notes on the arguments to the OpenFileDialog constructor:
   1. The first string is the one shown in the title bar (see below)
   2. You can pass in a default filename in the second argument, but in our case it isn't appropriate
   3. You can provide multiple file extensions upon which to filter in the third argument, separated by semi-colons
   4. The fourth argument is an internal identifier used to store data about the dialog, such as size, position and last navigated path (this data will be picked up automatically the next time the identifier is used)
   5. The fifth argument is for flags: we're choosing not to copy remote files locally if selected via a URL, in this case
If we were opting to allow multiple file selection (passing AllowMultiple as an additional flag to the fifth argument), then we would access the files returned using ofd.GetFileNames() to access an array of strings.
Here's the dialog we see when we run the SS command:

雪山飞狐_lzh 发表于 2009-9-7 15:29:00

十、派生自定义的颜色组合框
March 20, 2008
Implementing your own AutoCAD color combobox control using .NET
A big thanks to Scott McFarlane, from Geotropix, Inc., for sharing the code in this post. Here's an email I received from Scott:
    I was reading this blog entry on “Through the Interface” and some folks were asking about how to implement .NET combo box versions of the color and linetype ActiveX controls that are available. I just wanted to share a simple .NET implementation of a color combo box. The color combo is quite easy, really. The linetype one would be more difficult.
    Attached is the source code. This is just a generic color combo, that loads up with the 255 ACI colors. It has no dependency on AutoCAD – I was actually using this in an external program. It would be easy, however, to modify this to provide a list item to launch the built-in AutoCAD color dialog if used inside AutoCAD.
Here is the C# code Scott provided (which was in a source file named AcColorComboBox.cs): using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
public class AcColorComboBox : ComboBox
{
public class ColorItem
{
    private short _colorIndex;
    private Color _color;
    public ColorItem(short colorIndex, Color color)
    {
      _colorIndex = colorIndex;
      _color = color;
    }
    public short ColorIndex
    {
      get { return _colorIndex; }
    }
    public Color Color
    {
      get { return _color; }
    }
    public override string ToString()
    {
      return AcColorComboBox.ColorNameOf(_colorIndex);
    }
}
public class ColorItemSorter : IComparer
{
    public int Compare(object x, object y)
    {
      return ((ColorItem)x).ColorIndex - ((ColorItem)y).ColorIndex;
    }
}
private short _colorIndex;
#region " Windows Form Designer generated code "
public AcColorComboBox()
    : base()
{
    // This call is required by the Windows Form Designer.
    InitializeComponent();
    // Add any initialization after the InitializeComponent() call
    DrawMode = DrawMode.OwnerDrawFixed;
    DropDownStyle = ComboBoxStyle.DropDownList;
}
// Override dispose to clean up the component list.
protected override void Dispose(bool disposing)
{
    if (disposing)
    {
      if ((components != null))
      {
      components.Dispose();
      }
    }
    base.Dispose(disposing);
}
// Required by the Windows Form Designer
private System.ComponentModel.IContainer components;
// NOTE: The following procedure is required by the Windows Form Designer
// It can be modified using the Windows Form Designer.
// Do not modify it using the code editor.

private void InitializeComponent()
{
    components = new System.ComponentModel.Container();
}
#endregion
protected override void OnDrawItem(System.Windows.Forms.DrawItemEventArgs e)
{
    if (e.Index >= 0)
    {
      e.DrawBackground();
      e.DrawFocusRectangle();
      Rectangle r = e.Bounds;
      r.Inflate(-1, -1);
      r.Width = 20;
      r.Offset(1, 0);
      ColorItem objColor = (ColorItem)Items;
      e.Graphics.FillRectangle(new System.Drawing.SolidBrush(objColor.Color), r);
      e.Graphics.DrawRectangle(new System.Drawing.Pen(Color.Black), r);
      e.Graphics.DrawString(objColor.ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds.X + r.Width + 4, e.Bounds.Y);
    }
}
protected override void OnCreateControl()
{
    Items.Clear();
    for (short i = 1; i < 256; i++)
      Items.Add(new ColorItem(i, ColorOf(i)));
    base.OnCreateControl();
}
// ColorValue represents colorId
public short ColorIndex
{
    get { return _colorIndex; }
    set
    {
      _colorIndex = value;
      foreach (ColorItem objColor in Items)
      {
      if (objColor.ColorIndex == value)
      {
          SelectedItem = objColor;
          break;
      }
      }
    }
}
protected override void OnSelectedIndexChanged(System.EventArgs e)
{
    _colorIndex = ((ColorItem)Items).ColorIndex;
    base.OnSelectedIndexChanged(e);
}
public static string ColorNameOf(short colorIndex)
{
    switch (colorIndex)
    {
      case 1:
      return "1 - Red";
      case 2:
      return "2 - Yellow";
      case 3:
      return "3 - Green";
      case 4:
      return "4 - Cyan";
      case 5:
      return "5 - Blue";
      case 6:
      return "6 - Magenta";
      case 7:
      return "7 - White";
      case 8:
      return "8 - Grey";
      default:
      return colorIndex.ToString();
    }
}
public static Color ColorOf(short colorIndex)
{
    switch (colorIndex)
    {
      case 1:
      return Color.FromArgb(255, 0, 0);
      case 2:
      return Color.FromArgb(255, 255, 0);
      case 3:
      return Color.FromArgb(0, 255, 0);
      case 4:
      return Color.FromArgb(0, 255, 255);
      case 5:
      return Color.FromArgb(0, 0, 255);
      case 6:
      return Color.FromArgb(255, 0, 255);
      case 7:
      return Color.FromArgb(255, 255, 255);
      case 8:
      return Color.FromArgb(128, 128, 128);
      case 9:
      return Color.FromArgb(192, 192, 192);
      case 10:
      return Color.FromArgb(255, 0, 0);
      case 11:
      return Color.FromArgb(255, 127, 127);
      case 12:
      return Color.FromArgb(204, 0, 0);
      case 13:
      return Color.FromArgb(204, 102, 102);
      case 14:
      return Color.FromArgb(153, 0, 0);
      case 15:
      return Color.FromArgb(153, 76, 76);
      case 16:
      return Color.FromArgb(127, 0, 0);
      case 17:
      return Color.FromArgb(127, 63, 63);
      case 18:
      return Color.FromArgb(76, 0, 0);
      case 19:
      return Color.FromArgb(76, 38, 38);
      case 20:
      return Color.FromArgb(255, 63, 0);
      case 21:
      return Color.FromArgb(255, 159, 127);
      case 22:
      return Color.FromArgb(204, 51, 0);
      case 23:
      return Color.FromArgb(204, 127, 102);
      case 24:
      return Color.FromArgb(153, 38, 0);
      case 25:
      return Color.FromArgb(153, 95, 76);
      case 26:
      return Color.FromArgb(127, 31, 0);
      case 27:
      return Color.FromArgb(127, 79, 63);
      case 28:
      return Color.FromArgb(76, 19, 0);
      case 29:
      return Color.FromArgb(76, 47, 38);
      case 30:
      return Color.FromArgb(255, 127, 0);
      case 31:
      return Color.FromArgb(255, 191, 127);
      case 32:
      return Color.FromArgb(204, 102, 0);
      case 33:
      return Color.FromArgb(204, 153, 102);
      case 34:
      return Color.FromArgb(153, 76, 0);
      case 35:
      return Color.FromArgb(153, 114, 76);
      case 36:
      return Color.FromArgb(127, 63, 0);
      case 37:
      return Color.FromArgb(127, 95, 63);
      case 38:
      return Color.FromArgb(76, 38, 0);
      case 39:
      return Color.FromArgb(76, 57, 38);
      case 40:
      return Color.FromArgb(255, 191, 0);
      case 41:
      return Color.FromArgb(255, 223, 127);
      case 42:
      return Color.FromArgb(204, 153, 0);
      case 43:
      return Color.FromArgb(204, 178, 102);
      case 44:
      return Color.FromArgb(153, 114, 0);
      case 45:
      return Color.FromArgb(153, 133, 76);
      case 46:
      return Color.FromArgb(127, 95, 0);
      case 47:
      return Color.FromArgb(127, 111, 63);
      case 48:
      return Color.FromArgb(76, 57, 0);
      case 49:
      return Color.FromArgb(76, 66, 38);
      case 50:
      return Color.FromArgb(255, 255, 0);
      case 51:
      return Color.FromArgb(255, 255, 127);
      case 52:
      return Color.FromArgb(204, 204, 0);
      case 53:
      return Color.FromArgb(204, 204, 102);
      case 54:
      return Color.FromArgb(153, 153, 0);
      case 55:
      return Color.FromArgb(153, 153, 76);
      case 56:
      return Color.FromArgb(127, 127, 0);
      case 57:
      return Color.FromArgb(127, 127, 63);
      case 58:
      return Color.FromArgb(76, 76, 0);
      case 59:
      return Color.FromArgb(76, 76, 38);
      case 60:
      return Color.FromArgb(191, 255, 0);
      case 61:
      return Color.FromArgb(223, 255, 127);
      case 62:
      return Color.FromArgb(153, 204, 0);
      case 63:
      return Color.FromArgb(178, 204, 102);
      case 64:
      return Color.FromArgb(114, 153, 0);
      case 65:
      return Color.FromArgb(133, 153, 76);
      case 66:
      return Color.FromArgb(95, 127, 0);
      case 67:
      return Color.FromArgb(111, 127, 63);
      case 68:
      return Color.FromArgb(57, 76, 0);
      case 69:
      return Color.FromArgb(66, 76, 38);
      case 70:
      return Color.FromArgb(127, 255, 0);
      case 71:
      return Color.FromArgb(191, 255, 127);
      case 72:
      return Color.FromArgb(102, 204, 0);
      case 73:
      return Color.FromArgb(153, 204, 102);
      case 74:
      return Color.FromArgb(76, 153, 0);
      case 75:
      return Color.FromArgb(114, 153, 76);
      case 76:
      return Color.FromArgb(63, 127, 0);
      case 77:
      return Color.FromArgb(95, 127, 63);
      case 78:
      return Color.FromArgb(38, 76, 0);
      case 79:
      return Color.FromArgb(57, 76, 38);
      case 80:
      return Color.FromArgb(63, 255, 0);
      case 81:
      return Color.FromArgb(159, 255, 127);
      case 82:
      return Color.FromArgb(51, 204, 0);
      case 83:
      return Color.FromArgb(127, 204, 102);
      case 84:
      return Color.FromArgb(38, 153, 0);
      case 85:
      return Color.FromArgb(95, 153, 76);
      case 86:
      return Color.FromArgb(31, 127, 0);
      case 87:
      return Color.FromArgb(79, 127, 63);
      case 88:
      return Color.FromArgb(19, 76, 0);
      case 89:
      return Color.FromArgb(47, 76, 38);
      case 90:
      return Color.FromArgb(0, 255, 0);
      case 91:
      return Color.FromArgb(127, 255, 127);
      case 92:
      return Color.FromArgb(0, 204, 0);
      case 93:
      return Color.FromArgb(102, 204, 102);
      case 94:
      return Color.FromArgb(0, 153, 0);
      case 95:
      return Color.FromArgb(76, 153, 76);
      case 96:
      return Color.FromArgb(0, 127, 0);
      case 97:
      return Color.FromArgb(63, 127, 63);
      case 98:
      return Color.FromArgb(0, 76, 0);
      case 99:
      return Color.FromArgb(38, 76, 38);
      case 100:
      return Color.FromArgb(0, 255, 63);
      case 101:
      return Color.FromArgb(127, 255, 159);
      case 102:
      return Color.FromArgb(0, 204, 51);
      case 103:
      return Color.FromArgb(102, 204, 127);
      case 104:
      return Color.FromArgb(0, 153, 38);
      case 105:
      return Color.FromArgb(76, 153, 95);
      case 106:
      return Color.FromArgb(0, 127, 31);
      case 107:
      return Color.FromArgb(63, 127, 79);
      case 108:
      return Color.FromArgb(0, 76, 19);
      case 109:
      return Color.FromArgb(38, 76, 47);
      case 110:
      return Color.FromArgb(0, 255, 127);
      case 111:
      return Color.FromArgb(127, 255, 191);
      case 112:
      return Color.FromArgb(0, 204, 102);
      case 113:
      return Color.FromArgb(102, 204, 153);
      case 114:
      return Color.FromArgb(0, 153, 76);
      case 115:
      return Color.FromArgb(76, 153, 114);
      case 116:
      return Color.FromArgb(0, 127, 63);
      case 117:
      return Color.FromArgb(63, 127, 95);
      case 118:
      return Color.FromArgb(0, 76, 38);
      case 119:
      return Color.FromArgb(38, 76, 57);
      case 120:
      return Color.FromArgb(0, 255, 191);
      case 121:
      return Color.FromArgb(127, 255, 223);
      case 122:
      return Color.FromArgb(0, 204, 153);
      case 123:
      return Color.FromArgb(102, 204, 178);
      case 124:
      return Color.FromArgb(0, 153, 114);
      case 125:
      return Color.FromArgb(76, 153, 133);
      case 126:
      return Color.FromArgb(0, 127, 95);
      case 127:
      return Color.FromArgb(63, 127, 111);
      case 128:
      return Color.FromArgb(0, 76, 57);
      case 129:
      return Color.FromArgb(38, 76, 66);
      case 130:
      return Color.FromArgb(0, 255, 255);
      case 131:
      return Color.FromArgb(127, 255, 255);
      case 132:
      return Color.FromArgb(0, 204, 204);
      case 133:
      return Color.FromArgb(102, 204, 204);
      case 134:
      return Color.FromArgb(0, 153, 153);
      case 135:
      return Color.FromArgb(76, 153, 153);
      case 136:
      return Color.FromArgb(0, 127, 127);
      case 137:
      return Color.FromArgb(63, 127, 127);
      case 138:
      return Color.FromArgb(0, 76, 76);
      case 139:
      return Color.FromArgb(38, 76, 76);
      case 140:
      return Color.FromArgb(0, 191, 255);
      case 141:
      return Color.FromArgb(127, 223, 255);
      case 142:
      return Color.FromArgb(0, 153, 204);
      case 143:
      return Color.FromArgb(102, 178, 204);
      case 144:
      return Color.FromArgb(0, 114, 153);
      case 145:
      return Color.FromArgb(76, 133, 153);
      case 146:
      return Color.FromArgb(0, 95, 127);
      case 147:
      return Color.FromArgb(63, 111, 127);
      case 148:
      return Color.FromArgb(0, 57, 76);
      case 149:
      return Color.FromArgb(38, 66, 76);
      case 150:
      return Color.FromArgb(0, 127, 255);
      case 151:
      return Color.FromArgb(127, 191, 255);
      case 152:
      return Color.FromArgb(0, 102, 204);
      case 153:
      return Color.FromArgb(102, 153, 204);
      case 154:
      return Color.FromArgb(0, 76, 153);
      case 155:
      return Color.FromArgb(76, 114, 153);
      case 156:
      return Color.FromArgb(0, 63, 127);
      case 157:
      return Color.FromArgb(63, 95, 127);
      case 158:
      return Color.FromArgb(0, 38, 76);
      case 159:
      return Color.FromArgb(38, 57, 76);
      case 160:
      return Color.FromArgb(0, 63, 255);
      case 161:
      return Color.FromArgb(127, 159, 255);
      case 162:
      return Color.FromArgb(0, 51, 204);
      case 163:
      return Color.FromArgb(102, 127, 204);
      case 164:
      return Color.FromArgb(0, 38, 153);
      case 165:
      return Color.FromArgb(76, 95, 153);
      case 166:
      return Color.FromArgb(0, 31, 127);
      case 167:
      return Color.FromArgb(63, 79, 127);
      case 168:
      return Color.FromArgb(0, 19, 76);
      case 169:
      return Color.FromArgb(38, 47, 76);
      case 170:
      return Color.FromArgb(0, 0, 255);
      case 171:
      return Color.FromArgb(127, 127, 255);
      case 172:
      return Color.FromArgb(0, 0, 204);
      case 173:
      return Color.FromArgb(102, 102, 204);
      case 174:
      return Color.FromArgb(0, 0, 153);
      case 175:
      return Color.FromArgb(76, 76, 153);
      case 176:
      return Color.FromArgb(0, 0, 127);
      case 177:
      return Color.FromArgb(63, 63, 127);
      case 178:
      return Color.FromArgb(0, 0, 76);
      case 179:
      return Color.FromArgb(38, 38, 76);
      case 180:
      return Color.FromArgb(63, 0, 255);
      case 181:
      return Color.FromArgb(159, 127, 255);
      case 182:
      return Color.FromArgb(51, 0, 204);
      case 183:
      return Color.FromArgb(127, 102, 204);
      case 184:
      return Color.FromArgb(38, 0, 153);
      case 185:
      return Color.FromArgb(95, 76, 153);
      case 186:
      return Color.FromArgb(31, 0, 127);
      case 187:
      return Color.FromArgb(79, 63, 127);
      case 188:
      return Color.FromArgb(19, 0, 76);
      case 189:
      return Color.FromArgb(47, 38, 76);
      case 190:
      return Color.FromArgb(127, 0, 255);
      case 191:
      return Color.FromArgb(191, 127, 255);
      case 192:
      return Color.FromArgb(102, 0, 204);
      case 193:
      return Color.FromArgb(153, 102, 204);
      case 194:
      return Color.FromArgb(76, 0, 153);
      case 195:
      return Color.FromArgb(114, 76, 153);
      case 196:
      return Color.FromArgb(63, 0, 127);
      case 197:
      return Color.FromArgb(95, 63, 127);
      case 198:
      return Color.FromArgb(38, 0, 76);
      case 199:
      return Color.FromArgb(57, 38, 76);
      case 200:
      return Color.FromArgb(191, 0, 255);
      case 201:
      return Color.FromArgb(223, 127, 255);
      case 202:
      return Color.FromArgb(153, 0, 204);
      case 203:
      return Color.FromArgb(178, 102, 204);
      case 204:
      return Color.FromArgb(114, 0, 153);
      case 205:
      return Color.FromArgb(133, 76, 153);
      case 206:
      return Color.FromArgb(95, 0, 127);
      case 207:
      return Color.FromArgb(111, 63, 127);
      case 208:
      return Color.FromArgb(57, 0, 76);
      case 209:
      return Color.FromArgb(66, 38, 76);
      case 210:
      return Color.FromArgb(255, 0, 255);
      case 211:
      return Color.FromArgb(255, 127, 255);
      case 212:
      return Color.FromArgb(204, 0, 204);
      case 213:
      return Color.FromArgb(204, 102, 204);
      case 214:
      return Color.FromArgb(153, 0, 153);
      case 215:
      return Color.FromArgb(153, 76, 153);
      case 216:
      return Color.FromArgb(127, 0, 127);
      case 217:
      return Color.FromArgb(127, 63, 127);
      case 218:
      return Color.FromArgb(76, 0, 76);
      case 219:
      return Color.FromArgb(76, 38, 76);
      case 220:
      return Color.FromArgb(255, 0, 191);
      case 221:
      return Color.FromArgb(255, 127, 223);
      case 222:
      return Color.FromArgb(204, 0, 153);
      case 223:
      return Color.FromArgb(204, 102, 178);
      case 224:
      return Color.FromArgb(153, 0, 114);
      case 225:
      return Color.FromArgb(153, 76, 133);
      case 226:
      return Color.FromArgb(127, 0, 95);
      case 227:
      return Color.FromArgb(127, 63, 111);
      case 228:
      return Color.FromArgb(76, 0, 57);
      case 229:
      return Color.FromArgb(76, 38, 66);
      case 230:
      return Color.FromArgb(255, 0, 127);
      case 231:
      return Color.FromArgb(255, 127, 191);
      case 232:
      return Color.FromArgb(204, 0, 102);
      case 233:
      return Color.FromArgb(204, 102, 153);
      case 234:
      return Color.FromArgb(153, 0, 76);
      case 235:
      return Color.FromArgb(153, 76, 114);
      case 236:
      return Color.FromArgb(127, 0, 63);
      case 237:
      return Color.FromArgb(127, 63, 95);
      case 238:
      return Color.FromArgb(76, 0, 38);
      case 239:
      return Color.FromArgb(76, 38, 57);
      case 240:
      return Color.FromArgb(255, 0, 63);
      case 241:
      return Color.FromArgb(255, 127, 159);
      case 242:
      return Color.FromArgb(204, 0, 51);
      case 243:
      return Color.FromArgb(204, 102, 127);
      case 244:
      return Color.FromArgb(153, 0, 38);
      case 245:
      return Color.FromArgb(153, 76, 95);
      case 246:
      return Color.FromArgb(127, 0, 31);
      case 247:
      return Color.FromArgb(127, 63, 79);
      case 248:
      return Color.FromArgb(76, 0, 19);
      case 249:
      return Color.FromArgb(76, 38, 47);
      case 250:
      return Color.FromArgb(51, 51, 51);
      case 251:
      return Color.FromArgb(91, 91, 91);
      case 252:
      return Color.FromArgb(132, 132, 132);
      case 253:
      return Color.FromArgb(173, 173, 173);
      case 254:
      return Color.FromArgb(214, 214, 214);
      case 255:
      return Color.FromArgb(255, 255, 255);
      default:
      throw new ArgumentOutOfRangeException();
    }
}
}Thanks again, Scott. I'll be back with a post of my own after the long Easter weekend here in Switzerland.
页: [1] 2
查看完整版本: Kean专题(15)—User_Interface