| Richie's profileThe Sandpit - "We hack s...BlogLists | Help |
|
August 31 ArcGIS Diagrammer - Managing MetadataArcGIS Diagrammer has the capability to view and edit metadata. When exporting geodatabase schema to an XML workspace document using ArcCatalog, ensure that you have the Export Metadata option checked. This option is enabled by default. To view metadata for a geodatabase object in ArcGIS Diagrammer, simply right click and select View Metadata as shown below. Please note that not all geodatabase objects support metadata, for example, domains and subtypes do not have metadata. After clicking View Metadata, a new tab is added to ArcGIS Diagrammer. By default the raw metadata XML is displayed. In the Properties Window, you can select one of the ArcGIS Desktop metadata stylesheets as shown below. These stylesheets translate raw metadata XML into readable HTML. This is what the Parcels feature class metadata looks like with the ISO metadata stylesheet. To edit metadata of a geodatabase object select the object in the diagram and click the ellipse button next to the Metadata property in the Properties Window.
The ellipse button will launch the ESRI ISO Metadata Wizard.
ArcGIS Diagrammer - Reverse Engineering a Geodatabase to a DiagramThis post will describe how to create a ready-to-print diagram of your geodatabase in four easy steps. This exercise will use ArcGIS Diagrammer (free) which is available from ArcScripts. Prerequisites for ArcGIS Diagrammer include ArcGIS Desktop 9.2 and Microsoft .NET Framework 2.0. Step 1: Export an existing geodatabase to an ESRI XML Workspace Document Right click on a personal geodatabase, file geodatabase or an SDE connection. Select Export > XML Workspace Document... Select Schema Only and enter an output file name. For example C:\Temp\Montgomery.xml. Click Next. Click Finish to start the export. Step 2: Load the XML Workspace Document into ArcGIS Diagrammer Start ArcGIS Diagrammer by clicking: Drag and drop the XML file created by ArcCatalog into the ArcGIS Diagrammer canvas. ArcGIS Diagrammer will render all the geodatabase objects and associations. You may want to change the diagram scale, for example, to change the zooming scale to 25% click View > Zoom > 25%.
Step 3: Arrange geodatabase objects All geodatabase objects can be re-arranged to suit your needs. Also, some objects like subtypes, domains and feature classes can be expanded to reveal additional details. Step 4: Print the Diagram Before printing or plotting the diagram you may want to specify a printer/plotter and paper size. Click File > Print Setup... In the Printer Setup dialog select a printer and paper size.
Finally, click File > Print to send the diagram for printing/plotting.
Introducing ArcGIS DiagrammerArcGIS Diagrammer is a productivity tool for GIS professionals to create, edit and analyze geodatabase schema. Schema is presented as an editable diagram in an environment familiar to users of Microsoft Visual Studio. Essentially ArcGIS Diagrammer is a visual editor for ESRI’s xml workspace document. These xml documents can be created by exporting the schema from an existing geodatabase to xml using ArcCatalog. ArcCatalog can also create geodatabase schema by importing an xml workspace document. Here is a brief video demonstration of ArcGIS Diagrammer:
August 06 How to create an attractive (and functional) toolbar for ArcGIS DesktopESRI's ArcGIS Desktop product includes the applications ArcCatalog, ArcMap, ArcScene and ArcGlobe. The user interfaces for all four applications can be heavily customized, for example, developers can deploy custom toolbars and buttons. Below is an example of a custom toolbar for ArcMap. The toolbar is developed as a series of COM classes (or .NET classes with interop). The classes must use interfaces defined in the ArcGIS Desktop SDK such as IToolbarDef, IMenuDef, ICommand and IToolControl. For more information on this or other interfaces please visit EDN.
With ArcGIS Desktop 9.2, development of toolbars was made much easier with the inclusion of base classes in the ArcGIS .NET SDK. However, the basic look and feel of the ArcGIS Desktop user interface has not changed since it was first released in 2000. In this article, I will describe how to implement a modern UI in an ArcGIS Desktop application using .NET 2.0. This is achieved by hosting a .NET 2.0 ToolStrip inside a traditional ESRI Toolbar. This is the result:
With minimal effort it is possible to create an attractive, functional and efficient toolbar. To summarize the benefits of a hosted ToolStrip:
But there is always a catch! :-) The only disadvantage that I have found is that toolbars cannot be resized at runtime. The code below will create the ArcMap toolbar shown above. To use the code, create a new C# Class Library in Microsoft Visual Studio 2005. In the project properties, tick Register for COM interop. Please note that the code and methodology used in this post is not endorsed or supported by ESRI. Use this code at your own risk. using System; using System.Collections.Generic; using System.Drawing; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; using Microsoft.Win32; using ESRI.ArcGIS.Framework; using ESRI.ArcGIS.SystemUI; namespace ESRI.ArcGIS.DeveloperSamples.ToolbarNet { // .NET UserControl that hosts a ToolStrip [ComVisible(false)] public class UserControlTest : UserControl{ private enum Action { None, Cut, Copy, Paste, Delete, Zoom25, Zoom50, Zoom100 } private IApplication m_application = null; public UserControlTest() { // Get .NET Bitmaps Assembly assembly = Assembly.GetAssembly(typeof(Form)); Bitmap bitmap1 = new Bitmap(assembly.GetManifestResourceStream("System.Windows.Forms.cut.bmp")); Bitmap bitmap2 = new Bitmap(assembly.GetManifestResourceStream("System.Windows.Forms.copy.bmp")); Bitmap bitmap3 = new Bitmap(assembly.GetManifestResourceStream("System.Windows.Forms.paste.bmp")); Bitmap bitmap4 = new Bitmap(assembly.GetManifestResourceStream("System.Windows.Forms.delete.bmp")); bitmap1.MakeTransparent(Color.Fuchsia); bitmap2.MakeTransparent(Color.Fuchsia); bitmap3.MakeTransparent(Color.Fuchsia); bitmap4.MakeTransparent(Color.Fuchsia); // Create Dropdown Button ToolStripDropDownButton toolStripDropDownButton = new ToolStripDropDownButton(); toolStripDropDownButton.Text = "Zoom"; toolStripDropDownButton.DropDownItems.Add(new ToolStripMenuItemAction("25%", Action.Zoom25)); toolStripDropDownButton.DropDownItems.Add(new ToolStripMenuItemAction("50%", Action.Zoom50)); toolStripDropDownButton.DropDownItems.Add(new ToolStripMenuItemAction("100%", Action.Zoom100)); toolStripDropDownButton.DropDownItemClicked += new ToolStripItemClickedEventHandler( this.ToolStrip_DropDownItemClicked); // Create Toolstrip ToolStrip toolstrip = new ToolStrip(); toolstrip.GripStyle = ToolStripGripStyle.Hidden; toolstrip.Items.Add(new ToolStripButtonAction(bitmap1, Action.Cut)); toolstrip.Items.Add(new ToolStripButtonAction(bitmap2, Action.Copy)); toolstrip.Items.Add(new ToolStripButtonAction(bitmap3, Action.Paste)); toolstrip.Items.Add(new ToolStripSeparator()); toolstrip.Items.Add(new ToolStripButtonAction(bitmap4, Action.Delete)); toolstrip.Items.Add(new ToolStripSeparator()); toolstrip.Items.Add(toolStripDropDownButton); toolstrip.Stretch = true; toolstrip.MouseEnter += new EventHandler(this.Toolstrip_MouseEnter); toolstrip.ItemClicked += new ToolStripItemClickedEventHandler(this.Toolstrip_ItemClicked); // Add Toolbar. Set Size. this.Controls.Add(toolstrip); this.Width = 160; } public IApplication Application { set { this.m_application = value; } } private void Toolstrip_MouseEnter(object sender, EventArgs e) { ToolStrip toolStrip = sender as ToolStrip; if (toolStrip == null) { return; } toolStrip.Focus(); } private void ToolStrip_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e) { ToolStripMenuItemAction toolStripMenuItemAction = e.ClickedItem as ToolStripMenuItemAction; if (toolStripMenuItemAction == null) { return; } this.ExecuteAction(toolStripMenuItemAction.Action); } private void Toolstrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e) { ToolStripButtonAction toolStripButtonAction = e.ClickedItem as ToolStripButtonAction; if (toolStripButtonAction == null) { return; } this.ExecuteAction(toolStripButtonAction.Action); } private void ExecuteAction(Action action) { switch (action) { case Action.Cut: case Action.Copy: case Action.Paste: case Action.Delete: case Action.Zoom25: case Action.Zoom50: case Action.Zoom100: MessageBox.Show(action.ToString()); break; default: break; } } // Subclassed ToolStripButton private class ToolStripButtonAction : ToolStripButton { private readonly Action m_action = Action.None; public ToolStripButtonAction(Image image, Action action) : base(image) { this.m_action = action; } public Action Action { get { return this.m_action; } } } private class ToolStripMenuItemAction : ToolStripMenuItem { private readonly Action m_action = Action.None; public ToolStripMenuItemAction(string text, Action action) : base(text) { this.m_action = action; } public Action Action { get { return this.m_action; } } } } // The ESRI ArcMap Command that hosts the User Control [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [Guid(ApplicationGuid.GUID_COMMAND_TEST)] public sealed class CommandHost : EsriCommandControlMx { public CommandHost() : base() { this.m_control = new UserControlTest(); } public override void OnCreate(object hook) { base.OnCreate(hook); if (hook != null) { ((UserControlTest)this.m_control).Application = (IApplication)hook; } } } // The ESRI ArcMap Toolbar [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] [Guid(ApplicationGuid.GUID_TOOLBAR_TEST)] public sealed class ToolbarTest : EsriToolbarMx { public ToolbarTest() : base() { this.m_caption = "Test"; this.m_commands.Add(new EsriToolbarCommand(new Guid(ApplicationGuid.GUID_COMMAND_TEST), false)); } } // The Abstract ESRI ArcMap Toolbar [ComVisible(false)] public abstract class EsriToolbarMx : EsriToolbar { private const string IMPLEMENT_CATEGORIES = "\\Implemented Categories\\"; [ComVisible(false)] [ComRegisterFunction()] private static void RegisterFunction(string regKey) { Registry.ClassesRoot.CreateSubKey(regKey.Substring(18) + IMPLEMENT_CATEGORIES + EsriRegistry.COMPONENT_MX_TOOLBAR); } [ComVisible(false)] [ComUnregisterFunction()] private static void UnregisterFunction(string regKey) { Registry.ClassesRoot.DeleteSubKey(regKey.Substring(18) + IMPLEMENT_CATEGORIES + EsriRegistry.COMPONENT_MX_TOOLBAR); } } // Abstract ESRI Toolbar [ComVisible(false)] public abstract class EsriToolbar : IToolBarDef { private const string SUFFIX = "_TOOLBAR"; protected List<EsriToolbarCommand> m_commands = new List<EsriToolbarCommand>(); protected string m_caption = null; public void GetItemInfo(int pos, IItemDef itemDef) { itemDef.ID = this.m_commands[pos].Guid.ToString("B"); itemDef.Group = this.m_commands[pos].Group; } public string Caption { get { return this.m_caption; } } public string Name { get { return this.m_caption.ToUpper().Replace(" ", "") + SUFFIX; } } public int ItemCount { get { return this.m_commands.Count; } } } // Abstract ESRI Toolbar Item [ComVisible(false)] public class EsriToolbarCommand { private readonly Guid m_guid = Guid.Empty; private readonly bool m_group = false; public EsriToolbarCommand(Guid guid, bool group) { this.m_guid = guid; this.m_group = group; } public Guid Guid { get { return this.m_guid; } } public bool Group { get { return this.m_group; } } } // Abstract ESRI ArcMap Command Tool Control [ComVisible(false)] public abstract class EsriCommandControlMx : EsriCommandControl { private const string IMPLEMENT_CATEGORIES = "\\Implemented Categories\\"; [ComVisible(false)] [ComRegisterFunction()] private static void RegisterFunction(string regKey) { Registry.ClassesRoot.CreateSubKey(regKey.Substring(18) + IMPLEMENT_CATEGORIES + EsriRegistry.COMPONENT_MX_COMMAND); } [ComVisible(false)] [ComUnregisterFunction()] private static void UnregisterFunction(string regKey) { Registry.ClassesRoot.DeleteSubKey(regKey.Substring(18) + IMPLEMENT_CATEGORIES + EsriRegistry.COMPONENT_MX_COMMAND); } } // Abstract ESRI Command Tool Control [ComVisible(false)] public abstract class EsriCommandControl : EsriCommand, IToolControl { protected ICompletionNotify m_completionNotify = null; protected UserControl m_control = null; public virtual bool OnDrop(esriCmdBarType barType) { return true; } public virtual void OnFocus(ICompletionNotify complete) { this.m_completionNotify = complete; // Can add UI update here } public int hWnd { get { return this.m_control.Handle.ToInt32(); } } } // Abstract ESRI Command [ComVisible(false)] public abstract class EsriCommand : ICommand { protected string m_category = null; protected string m_message = null; protected string m_caption = null; protected string m_tooltip = null; protected IApplication m_application = null; protected Bitmap m_bitmap = null; private IntPtr m_hBitmap = IntPtr.Zero; [DllImport("gdi32.dll")] protected static extern bool DeleteObject([In] IntPtr hObject); protected EsriCommand() { } ~EsriCommand() { if (this.m_hBitmap != IntPtr.Zero) { DeleteObject(this.m_hBitmap); } this.m_bitmap = null; this.m_application = null; } public virtual void OnClick() { } public string Message { get { return this.m_message; } } public int Bitmap { get { if (this.m_hBitmap == IntPtr.Zero) { if (this.m_bitmap != null) { this.m_hBitmap = this.m_bitmap.GetHbitmap(); } } return this.m_hBitmap.ToInt32(); } } public virtual void OnCreate(object hook) { if (hook != null) { this.m_application = (IApplication)hook; } } public string Caption { get { return this.m_caption; } } public string Tooltip { get { return this.m_tooltip; } } public int HelpContextID { get { return 0; } } public string Name { get { return this.m_category.Replace(" ", "") + "_" + this.m_caption.Replace(" ", ""); } } public virtual bool Checked { get { return false; } } public virtual bool Enabled { get { return true; } } public string HelpFile { get { return null; } } public string Category { get { return this.m_category; } } } // List of ESRI Guids [ComVisible(false)] public static class EsriRegistry { public const string COMPONENT_MX_COMMAND = "{B56A7C42-83D4-11D2-A2E9-080009B6F22B}"; public const string COMPONENT_MX_TOOLBAR = "{B56A7C4A-83D4-11D2-A2E9-080009B6F22B}"; } // List of hardcoded application guids [ComVisible(false)] public static class ApplicationGuid { public const string GUID_COMMAND_TEST = "D4E1C9EB-F2E4-4BD1-AF13-3868E555D322"; public const string GUID_TOOLBAR_TEST = "2B8966B6-C623-4F83-A376-53042F667B13"; } } August 02 Accessing ESRI Style Files using ADO.NETESRI's products ArcGIS Engine, ArcGIS Desktop and ArcGIS Server use style files to store and manage collections of symbols. A symbol is a graphic used to represent a geographic feature or class of features. Styles contains named and categorized symbols for various geographic entities like points, lines and polygons. ArcGIS Engine and ArcGIS Desktop style files are Microsoft Access databases with a style file extension. ArcGIS Server style files use a proprietary file type and have a serverstyle file extension. Developers can only use the ArcObjects API to access this file. ArcGIS Engine developers can use the SymbologyControl to browse symbols contained in a server style. Whereas ArcGIS Desktop developers can re-use the desktop dialogs like the StyleManagerDialog, SymbolEditor and the SymbolPickerDialog. In this post I will present a sample that demonstrates how to access ESRI style files using ADO.NET. The sample will also show how to convert an ESRI symbol into a .NET bitmap. This sample may be useful to developers that want to: Please note that the code and methodology used in this post is not endorsed or supported by ESRI. Use this code at your own risk. This sample was developed in C# using Microsoft Visual Studio 2005. The windows application consists of four controls and one component, these are:
When the form loads: The application, when loaded, looks like this.
If you run this application in debug mode, Microsoft Visual Studio 2005 may throw a PInvokeStackImbalance exception. This can be overcome by running the application normally from the executable or by disabling this exception. This and other debug exceptions can be ignored using the Exception window (Debug > Exceptions...). To load the point, line and polygon symbols from the style to the ListView click GO!
Here is the source code for the sample: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.OleDb; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Runtime.InteropServices; using stdole; using ESRI.ArcGIS.Display; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.Framework; namespace BrowseEsriSymbols { public partial class Form1 : Form { private const string GDB_TABLE_MARKER = "MARKER SYMBOLS"; private const string GDB_TABLE_LINE = "LINE SYMBOLS"; private const string GDB_TABLE_AREA = "FILL SYMBOLS"; private const string JET_SCHEMA_TABLE = "TABLE_NAME"; private const string JET_SCHEMA_COLUMN = "COLUMN_NAME"; private const string FIELD_ID = "ID"; private const string FIELD_CATEGORY = "CATEGORY"; private const string FIELD_NAME = "NAME"; public Form1() { // Initialize Components InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // Set Button Name from Resource this.textBox1.Text = "C:\\Program Files\\ArcGIS\\Styles\\Conservation.style"; this.listView1.SmallImageList = this.imageList1; this.listView1.View = View.Details; this.listView1.Columns.Add("Table"); this.listView1.Columns.Add("Id"); this.listView1.Columns.Add("Category"); this.listView1.Columns.Add("Name"); } private void button1_Click(object sender, EventArgs e) { // Get Drawing Context Graphics graphics = this.CreateGraphics(); // Display Hourglass Cursor this.Cursor = Cursors.WaitCursor; // Remove all rows (if any) this.listView1.Items.Clear(); // Stop ListView Redraws this.listView1.BeginUpdate(); // Connect to Style (using ADO.NET) string connection = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=" + this.textBox1.Text + ";"; OleDbConnection oleConnection = new OleDbConnection(connection); oleConnection.Open(); // Style Hardcode Table Names and Fields string[] tables = new string[] { GDB_TABLE_MARKER, GDB_TABLE_LINE, GDB_TABLE_AREA }; // Loop For Each Symbol Table in Style foreach (string table in tables) { // Construct SQL statement string query = "SELECT * FROM [" + table + "] "; // Connect to the Access File and create reader OleDbCommand command = new OleDbCommand(query, oleConnection); OleDbDataReader dataReader = command.ExecuteReader(); if (!dataReader.HasRows) { continue; } // Find column indexes int indexId = dataReader.GetOrdinal(FIELD_ID); int indexCategory = dataReader.GetOrdinal(FIELD_CATEGORY); int indexName = dataReader.GetOrdinal(FIELD_NAME); // Read each row in table while (dataReader.Read()) { // Get row values int id = dataReader.GetInt32(indexId); string category = dataReader.GetString(indexCategory); string name = dataReader.GetString(indexName); // Get ESRI Symbol ISymbol symbol = WindowsAPI.GetSymbol(this.textBox1.Text, table, id); // Convert ESRI Symbol to Bitmap Bitmap bitmap = WindowsAPI.SymbolToBitmap( symbol, new Size(16, 16), graphics, ColorTranslator.ToWin32(this.listView1.BackColor)); // Add Image to the listview's image list int index = this.listView1.SmallImageList.Images.Add(bitmap, Color.Transparent); // Add ListViewItem to ListView string[] cells = new string[] { table, id.ToString(), category, name }; ListViewItem item = new ListViewItem(cells); this.listView1.Items.Add(item); item.ImageIndex = index; } // Close Reader dataReader.Close(); } // Close Connection oleConnection.Close(); // Resume ListView Drawing this.listView1.EndUpdate(); // Display Default Cursor this.Cursor = Cursors.Default; } } public static class WindowsAPI { private const int COLORONCOLOR = 3; private const int HORZSIZE = 4; private const int VERTSIZE = 6; private const int HORZRES = 8; private const int VERTRES = 10; private const int ASPECTX = 40; private const int ASPECTY = 42; private const int LOGPIXELSX = 88; private const int LOGPIXELSY = 90; private enum PictureTypeConstants { picTypeNone = 0, picTypeBitmap = 1, picTypeMetafile = 2, picTypeIcon = 3, picTypeEMetafile = 4 } private struct PICTDESC { public int cbSizeOfStruct; public int picType; public IntPtr hPic; public IntPtr hpal; public int _pad; } private struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [DllImport("olepro32.dll", EntryPoint = "OleCreatePictureIndirect", PreserveSig = false)] private static extern int OleCreatePictureIndirect( ref PICTDESC pPictDesc, ref Guid riid, bool fOwn, out IPictureDisp ppvObj); [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC", ExactSpelling = true, SetLastError = true)] private static extern IntPtr CreateCompatibleDC(IntPtr hDC); [DllImport("gdi32.dll", EntryPoint = "DeleteDC", ExactSpelling = true, SetLastError = true)] private static extern bool DeleteDC(IntPtr hdc); [DllImport("gdi32.dll", EntryPoint = "SelectObject", ExactSpelling = true, SetLastError = true)] private static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); [DllImport("gdi32.dll", EntryPoint = "DeleteObject", ExactSpelling = true, SetLastError = true)] private static extern bool DeleteObject(IntPtr hObject); [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap", ExactSpelling = true, SetLastError = true)] private static extern IntPtr CreateCompatibleBitmap(IntPtr hObject, int width, int height); [DllImport("user32.dll", EntryPoint = "GetDC", ExactSpelling = true, SetLastError = true)] private static extern IntPtr GetDC(IntPtr ptr); [DllImport("user32.dll", EntryPoint = "ReleaseDC", ExactSpelling = true, SetLastError = true)] private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc); [DllImport("gdi32", EntryPoint = "CreateSolidBrush", ExactSpelling = true, SetLastError = true)] private static extern IntPtr CreateSolidBrush(int crColor); [DllImport("user32", EntryPoint = "FillRect", ExactSpelling = true, SetLastError = true)] private static extern int FillRect(IntPtr hdc, ref RECT lpRect, IntPtr hBrush); [DllImport("GDI32.dll", EntryPoint = "GetDeviceCaps", ExactSpelling = true, SetLastError = true)] private static extern int GetDeviceCaps(IntPtr hdc, int nIndex); [DllImport("user32", EntryPoint = "GetClientRect", ExactSpelling = true, SetLastError = true)] private static extern int GetClientRect(IntPtr hwnd, ref RECT lpRect); public static ISymbol GetSymbol(string style, string classname, int id) { ISymbol symbol = null; IStyleGallery styleGallery = new StyleGalleryClass(); IStyleGalleryStorage styleGalleryStorage = (IStyleGalleryStorage)styleGallery; styleGalleryStorage.TargetFile = style; IEnumStyleGalleryItem styleGalleryItems = styleGallery.get_Items(classname, style, ""); styleGalleryItems.Reset(); IStyleGalleryItem styleGalleryItem = styleGalleryItems.Next(); while (styleGalleryItem != null) { if (styleGalleryItem.ID == id) { symbol = (ISymbol)styleGalleryItem.Item; break; } styleGalleryItem = styleGalleryItems.Next(); } styleGalleryItem = null; styleGalleryStorage = null; styleGallery = null; return symbol; } private static IPictureDisp CreatePictureFromSymbol(IntPtr hDCOld, ref IntPtr hBmpNew, ISymbol pSymbol, Size size, int lGap, int backColor) { IntPtr hDCNew = IntPtr.Zero; IntPtr hBmpOld = IntPtr.Zero; try { hDCNew = CreateCompatibleDC(hDCOld); hBmpNew = CreateCompatibleBitmap(hDCOld, size.Width, size.Height); hBmpOld = SelectObject(hDCNew, hBmpNew); // Draw the symbol to the new device context. bool lResult = DrawToDC(hDCNew, size, pSymbol, lGap, backColor); hBmpNew = SelectObject(hDCNew, hBmpOld); DeleteDC(hDCNew); // Return the Bitmap as an OLE Picture. return CreatePictureFromBitmap(hBmpNew); } catch (Exception error) { if (pSymbol != null) { pSymbol.ResetDC(); if ((hBmpNew != IntPtr.Zero) && (hDCNew != IntPtr.Zero) && (hBmpOld != IntPtr.Zero)) { hBmpNew = SelectObject(hDCNew, hBmpOld); DeleteDC(hDCNew); } } throw error; } } private static IPictureDisp CreatePictureFromBitmap(IntPtr hBmpNew) { try { Guid iidIPicture = new Guid("7BF80980-BF32-101A-8BBB-00AA00300CAB"); PICTDESC picDesc = new PICTDESC(); picDesc.cbSizeOfStruct = Marshal.SizeOf(picDesc); picDesc.picType = (int)PictureTypeConstants.picTypeBitmap; picDesc.hPic = (IntPtr)hBmpNew; picDesc.hpal = IntPtr.Zero; // Create Picture object. IPictureDisp newPic; OleCreatePictureIndirect(ref picDesc, ref iidIPicture, true, out newPic); // Return the new Picture object. return newPic; } catch (Exception error) { throw error; } } private static bool DrawToWnd(IntPtr hWnd, ISymbol pSymbol, int lGap, int backColor) { IntPtr hDC = IntPtr.Zero; try { if (hWnd != IntPtr.Zero) { // Calculate size of window. RECT udtRect = new RECT(); int lResult = GetClientRect(hWnd, ref udtRect); if (lResult != 0) { int lWidth = (udtRect.Right - udtRect.Left); int lHeight = (udtRect.Bottom - udtRect.Top); hDC = GetDC(hWnd); // Must release the DC afterwards. if (hDC != IntPtr.Zero) { bool ok = DrawToDC(hDC, new Size(lWidth, lHeight), pSymbol, lGap, backColor); // Release cached DC obtained with GetDC. ReleaseDC(hWnd, hDC); return ok; } } } } catch { if (pSymbol != null) { // Try resetting DC, in case we have already called SetupDC for this symbol. pSymbol.ResetDC(); if ((hWnd != IntPtr.Zero) && (hDC != IntPtr.Zero)) { ReleaseDC(hWnd, hDC); // Try to release cached DC obtained with GetDC. } } return false; } return true; } private static bool DrawToDC(IntPtr hDC, Size size, ISymbol pSymbol, int lGap, int backColor) { try { if (hDC != IntPtr.Zero) { // First clear the existing device context. if (!Clear(hDC, backColor, 0, 0, size.Width, size.Height)) { throw new Exception("Could not clear the Device Context."); } // Create the Transformation and Geometry required by ISymbol::Draw. ITransformation pTransformation = CreateTransFromDC(hDC, size.Width, size.Height); IEnvelope pEnvelope = new EnvelopeClass(); pEnvelope.PutCoords(lGap, lGap, size.Width - lGap, size.Height - lGap); IGeometry pGeom = CreateSymShape(pSymbol, pEnvelope); // Perform the Draw operation. if ((pTransformation != null) && (pGeom != null)) { pSymbol.SetupDC(hDC.ToInt32(), pTransformation); pSymbol.Draw(pGeom); pSymbol.ResetDC(); } else { throw new Exception("Could not create required Transformation or Geometry."); } } } catch { if (pSymbol != null) { pSymbol.ResetDC(); } return false; } return true; } private static bool Clear(IntPtr hDC, int backgroundColor, int xmin, int ymin, int xmax, int ymax) { // This function fill the passed in device context with a solid brush, // based on the OLE color passed in. IntPtr hBrushBackground = IntPtr.Zero; int lResult; bool ok; try { RECT udtBounds; udtBounds.Left = xmin; udtBounds.Top = ymin; udtBounds.Right = xmax; udtBounds.Bottom = ymax; hBrushBackground = CreateSolidBrush(backgroundColor); if (hBrushBackground == IntPtr.Zero) { throw new Exception("Could not create GDI Brush."); } lResult = FillRect(hDC, ref udtBounds, hBrushBackground); if (hBrushBackground == IntPtr.Zero) { throw new Exception("Could not fill Device Context."); } ok = DeleteObject(hBrushBackground); if (hBrushBackground == IntPtr.Zero) { throw new Exception("Could not delete GDI Brush."); } } catch { if (hBrushBackground != IntPtr.Zero) { ok = DeleteObject(hBrushBackground); } return false; } return true; } private static ITransformation CreateTransFromDC(IntPtr hDC, int lWidth, int lHeight) { // Calculate the parameters for the new transformation, // based on the dimensions passed to this function. try { IEnvelope pBoundsEnvelope = new EnvelopeClass(); pBoundsEnvelope.PutCoords(0.0, 0.0, (double)lWidth, (double)lHeight); tagRECT deviceRect; deviceRect.left = 0; deviceRect.top = 0; deviceRect.right = lWidth; deviceRect.bottom = lHeight; int dpi = GetDeviceCaps(hDC, LOGPIXELSY); if (dpi == 0) { throw new Exception("Could not retrieve Resolution from device context."); } // Create a new display transformation and set its properties. IDisplayTransformation newTrans = new DisplayTransformationClass(); newTrans.VisibleBounds = pBoundsEnvelope; newTrans.Bounds = pBoundsEnvelope; newTrans.set_DeviceFrame(ref deviceRect); newTrans.Resolution = dpi; return newTrans; } catch { return null; } } private static IGeometry CreateSymShape(ISymbol pSymbol, IEnvelope pEnvelope) { // This function returns an appropriate Geometry type depending on the // Symbol type passed in. try { if (pSymbol is IMarkerSymbol) { // For a MarkerSymbol return a Point. IArea pArea = (IArea)pEnvelope; return pArea.Centroid; } else if ((pSymbol is ILineSymbol) || (pSymbol is ITextSymbol)) { // For a LineSymbol or TextSymbol return a Polyline. IPolyline pPolyline = new PolylineClass(); pPolyline.FromPoint = pEnvelope.LowerLeft; pPolyline.ToPoint = pEnvelope.UpperRight; return pPolyline; } else { // For any FillSymbol return an Envelope. return pEnvelope; } } catch { return null; } } public static Bitmap SymbolToBitmap(ISymbol userSymbol, Size size, Graphics gr, int backColor) { IntPtr graphicsHdc = gr.GetHdc(); IntPtr hBitmap = IntPtr.Zero; IPictureDisp newPic = CreatePictureFromSymbol( graphicsHdc, ref hBitmap, userSymbol, size, 1, backColor); Bitmap newBitmap = Bitmap.FromHbitmap(hBitmap); gr.ReleaseHdc(graphicsHdc); return newBitmap; } } } The ESRI Generic Get Position ToolESRI's ArcGIS Desktop product includes the applications ArcCatalog, ArcMap, ArcScene and ArcGlobe. The user interfaces of all four applications can be heavily customized by developers, for example, a developer can deploy custom toolbars and buttons. A button (or command in ESRI terminology) is a COM class that implements the ICommand interface. Some commands require geographic interaction, for example, clicking on a country in a world map. These commands must implement the ITool interface. Normally, developers create sets of commands that are specific to each project. In this article I will discuss an out-of-the-box command called Generic Get Point Tool that can be used for map/globe interaction. Using this command in future projects may reduce your development time. To demonstrate this command I have created an ArcGIS Engine-based windows application sample using Microsoft .Net Framework 2.0. The application consists of a map, an invisible toolbar and a button that will activate the Generic Get Point Tool. After the map is clicked, a message box will display the map coordinates of the clicked location and then deactivate the tool. The sample windows application (C#) was created using Microsoft Visual Studio 2005. It consists of a map control, toolbar control, license control and a button. The map control is assigned to the toolbar control's buddy property and the map control's is assigned a map document to load at runtime.
When the form loads, the Generic Get Point Tool is added to the toolbar and then by casting the command to the IToolPositionInitializer the form is assigned as the callback (because it supports IToolPositionCallback).
When the button is clicked the Generic Get Point Tool is located on the toolbar and then assigned as the current tool. This essentially activates the tool and deactivates the previously active tool (if any).
When the user clicks on the map display with the Generic Get Point Tool activated, the command will called the MouseClicked method on the IToolPositionCallback interface. In the sample, the form implements this interface and displays a message box displaying the map coordinates. Rather than leaving the tool active, setting IToolbarControl::CurrentTool (or IMapControl::CurrentTool) to null effectively deactivate the tool.
The sample code follows: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.SystemUI; using ESRI.ArcGIS.Geometry; namespace WindowsApplication1 { public partial class Form1 : Form, IToolPositionCallback{ public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // Hide ESRI Toolbar this.axToolbarControl1.Hide(); // Add Generic Get Point Tool UID uid = new UIDClass(); uid.Value = "{30DBCBEF-951E-4904-89DE-5A5F1AF571EE}"; IToolbarControl toolbarControl = (IToolbarControl)this.axToolbarControl1.Object; toolbarControl.AddItem(uid, -1, -1, false, -1, esriCommandStyles.esriCommandStyleIconOnly); // Find Generic Get Point Tool on Toolbar int index = toolbarControl.Find(uid); IToolbarItem toolbarItem = toolbarControl.GetItem(index); ICommand command = toolbarItem.Command; // Assign Callback to Generic Get Point Tool IToolPositionInitializer toolPositionInitializer = (IToolPositionInitializer)command; toolPositionInitializer.Initialize(this, -1); } private void Button_Click(object sender, EventArgs e) { if (sender == this.buttonGetPoint) { // Find Generic Get Point Tool UID uid = new UIDClass(); uid.Value = "{30DBCBEF-951E-4904-89DE-5A5F1AF571EE}"; IToolbarControl toolbarControl = (IToolbarControl)this.axToolbarControl1.Object; int index = toolbarControl.Find(uid); IToolbarItem toolbarItem = toolbarControl.GetItem(index); ICommand command = toolbarItem.Command; ITool tool = (ITool)command; // Set Generic Get Point Tool as the current tool toolbarControl.CurrentTool = tool; } } #region IToolPositionCallback Members public void Deactivated() { } public void MouseClicked(int lCookie, int button, int shift, int X, int Y, double mapX, double mapY, ISpatialReference pSpace) { // Display Message string message = string.Format( "Map location" + Environment.NewLine + "X: {0}" + Environment.NewLine + "Y: {1}", mapX.ToString(), mapY.ToString()); MessageBox.Show(message, "Test", MessageBoxButtons.OK, MessageBoxIcon.Information); // Deactivate Generic Get Point Tool IToolbarControl toolbarControl = (IToolbarControl)this.axToolbarControl1.Object; toolbarControl.CurrentTool = null; } #endregion } } |
|
|