明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 840|回复: 0

Managing drag & drop from a palette into AutoCAD using .NET

[复制链接]
发表于 2011-2-24 11:22:44 | 显示全部楼层 |阅读模式
I’m up early (after sleeping late) with jetlag, so I thought I may as well put together this post. My brain isn’t fully functional, I suspect, so forgive any errors (but please let me know about them, so I can fix them :-).
I was inspired to implement the code in this post by an internal email thread, wherein Albert Szilvasy recommended implementing a comparable technique to a colleague. Please don’t blame Albert for the implementation details, though, they are all mine.
The idea is simple: you have some kind of modeless PaletteSet, and you want to initiate and manage a drag & drop of some kind of custom content from the palette into AutoCAD. In this case – to get started quickly – I took the code from this previous post, which displayed a palette previewing the contents of the Windows clipboard for eventual inclusion in the Clipboard Manager Plugin of the Month.
In this example we have a bitmap hosted in a palette: when someone clicks on the image, we’ll start our drag operation, and should the drag leave the palette and enter AutoCAD’s drawing window, we’ll respond to the eventual drop by saving the image in the palette as a bitmap to file and firing a command inside AutoCAD with the location of the bitmap. Once again there’s our important
rule of thumb when it comes to implementing a modeless UI: rather than manually locking the current document, it’s safer to define a command – which will implicitly lock the current document – and call that from the UI via SendStringToExecute().
The custom command we call – named RINS – will simply add a raster image to the AutoCAD drawing in the current space.
Here’s the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using System;

namespace DragAndDrop
{

public
enum
Msgs
  {
    WM_DRAWCLIPBOARD = 0x0308,
    WM_CHANGECBCHAIN = 0x030D
  }


public
class
ClipboardView : UserControl
  {
    [DllImport("user32.dll")]

public
static
extern
IntPtr SetClipboardViewer(

IntPtr hWndNewViewer
    );

    [DllImport("user32.dll", CharSet = CharSet.Auto)]

public
static
extern
IntPtr SendMessage(

IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam
    );


private
IntPtr _nxtVwr;

private
PictureBox _img;

private
PaletteSet _ps;


public System.Drawing.Image Contents
    {

get { return _img.Image; }
    }


public ClipboardView(PaletteSet ps)
    {
      _img = new
PictureBox();
      _img.Anchor =
        (AnchorStyles)(AnchorStyles.Top |

AnchorStyles.Bottom |

AnchorStyles.Left |

AnchorStyles.Right);
      _img.Location = new
Point(0, 0);
      _img.Size = this.Size;
      _img.SizeMode = PictureBoxSizeMode.StretchImage;
      Controls.Add(_img);


// Add our event handler to launch a new drag event

// when someone clicks on the control

      _img.MouseDown +=

delegate(object sender, MouseEventArgs e)
        {

// Simply initiate the drag & drop in AutoCAD,

// specifying an instance of our custom "drop

// target" class

          Autodesk.AutoCAD.ApplicationServices.

Application.DoDragDrop(
            _img, this.Contents, DragDropEffects.Copy,

new
MyDropTarget()
          );
        };

      _nxtVwr = SetClipboardViewer(this.Handle);
      _ps = ps;
    }


private
void ExtractImage()
    {

IDataObject iData;

try
      {
        iData = Clipboard.GetDataObject();
      }

catch (System.Exception ex)
      {

MessageBox.Show(ex.ToString());

return;
      }


if (iData.GetDataPresent("Bitmap"))
      {

object o = iData.GetData("Bitmap");

Bitmap b = o as
Bitmap;

if (b != null)
        {
          _img.Image = b;

if (_ps != null)
          {
            _ps.Size =

new
Size(b.Size.Width / 3, b.Size.Height / 3);
          }
        }
      }
    }


protected
override
void WndProc(ref
Message m)
    {

switch ((Msgs)m.Msg)
      {

case
Msgs.WM_DRAWCLIPBOARD:
          ExtractImage();
          SendMessage(_nxtVwr, m.Msg, m.WParam, m.LParam);

break;

case
Msgs.WM_CHANGECBCHAIN:

if (m.WParam == _nxtVwr)
            _nxtVwr = m.LParam;

else
            SendMessage(_nxtVwr, m.Msg, m.WParam, m.LParam);

break;

default:

base.WndProc(ref m);

break;
      }
    }
  }


// Our custom drop target class


public
class
MyDropTarget : Autodesk.AutoCAD.Windows.DropTarget
  {

public
override
void OnDrop(DragEventArgs e)
    {

Document doc =
        Autodesk.AutoCAD.ApplicationServices.Application.
        DocumentManager.MdiActiveDocument;


// If we have a valid bitmap, save it and send

// our custom command (RINS)


if (e.Data.GetDataPresent("Bitmap"))
      {

object o = e.Data.GetData("Bitmap");

Bitmap b = o as
Bitmap;

if (b != null)
        {

// We'll save the bitmap as a "temp" file

// (as its unique - a better approach

// would probably to create a unique file

// in the same folder as the drawing, but

// that's left to the reader)


string path = Path.GetTempFileName();
          b.Save(path);


// Call our command


string cmd = "_RINS " + path + "\n";
          doc.SendStringToExecute(
            cmd, false, false, false
          );
        }
      }
    }
  }


public
class
Commands
  {

private
PaletteSet _ps = null;

private
ClipboardView _cv = null;

static
private
Point3d _pt = Point3d.Origin;

    [CommandMethod("DRAGDROP")]

public
void DragAndDropClipboardRaster()
    {

if (_ps == null)
      {
        _ps = new
PaletteSet(

"DRAGDROP",

new
Guid("5C8FC28C-45ED-4796-BD40-28D235B6D7DA")
        );


if (_cv == null)
        {
          _cv = new
ClipboardView(_ps);
        }

        _ps.Text = "Clipboard";
        _ps.DockEnabled =

DockSides.Left | DockSides.Right | DockSides.None;
        _ps.Size = new System.Drawing.Size(300, 500);
        _ps.Add("ClipboardView", _cv);
      }
      _ps.Visible = true;
    }



// Our custom command to insert a raster image

    [CommandMethod("RINS")]

public
void RasterInsert()
    {

Document doc =
      Autodesk.AutoCAD.ApplicationServices.Application.
      DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;


// Pick up the location of the bitmap image


PromptStringOptions pso =

new
PromptStringOptions(

"\nPath of raster image: "
        );
      pso.AllowSpaces = true;

PromptResult pr = ed.GetString(pso);

if (pr.Status != PromptStatus.OK)

return;


if (!File.Exists(pr.StringResult))
      {
        ed.WriteMessage(

"\nFile does not exist."
        );

return;
      }


string path = pr.StringResult;


Transaction tr =
        db.TransactionManager.StartTransaction();

using (tr)
      {

// Get or create our raster image dictionary


ObjectId dictId =

RasterImageDef.GetImageDictionary(db);

if (dictId == ObjectId.Null)
          dictId = RasterImageDef.CreateImageDictionary(db);


// And open it for write


DBDictionary dict =
          (DBDictionary)tr.GetObject(
            dictId, OpenMode.ForWrite
          );


// Get a unique name for our definition object


string name = RasterImageDef.SuggestName(dict, path);


// Create the definition and add it to the dictionary


RasterImageDef rid = new
RasterImageDef();
        rid.SourceFileName = path;
        rid.Load();

ObjectId ridId = dict.SetAt(name, rid);
        tr.AddNewlyCreatedDBObject(rid, true);


// Now we'll add our raster image reference

// to the current space


BlockTableRecord btr =
          (BlockTableRecord)tr.GetObject(
            db.CurrentSpaceId,

OpenMode.ForWrite
          );


// Create and add the image reference


RasterImage ri = new
RasterImage();
        ri.ImageDefId = ridId;
        ri.SetClipBoundaryToWholeImage();
        btr.AppendEntity(ri);
        tr.AddNewlyCreatedDBObject(ri, true);


// Of course we commit

        tr.Commit();
      }
    }
  }
}

Here’s what happens when we run the DRAGDROP command and copy a block to the clipboard:

As we click on the image to start the drag, we see the “not allowed” cursor:

As we drag onto the drawing canvas, we see the “drag a copy” cursor:

And as we drop we see the RINS command execute and our raster image get inserted at the origin of the drawing with the default size:

Where in this post we’re just passing the location (on disk) of the newly-saved image to the RINS command, in the next post I intend to extend the command to take the location of the drop as being the insertion point of the image and then prompt the user for the second corner. We’ll probably use the raster image jig from this previous post to help with that.
One problem I’m currently having (hopefully due to jetlag-related fogginess) is with translating the screen coordinates provided to the the drop target into a position inside AutoCAD (UCS or WCS, I don’t much care) at which we can create the raster image reference. If anyone knows a simple way to get from screen coordinates to some kind of drawing coordinates, please let me know. I’ve tried a point monitor, but that unfortunately only gets the cursor’s position in the drawing prior to entering the palette, rather than at the drop location.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
"觉得好,就打赏"
还没有人打赏,支持一下

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-12-24 07:35 , Processed in 0.194093 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表