Menu

Using JHotDraw together with JXLayer

Help
yccheok
2010-04-02
2013-05-01
  • yccheok

    yccheok - 2010-04-02

    So far, I am a happy JHotDraw users. I had been using JHotDraw in JStock's Indicator Editor exclusively.

    Recently, I had use JXLayer, to overlay two moving yellow message boxes, on the top of JFreeChart

    http://yccheok.blogspot.com/2010/02/investment-flow-chart.html

    I was wondering, had anyone experience using JXLayer + JHotdraw, to overlay all sorts of figures (Re-sizable text box, straight line, circle…), on the top of JFreeChart.

    I just would like to add drawing capability, without changing the JFreeChart source code. So that, JStock's user may draw trending lines, annotation text on their favorite stock charting.

    If anyone of you had experience of doing so, I will be very happy, if you are willing to share your experience to us.

    Thank you very much.

     
  • Werner Randelshofer

    Hi,

    I am not familiar with JFreeChart and JXLayer.
    I guess JFreeChart provides a JComponent into which it draws its chart?

    If this is the case, you can create a JHotDraw Figure which invokes the paint-Method of that JComponent.

    Here is a rough idea on how I would do it:

    1. Create a subclass of RectangleFigure.

    2. Override the draw-method. Create a javax.swing.CellRendererPane. Resize it to match the bounds of the figure. Add the JFreeChart component to it. Call the paint-method of the CellRendererPane.

    3. Override the getLayer method. Make it return -1. This way, this figure will stay below all other JHotDraw figures.

    4. Override methods isConnectable, isSelectable, isTransformable and make them all return false. This way, the figure can not be edited.

    Best,
    Werner

     
  • yccheok

    yccheok - 2010-04-03

    Thanks Werner.

    Is your suggested way only able to draw rectangle figures? How about circle figures, line figures, picture figures…

    For my, I prefer to do in the following way. However, I am not sure whether it is possible to do so.

    // this.chartPanel is JFreeChartPanel
    final org.jdesktop.jxlayer.JXLayer<ChartPanel> layer = new org.jdesktop.jxlayer.JXLayer<ChartPanel>(this.chartPanel);
    this.myUI = new MyUI<ChartPanel>(this);
    layer.setUI(this.myUI);
            
    public class MyUI<V extends javax.swing.JComponent> extends AbstractLayerUI<V> {
        @Override
        protected void paintLayer(Graphics2D g2, JXLayer<? extends V> layer) {
            // Previous, I am using my own hand-coded, to draw the yellow box
            //
            // Now, How can I make use of JHotDraw at here, to draw various type of
            // figures?
        }
        
        @Override
        protected void processMouseEvent(MouseEvent e, JXLayer<? extends V> layer) {
            // How can I make use of JHotDraw at here?
        }
        @Override
        protected void processMouseMotionEvent(MouseEvent e, JXLayer<? extends V> layer) {
            // How can I make use of JHotDraw at here?
        }
    }
    

    As you see, I already got Graphics2D g2 from paintLayer method. How is it possible that I can pass the Graphics2D object to JHotDraw, and let JHotDraw handles all the drawing.

    My experience in using JHotDraw are with

    org.jhotdraw.draw.DefaultDrawingView
    org.jhotdraw.draw.DefaultDrawingEditor

    I am able to use them to draw various figures, by clicking on the toolbar and click on drawing area.

    How is it possible I can use DefaultDrawingView and DefaultDrawingEditor within MyUI's paintLayer?

    Also, shall I let MyUI handles the mouse event, or JHotDraw?

    Sorry, I start getting confused.

     
  • yccheok

    yccheok - 2010-04-03

    Sorry. The code tag seems missing in previous post.

    // this.chartPanel is JFreeChartPanel
    final org.jdesktop.jxlayer.JXLayer<ChartPanel> layer = new org.jdesktop.jxlayer.JXLayer<ChartPanel>(this.chartPanel);
    this.myUI = new MyUI<ChartPanel>(this);
    layer.setUI(this.myUI);
            
    public class MyUI<V extends javax.swing.JComponent> extends AbstractLayerUI<V> {
        @Override
        protected void paintLayer(Graphics2D g2, JXLayer<? extends V> layer) {
            // Previous, I am using my own hand-coded, to draw the yellow box
            //
            // Now, How can I make use of JHotDraw at here, to draw various type of
            // figures?
        }
        
        @Override
        protected void processMouseEvent(MouseEvent e, JXLayer<? extends V> layer) {
            // How can I make use of JHotDraw at here?
        }
        @Override
        protected void processMouseMotionEvent(MouseEvent e, JXLayer<? extends V> layer) {
            // How can I make use of JHotDraw at here?
        }
    }
    
     
  • Werner Randelshofer

    Sorry, maybe I should have elaborated my proposal a bit more.

    The code snippets that you have posted are useful for displaying a JHotDraw drawing on top of JFreeChart.
    This is perfectly fine. But it is not suited for editing a drawing.

    My proposal is to create a new figure class which holds the JFreeChart JComponent.
    I am suggesting to use RectangleFigure as super class, because JComponent's are rectangular.

    Then you can add this figure to your drawing, and display that drawing in a DefaultDrawingView.
    You can use DefaultDrawingEditor to make the drawing in the drawing view editable.

    hth,
    Werner

     
  • yccheok

    yccheok - 2010-04-04

    Thanks. Hope able to obtain your priceless support during the integration work ;)

    What I start to do is :

    http://jstock.cvs.sourceforge.net/viewvc/jstock/jstock/src/org/yccheok/jstock/gui/charting/ChartJDialog.java?revision=1.20&view=markup

    For line 133, instead of

    getContentPane().add(layer, java.awt.BorderLayout.CENTER);
    

    I change it to :

            final JComponentFigure jComponentFigure = new JComponentFigure(layer);
            final java.awt.Rectangle rect = this.svgDrawingPanel.getBounds();
            System.out.println(rect);   // dimension is 0?
            // Temporary hard coded.
            jComponentFigure.setBounds(new Rectangle2D.Double(0, 0, 450, 450));
            this.svgDrawingPanel.addFigure(jComponentFigure);
            getContentPane().add(svgDrawingPanel, java.awt.BorderLayout.CENTER);
    

    JComponentFigure code is as follow :

    public class JComponentFigure extends RectangleFigure {
        public JComponentFigure(JComponent component) {
            this.component = component;
            this.cellRendererPane = new CellRendererPane();
        }
        @Override
        public void draw(Graphics2D g) {
            super.draw(g);
            final Rectangle2D.Double rectDouble = this.getDrawingArea();
            final Rectangle rect = new Rectangle((int)rectDouble.getX(), (int)rectDouble.getY(), (int)rectDouble.getWidth(), (int)rectDouble.getHeight());
            cellRendererPane.paintComponent(g, component, component.getParent(), rect);
            System.out.println("JComponentFigure's draw is being triggered");
        }
        private final CellRendererPane cellRendererPane;
        private final JComponent component;
    }
    

    svgDrawingPanel, are just simply picked from sample code found at JHotDraw\Source\jhotdraw7\src\main\java\org\jhotdraw\samples\svg\SVGDrawingPanel.java

    with new method being added in SVGDrawingPanel.

        public void addFigure(Figure figure) {
            this.view.getDrawing().add(figure);
        }
    

    I am getting something like

    By using println, I am pretty sure JComponentFigure 's pain method is being triggered.

    Anything I had missed out?

    Thanks.

     
  • Werner Randelshofer

    You may have to override method isShowing of the JComponent that you want to draw using the cellRenderePane.

    The JavaDoc of CellRendererPane says:
    "A renderer component must override isShowing() and unconditionally return true to work correctly because the Swing paint does nothing for components with isShowing false."

    Best,
    Werner

     
  • Werner Randelshofer

    Alternatively, if all this gets too complicated.
    You might render the JComponent into a BufferedImage, and then use an ImageFigure to represent it in the drawing.

    Best,
    Werner

     
  • yccheok

    yccheok - 2010-04-04

    I tried

        public JComponentFigure(JComponent component) {
            this.component = component;
            this.cellRendererPane = new CellRendererPane() {
                @Override
                public boolean isShowing() {
                    return true;
                }
            };
        }
    

    But result is still the same :(

     
  • yccheok

    yccheok - 2010-04-04

    My another concern is, are JHotDraw able to pass all the necessary event back to my old JXLayer and JFreeChart

    JXLayer - concern about mouse move event, where when I move the mouse along, the yellow box will follow the mouse movement.

    JFreeChart - concern about mouse drag event, to handle chart zoom-in and zoom-out.

     
  • Werner Randelshofer

    >I tried
    >…
    >But result is still the same :(

    You have to override method isShowing of JFreeChart. Since this is the JComponent that is going to be rendered by the CellRendererPane:

    JFreeChart myChart = new JFreeChart() {
      @Override public boolean isShowing() { return true; }
    };

    > My another concern is, are JHotDraw able to pass all the necessary event back to my old JXLayer and JFreeChart

    Hm. Do you really want JFreeChart and JXLayer to process input events while the user is drawing on top of them?
    I don't think this is a good idea.

    For example what happens if the user drags a figure? Its not a good idea to let JFreeChart perform a zoom-in or zoom-out during this operation.

    By integrating JFreeChart as a Figure into JHotDraw, you can easily coordinate all user input.

    > JXLayer - concern about mouse move event, where when I move the mouse along, the yellow box will follow the mouse
    > movement.

    JHotDraw already supports tooltips on figures. You can override method getToolTipText in your JComponentFigure.

    > JFreeChart - concern about mouse drag event, to handle chart zoom-in and zoom-out.

    JHotDraw already has a zoom function.
    I think you certainly want to keep the zoom factor of the drawing in sync with the zoom factor of the JFreeChart?

    hth,
    Werner

     
  • yccheok

    yccheok - 2010-04-07

    Sorry for late reply. I haven't try that out yet as I am working on other stuffs else. Will update here soon…

     
  • yccheok

    yccheok - 2010-04-13

    I am able to have JFreeChart component display within the rectangle figure, by removing JXLayer (Not sure why, even I set isShowing to true for JXLayer), after set isShowing to true for JFreeChart.

    However, one of the expected short coming is, all event listener behavior default to JFreeChart component is lost.

    Is there any way, where by push down a draw button, all the event will be forwarded to JHotDraw. and by pop up a draw button, all the event will be forwarded to the component re-inside (JFreeChart component) rectangle figure?

    Is not, I prefer to implement the draw code within JXLayer draw function, by using several data structure class from JHotDraw. I only need some primitive drawing feature

    - click and move, on an empty draw area, to draw a new figure.
    - click and move, on an already drawn figure, to drag move the figure.
    - click and move, to resize the selected figure.
    - figure will be circle, lines and pictures.

    Do you have any suggestion on which data structure classes from JHotDraw I can re-use?

     
  • Werner Randelshofer

    I am glad that embedding JFreeChart into RectangleFigure worked.

    As far as I can tell, the things that you are missing now are:

    A) Tooltips (which you previously implemented by means of JXLayer)

    B) Zooming (which previously was provided by JFreeChart)

    To achieve A) you can override method getToolTipText(Point2D.Double) in RectangleFigure. The implementation will be very much like the one you already have. You just need to translate the point by the start point of the RectangleFigure. You can use method getStartPoint for this.

    For B) you can implement a new DragTracker, which changes the scale factor of the drawing view instead of moving figures.

    > Is there any way, where by push down a draw button, all the event will be forwarded to JHotDraw. and by pop up a draw
    > button, all the event will be forwarded to the component re-inside (JFreeChart component) rectangle figure?

    Yes. All event handling is done by Tool objects. You can create a Tool which doesn't provide drawing behavior.
    If the user clicks the button for this tool, then JHotDraw is in "viewing mode", the user clicks on the button for another tool, then JHotDraw is in "editing mode".

    How to put things together:

    1. I suggest that you first try to implement the tooltips.

    2. Then try adding a button for an additional DefaultDelegationTool to your user interface. You can use ButtonFactory.addSelectionToolTo(JToolBar, DrawingEditor, Tool) for creating the toolbar button.

    3. Strip functionality from the additional DefaultDelegationTool to achieve a "viewing mode". You can do this, by creating empty implementations of HandleTracker, SelectAreaTracker and DragTracker and setting them to the DefaultDelegationTool.

    4. Now implement a new DragTracker  - as I suggested for B - and set it to the additional DefaultDelegationTool.

    hth,
    Werner

     
  • yccheok

    yccheok - 2010-04-15

    I still have question in doubt :)

    1) public String getToolTipText(Point2D.Double p);

    I afraid by overriding the getToolTipText doesn't meet my requirement as

    1) http://3.bp.blogspot.com/_ttdgIQxreUA/S4ECdNEjQ-I/AAAAAAAADPY/W2OvcQoQGjU/s1600-h/genting.png
    - It doesn't let me specific I want yellow semi-transparent background.
    - It doesn't let me specific I want yellow border
    - It doesn't let me specific the font type
    - It doesn't let me specific the text alignment.

    2) Currently, if I right click on JFreeChart, it can pop up a menu with wide range of functionality selection.
    - How can I pass the right click event to JFreeChart?

    Thanks.

     
  • Werner Randelshofer

    Please note that my interest is just into showing you a way through the JHotDraw framework.
    There might be other approaches to solve this problem. I don't know your requirements in detail.

    1)
    JTooltip supports HTML. You can specify the font type, alignments and stuff like this using HTML.
    If this is not sufficient, you can always add new methods to your RectangleFigure and then look for uses of method Figure.getToolTipText(Point2D.Double) in JHotDraw - which will lead you to the Tool classes down to DelegationSelectionTool and the DefaultDrawingView -, and then extend these classes along this execution path.

    2)
    You can't pass AWT events down to JFreeChart anymore since it used as a "rubber stamp" in RectangleFigure.
    If you want to have support for actions presented by the JFreeChart popup menu, _while_ the drawing editor is in "edit mode" (as described in my previous reply) you need to find a way to retrieve the underlying Actions from JFreeChart and then relegate them to method RectangleFigure.getActions(Point2D.Double).

    Alternatively, if you only need support for JFreeChart functionality while the drawing editor is in "view mode" then you can use the JXLayer solution, which you already have implemented, while "view mode" is on, and the above solution, while "edit mode" is on.

    Best,
    Werner

     
  • yccheok

    yccheok - 2010-04-19

    Hi Werner,

    I did some quick hack during weekend. I try to get some additional advice from JXLayer community. The closest solution I can get is http://forums.java.net/jive/thread.jspa?messageID=397847&#397847

    Not sure whether you would like to provide additional advice?

    The worst come to worst, is I plan to use data structure classes (Figure…) from JHotDraw, but implement the real painting code directly inside JXLayer. But of course, that is for the worst case, if only there isn't any more better way to integrate JHotDraw with JFreeChart.

    Thanks.

     
  • Werner Randelshofer

    Well, you have now explored two different alternatives. It is up to you to pick the one which suits you best.

    Personally, I think both approaches are very fragile. I mean, you are jumbling together four
    libraries here (JXLayer, JHotDraw, JFreeChart and your tooltips).

    Personally, I would implement the chart as a Figure in JHotDraw.
    This way, I would only have to deal with a single library.

    Best,
    Werner

     

Log in to post a comment.

MongoDB Logo MongoDB