ArcMap add-ins JOptionPane

1888
11
08-31-2011 10:01 AM
LeoDonahue
Occasional Contributor III
ArcMap 10.0 SP2
ArcObjects Java SDK SP2
Eclipse Helios 3.6.2
Java sdk 1.6.0_24

Following this example: http://help.arcgis.com/en/sdk/10.0/java_ao_adf/conceptualhelp/engine/0001/00010000041v000000.htm

I'm finding that using JOptionPane.showMessageDialog's do not always execute right away when you click a tool and sometimes the message dialog opens up behind ArcMap.  And don't click on anything else until you've dismissed the dialog or ArcMap hangs.

Anyone using Java add-ins?  If so, what are you using for notifying the client of certain actions?  JOptionPane messages?

import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.UnknownHostException;

import javax.swing.JOptionPane;

import com.esri.arcgis.addins.desktop.Tool;
import com.esri.arcgis.arcmapui.IMxDocument;
import com.esri.arcgis.carto.IActiveView;
import com.esri.arcgis.display.IDisplayTransformation;
import com.esri.arcgis.display.IScreenDisplay;
import com.esri.arcgis.framework.IApplication;
import com.esri.arcgis.geometry.IPoint;
import com.esri.arcgis.geometry.ISpatialReference;
import com.esri.arcgis.geometry.Point;
import com.esri.arcgis.geometry.SpatialReferenceEnvironment;
import com.esri.arcgis.interop.AutomationException;

public class HelloTool extends Tool {

    /**
     * Called when the tool is activated by clicking it.
     * 
     * @exception java.io.IOException if there are interop problems.
     * @exception com.esri.arcgis.interop.AutomationException if the component throws an ArcObjects exception.
     */
    @Override
    public void activate() throws IOException, AutomationException {
        // TODO Auto-generated method stub
        
    }
    @Override
    public void mousePressed(MouseEvent mouseEvent) {
        // TODO Auto-generated method stub
        super.mousePressed(mouseEvent);
        
        try {
            Point point1 = new Point();
            point1.putCoords((double)mouseEvent.getX(), (double)mouseEvent.getY());
            
            Point point2 = (Point) getMapCoordinatesFromScreenCoordinates(point1,av);
            String message2 = "x: " + point2.getX() + " y: " + point2.getY();
            
            Point point3 = (Point) getScreenCoordinatesFromMapCoorindates(point1,av);
            String message3 = "x: " + point3.getX() + " y: " + point3.getY();
            
            JOptionPane.showMessageDialog(null, message2, "Map Coordinates from Screen Coordinates", JOptionPane.INFORMATION_MESSAGE);
            JOptionPane.showMessageDialog(null, message3, "Screen Coordinates from Map Coordinates", JOptionPane.INFORMATION_MESSAGE);
            
            
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private IApplication app;
    private String appName;
    private IActiveView av;
    private int mapUnits = com.esri.arcgis.system.esriUnits.esriFeet;
    
    @Override
    public void init(IApplication app){
        //Stuff in here runs right away, even if the map document doesn't have the add-in loaded.
        this.app = app;
        try {
            IMxDocument mxDocument = (IMxDocument)app.getDocument();
            appName = app.getDocument().getTitle();
            av = mxDocument.getActiveView();
        } catch (AutomationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    public IPoint getMapCoordinatesFromScreenCoordinates(IPoint screenPoint, IActiveView activeView)throws Exception{

        if (screenPoint == null || screenPoint.isEmpty() || activeView == null)
            return null;

        int nad83HarnAZCentral = com.esri.arcgis.geometry.esriSRProjCSType.esriSRProjCS_NAD1983HARNSPCS_AZCentral;
        int mapUnits = com.esri.arcgis.system.esriUnits.esriFeet;
        SpatialReferenceEnvironment spatRef = new SpatialReferenceEnvironment();
        ISpatialReference nad83HarnAZC = spatRef.createProjectedCoordinateSystem(nad83HarnAZCentral);
        
        IScreenDisplay screenDisplay = activeView.getScreenDisplay();
        IDisplayTransformation displayTransformation = screenDisplay.getDisplayTransformation();
        displayTransformation.setSpatialReferenceByRef(nad83HarnAZC);
        displayTransformation.setUnits(mapUnits);

        return displayTransformation.toMapPoint((int)screenPoint.getX(), (int)
            screenPoint.getY());
    }

    public IPoint getScreenCoordinatesFromMapCoorindates(IPoint mapPoint, IActiveView activeView)throws Exception{
        if (mapPoint == null || mapPoint.isEmpty() || activeView == null)
            return null;

        int nad83HarnAZCentral = com.esri.arcgis.geometry.esriSRProjCSType.esriSRProjCS_NAD1983HARNSPCS_AZCentral;
        int mapUnits = com.esri.arcgis.system.esriUnits.esriFeet;
        SpatialReferenceEnvironment spatRef = new SpatialReferenceEnvironment();
        ISpatialReference nad83HarnAZC = spatRef.createProjectedCoordinateSystem(nad83HarnAZCentral);
        
        IScreenDisplay screenDisplay = activeView.getScreenDisplay();
        IDisplayTransformation displayTransformation = screenDisplay.getDisplayTransformation();
        displayTransformation.setSpatialReferenceByRef(nad83HarnAZC);
        displayTransformation.setUnits(mapUnits);
        
        int x[] = new int[1];
        int y[] = new int[1];
        displayTransformation.fromMapPoint(mapPoint, x, y);
        IPoint returnPoint = new Point();
        returnPoint.putCoords(x[0], y[0]);
        return returnPoint;
    }
}
11 Replies
LeoDonahue
Occasional Contributor III
This also works: 

com.esri.arcgis.framework.MessageDialog
MessageDialog md = new MessageDialog();
md.doModal("Map Coordinates from Screen Coordinates", message2, null, null, 0);

It's more reliable than JOptionPage, but I don't like how it looks.

What is the dialog used when you close ArcMap and it asks you to save?
0 Kudos
AlbertoDe_Luca
New Contributor
Hey Leo,

I'm facing the same problem. I can't find a way to pass the parent component neither to JOptionPane nor to JDialog. I hoped I could pass com.esri.arcgis.addins.desktop.Button as parent at least to JOptionPane, but unfortunately it does not extend java.awt.Component...

I've checked the samples on the esri web site, but they always set null as parent component...

Have you found a solution?
Alberto
0 Kudos
LeoDonahue
Occasional Contributor III
Alberto,

My solution was to take all of the dialogs out of class that extends Tool and place them in a Controller class that responds to all of my JFrame component events.

For example, I have a JFrame with a submit button. The button is a private class member with no get/set methods.  However, I added a public method to my JFrame class that allows me to assign an ActionListener to my JFrame submit button from my controller class.

Code in the MyView class that extends JFrame.
    /**
     * sal = Submit ActionListner
     * @param sal as <code>ActionListener</code>.
     */
    void addSubmitListener(ActionListener sal){
        btnSubmit.addActionListener(sal);
    }


In my controller class, once I get an instance of the JFrame, i can pass a reference to an inner class (nested in the controller class), to the JFrame public method that handles the action for that submit button.

Controller code sample located in constructor:
myView.addSubmitListener(new AddSubmitListener());


Inner class nested within the controller class, which has an instance variable of the class MyView called myView:
    /**
     * Inner class used as the ActionListener for the btnSubmit in class MyView.
     * @author donahuel
     *
     */
    class AddSubmitListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            
            String description = myView.getTxtDescription().getText();
            
            if(description.trim().equals("")){
                
                JOptionPane.showMessageDialog(myView, "Please enter a Description.", "Title", JOptionPane.ERROR_MESSAGE);
                
            } else {
                // Do other stuff
            }

        }
    }
0 Kudos
AlbertoDe_Luca
New Contributor
Leo,

thank you for your reply. I see your point, but unfortunately I need to create a JDialog (not a JFrame) because I need a modal window. And to make sure the JDialog stays on top of the ArcMap window (and inside it) I need to specify its parent component. But I don't see any way of doing it when I instantiate the JDialog in my Button's code...

Cheers
Alberto
0 Kudos
LeoDonahue
Occasional Contributor III
Sadly, there aren't any other options that will produce a Java based dialog, window or frame that is guaranteed to be on top of other windows.

Check out the Java Tutorial on how to work with Dialogs:  http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
In the JOptionPane Features section where it talks about parent component, it says:
If you specify null, then the look and feel will pick an  appropriate position for the dialog �?? generally the center of the screen  �?? and the Dialog will not necessarily follow the focus behavior of any  visible Frame or Dialog.


If you look at the Java API for the Windows class, you can try calling the toFront() method, but even that doesn't produce a JFrame that consistently places itself on top of the other windows.

If this Window is visible, brings this Window to the front and may make  it the focused Window.    Places this Window at the top of the stacking order and shows it in  front of any other Windows in this VM. No action will take place if this  Window is not visible. Some platforms do not allow Windows which own  other Windows to appear on top of those owned Windows. Some platforms  may not permit this VM to place its Windows above windows of native  applications, or Windows of other VMs. This permission may depend on  whether a Window in this VM is already focused. Every attempt will be  made to move this Window as high as possible in the stacking order;  however, developers should not assume that this method will move this  Window above all other windows in every situation. 



com.esri.arcgis.framework.MessageDialog  seems more consistent than anything else, but it is not very robust.

When I think about the times I get a dialog working with ArcInfo Desktop, I can't think of many, other than the save edits dialog.

The only other thing is to place a JFrame inside a Dockable Window and then show the dockable window, which contains the JFrame which has the JOptionPane.  The Dockable window doesn't have to be very big.  Responding to the JOptionPane could also close the Dockable window.  Kind of a painful process though...

The joys of Java + COM...  I suspect that ArcObjects .NET developers don't suffer from the modal message dialog problem.
0 Kudos
AlbertoDe_Luca
New Contributor
Well Leo,

you've pretty much confirmed what I was already suspecting: there's no way of having a java solution that gives consistent results. Unfortunately, to me (and to my my client) it's not acceptable to have a dialog that sometimes pops up and some other times pops under the ArcMap window.

So, sadly, I've downloaded Visual Studio Express and switched to VB.NET (hoping to remember something from the old VBA times...).

Thanks a lot for your help
Alberto
0 Kudos
ArjunDongre
Occasional Contributor

Hello,

  This the ONLY thread on the entire internet that discusses the problem I am having. Has there been any headway on the solution using Swing?

Thanks!

Arjun

0 Kudos
LeoDonahue
Occasional Contributor III
At least go in the C# direction.
0 Kudos
AlbertoDe_Luca
New Contributor
To tell the whole story, I had a go with C#, but realised I don't have enough time right now to learn it. And then I thought I could maybe raise my dead VB skills... Which is sad, I know... 😛
0 Kudos