Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I am working in ArcGIS 10.0 (ArcMap) and Python 2.6.5 and in the Data View. I have an IGroupElement3 to which I add a TextElement and up to several RectangleElements. I want then to retrieve the envelope of the GroupElement, recenter that envelope, and set the envelope as the new geometry of the GroupElement. The intent is to reposition (translate) the GroupElement. Here is a snippet:

pGrpElem = CType(pGroupElementFull, esriCarto.IElement)
pEnv = pGrpElem.Geometry.Envelope
pEnv.CenterAt(pCtrPoint)
pGrpElem.Geometry = pEnv

When the code runs, I get an error on the CenterAt method, saying I am performing an operation on an empty geometry. I checked, and indeed the pEnv is empty. So I have a few questions:

(1) Is this a valid method for moving a GroupElement?

(2) If not, how should I be doing it?

(3) If so, then I have a problem elsewhere. Do I have to add the component elements - and the GroupElement for that matter - to the display's GraphicsContainer to get them to "gel" and have valid envelopes? I was trying to avoid the GraphicsContainer step, because I really don't want the graphics to draw to the screen. The GroupElement is really for loading into an annotation feature. When I use the GraphicsContainer the screen drawing can get messed up unnecessarily. The graphics draw anyway when they are added to annotation, so I don't need two copies onscreen.

(4) If, as described above, I need to do something in addition to simply adding elements to the GroupElement to make their geometries visible to the GroupElement, how might I do that and avoid drawing the graphics to the screen at the same time?

Thanks for the help, all.

share|improve this question

2 Answers 2

up vote 2 down vote accepted

This is a common gotcha when working with GroupElements. The best way to change position, size etc. of group elements is to use the ITransform2D interface which the GroupElement class implements.

So, to recenter a group element to another location, first retrieve its current envelope through IElement.QueryBounds, for example. This will allow you to determine the offset to move the element to the desired location, which you will then use when calling ITransform2D.Move.

This Python function using comtypes centers an element (of just about any type, including a group element) to the [x,y] location. display is an IDisplay reference, this will usually be IActiveView.ScreenDisplay on the map. objectFactory is IObjectFactory used to create out-of-process COM objects.

def centerElementAt(element, display, x, y, objectFactory):
    boundsEnvelope = CType(objectFactory.Create("esriGeometry.Envelope"), esriGeometry.IEnvelope)
    (CType(element, esriCarto.IElement)).QueryBounds(CType(display, esriDisplay.IDisplay), boundsEnvelope)
    currentCenterPoint = CType((CType(boundsEnvelope, esriGeometry.IArea)).Centroid, esriGeometry.IPoint)
    transform2D = CType(element, esriGeometry.ITransform2D)
    transform2D.Move(x - currentCenterPoint.X, y - currentCenterPoint.Y)
share|improve this answer
    
Thank you, Petr. I shall try that. I am already using ITransform2D to rotate the GroupElement at some point, so I have a reference already. About the QueryBounds method: I have had trouble getting it to work. Can I create a new blank envelope and pass that in to get populated by QueryBounds? –  celticflute Feb 1 '11 at 21:08
    
See the code sample. Yes, the envelope you pass to QueryBounds needs to be an existing IEnvelope instance. –  Petr Krebs Feb 1 '11 at 21:32
1  
Also as a side note, remembering our previous discussion on in-process vs. inter-process COM calls, this is one of the cases when it's perfectly safe to use NewObj to create the Envelope instead of IObjectFactory. I still recommend using the object factory just like in the sample for performance reasons, but since ArcMap does not hold onto the envelope reference, you can try for yourself that it actually does NOT need to be instantiated inside the ArcMap process. –  Petr Krebs Feb 1 '11 at 22:09

I've also noticed when building a groupelement programatically it is (at least sometimes) necessary to call IElement.Activate in order to get a non-empty geometry.

share|improve this answer
1  
Interesting, looks like a nice alternative to retrieving the current envelope using QueryBounds. The docs say that this method "prepares the screen display for output and orients the scale of the element to the specified display". I'm only curious what the display preparation means and whether it has any (possibly unwanted) side effects –  Petr Krebs Feb 1 '11 at 21:59
    
I should have mentioned that the elements I was adding to the group element were those returned from IGraphicsComposite.get_Graphics, on a legend, so this behavior might be specific to this context. –  Kirk Kuykendall Feb 1 '11 at 22:21
    
Kirk, I did at least try the Activate method in the context I described above, but it did not "gel" the envelope. Using QueryBounds as petr k suggests below did the trick. –  celticflute Feb 3 '11 at 14:43

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.