"I want to draw a line, and it will highlight when I click it."


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 10 of 10

Thread: "I want to draw a line, and it will highlight when I click it."

  1. #1
    Join Date
    Sep 2005
    Posts
    14

    Red face "I want to draw a line, and it will highlight when I click it."

    I am currently working on a project right now. My project is a structural analysis software for civil engineers. Our project is already at it's infant
    stage of development. I am having trouble with how to implement drawing
    on a canvas. Heres the specs:

    -There are nodes on the drawing board illustrated by dots.
    -Lines must be drawn connecting the nodes.
    -Nodes must be a separate object where it could respond to mouse
    events.
    -Lines must also be a separate object where it could respond to mouse
    events.
    -Nodes and lines contain mathematical attributes, color information.
    -I can instantly delete a line, or change its attributes by selecting
    it.

    Heres what I have imagined:
    -I am going to draw my Nodes in a JPanel which implements a
    mouseListener.
    -Whenever I want to add nodes to the drawing board, I only have to add
    the Node objects i created.
    >> No problem with the nodes. Problem is in the lines i will be drawing
    connecting one node to another.
    -I tried manual live drawing of the lines as the mouse moves. Now its
    flat on the drawing board. It can't be touched!
    -I still don't have any idea how to implement the line that it could
    respond to mouse events.
    -If I try to draw it in a JPanel with mouseListener, a JPanel is square
    so if I move my mouse to point in to the line drawn on the JPanel, it
    will already respond before the mouse could reach the line image. One
    thing also, it could overlap other JPanels.
    -The JPanel idea came up to my mind coz I thought these objects could
    be
    selectable custom components.
    -Now I realized JPanel is not the ANSWER!

    In simple saying:
    "I want to draw a line, and it will highlight when I click it."

    Stubborn Newbie,

    Edgar

  2. #2
    Join Date
    Jul 2005
    Location
    SW MO, USA
    Posts
    299
    Do you have a lightweight line component?
    Off the top of my head:
    A line is a lightweight component containing its two end points, description info and a paint() method to display it
    There is a list of components for a panel.
    A mouselistener calls all the components in the panel to see if the mouse location is "in" one of the components, if so it calls the component telling it about the mouse position/action.
    The Component class has a contains() method. Is that called by the AWT engine?
    Have the line component override that.

  3. #3
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Basically...

    ...you want to keep track of the objects in your JPanel. You can then
    make an abstract class, say, VisibleObject that defines some
    abstract methods. Anyway, here is code that does that

    Btw, a JPanel is fine for drawing, I quit using (the "mouse deaf") Canvas
    years ago, when I discovered that mouseclicks in a Canvas on a Mac
    were completely silent, nothing happened.... It may be fixed now, but
    the JPanel is my favourite canvas...

    Code:
    import javax.swing.*;
    import java.util.*;
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.geom.*;
    
    class NodeLinePanel extends JPanel implements MouseListener {
      ArrayList voList=new ArrayList();
    
      public NodeLinePanel () {
        addMouseListener(this);
      }
    
      public void addVisibleObject(VisibleObject vo) {
        voList.add(vo);
        repaint();
      }
      public void update(Graphics g) {
        coverBackground(g, Color.white);
        for (int i=0; i<voList.size(); i++) {
          VisibleObject vo=(VisibleObject)voList.get(i);
          vo.draw(g);
        }
      }
      public void paint(Graphics g) {
        update(g);
      }
      private void coverBackground(Graphics g, Color color) {
        Color c=g.getColor();
        g.setColor(color);
        g.fillRect(0,0,getWidth(),getHeight());
        g.setColor(c);
      }
    
      public void mousePressed(MouseEvent e) {
        resetHits();
        for (int i=0; i<voList.size(); i++) {
          VisibleObject vo=(VisibleObject)voList.get(i);
          if (vo.getHit(e.getPoint())) {
            JOptionPane.showMessageDialog(this,"gotcha !"+vo.toString());
            break;
          }
        }
        repaint();
      }
      private void resetHits() {
        for (int i=0; i<voList.size(); i++) {
          VisibleObject vo = (VisibleObject) voList.get(i);
          vo.setHit(false);
        }
      }
      public void mouseClicked(MouseEvent e) {}
      public void mouseReleased(MouseEvent e) {}
      public void mouseEntered(MouseEvent e) {}
      public void mouseExited(MouseEvent e) {}
    }
    
    abstract class VisibleObject {
    
      public boolean hit=false;
      Point start = null;
    
      public abstract void draw(Graphics g);
      public abstract boolean getHit(Point p);
      public abstract String toString();
    
      public VisibleObject(){}
      public VisibleObject(Point start) {
        this.start=start;
      }
      public static StraightLine connectNodes(Node n1, Node n2) {
        StraightLine sL=new StraightLine(n1.getCenterPoint(),
                                         n2.getCenterPoint());
        return sL;
      }
      public boolean isHit() {
        return hit;
      }
      public void setHit (boolean hit) {
        this.hit=hit;
      }
      public Color getColor() {
        if (hit) {
          return Color.red;
        } else {
          return Color.blue;
        }
      }
    }
    
    class StraightLine extends VisibleObject {
      static int HIT_DISTANCE=3; // 2 pixels fuzz...
      Point end=null;
      Line2D.Double l2D=new Line2D.Double();
      public StraightLine(Point start, Point end) {
        super(start);
        this.end=end;
        l2D.setLine((double)start.x,(double)start.y,
                    (double)end.x,(double)end.y);
      }
      public String toString() {
        return "Line: "+start.x+","+start.y+" - "+
            end.x+","+end.y;
      }
      public void draw(Graphics g) {
        Color c=g.getColor();
        g.setColor(getColor());
        g.drawLine(start.x,start.y,end.x,end.y);
        g.setColor(c);
      }
      public boolean getHit(Point p) {
        double dist=l2D.ptLineDist((double)p.x, (double)p.y);
        hit = dist < HIT_DISTANCE;
        return hit;
      }
    }
    class Node extends VisibleObject {
      Rectangle r=null;
      String name=null;
      public Node (Point p, String name) {
        super(p);
        this.name=name;
      }
      public Point getCenterPoint() {
        return new Point(start.x+6, start.y+6);
      }
      public String toString() {
        return "Node "+name+": "+start.x+","+start.y;
      }
    
      public void draw(Graphics g) {
        Color c=g.getColor();
        g.setColor(getColor());
        g.fillOval(start.x,start.y,13,13);
        r=new Rectangle(start,new Dimension(13,13));
        g.drawString(name,start.x+14,start.y);
        g.setColor(c);
      }
      public boolean getHit(Point p) {
        hit=r.contains(p);
        return hit;
      }
    
    }
    public class DrawFrame extends JFrame {
    
      public DrawFrame() {
      }
      public static void main(String[] args) {
        DrawFrame dF = new DrawFrame();
        dF.getContentPane().setLayout(new GridLayout());
        NodeLinePanel pan=new NodeLinePanel();
        dF.getContentPane().add(pan);
        dF.addWindowListener(new WindowAdapter() {
          public void windowClosed(WindowEvent e) {
            System.exit(0);
          }
        });
        dF.setBounds(10,10,600,500);
        dF.setVisible(true);
        Node n1=new Node(new Point(20,20), "n1");
        Node n2=new Node(new Point(400,400), "n2");
        Node n3=new Node(new Point(100,300), "n3");
        Node n4=new Node(new Point(260,200), "n4");
        Node n5=new Node(new Point(310,180), "n5");
    
        pan.addVisibleObject(n1);
        pan.addVisibleObject(n2);
        pan.addVisibleObject(n3);
        pan.addVisibleObject(n4);
        pan.addVisibleObject(n5);
    
        pan.addVisibleObject(VisibleObject.connectNodes(n1,n2));
        pan.addVisibleObject(VisibleObject.connectNodes(n2,n3));
        pan.addVisibleObject(VisibleObject.connectNodes(n3,n4));
        pan.addVisibleObject(VisibleObject.connectNodes(n4,n5));
        pan.addVisibleObject(VisibleObject.connectNodes(n5,n1));
    
      }
    }
    One more thing or two:

    it will already respond before the mouse could reach the line image ??
    what do you mean ?

    overlap other JPanels .... what is the problem with that ?

    Last edited by sjalle; 09-18-2005 at 08:54 PM.
    eschew obfuscation

  4. #4
    Join Date
    Sep 2005
    Posts
    14

    Unhappy

    WOW to sjalle!!!

    You're so cool!!! Thanx a lot for that great wonderfull idea...

    But this is my real problem: I have to implement it that it draws the line real time... like when I click on a node, the program will begin drawing a straight - one end on the node clicked and the other end is following the mouse. It will only stop following the mouse when it clicks on another node to connect it.

    HEEELLLP!!!!!

  5. #5
    Join Date
    Jul 2005
    Location
    SW MO, USA
    Posts
    299
    Here's an idea. When the mouse clicks on a node, save its Point and then in mouseDragged, save the point where the mouse has moved to and repaint().
    Paint can test these values and draw a line from the clicked on node to the current mouse position.

    In mouseDragged() ...
    Code:
                     Point p = new Point(me.getX()-tX, me.getY()-tY);
    
                        // Set end drag line if started and not ended
                        if (selNode != NON_SELECTED) { //&& selEndNode == NON_SELECTED) {
                            selEndNode = NON_SELECTED;      // clear old line
                            // Draw line from selected node to cursor position
                            dragPoint = p;      // save for paint
                            repaint();
    In paint():
    Code:
                if (selNode != NON_SELECTED && dragPoint != null) {
                    bg.setColor(dragColor);
                    bg.drawLine(pts[selNode].x, pts[selNode].y, dragPoint.x, dragPoint.y);
    Here pts[selNode] is a Point which the mouse was initially clicked on

    In mousePressed:
    Code:
                        // Check if its over a node - for drawing a line
                        int i = inNode(p);
                        if (i >= 0) {
                            if(pts[i] == null) return;      // exit if empty
                            // Problem if only "clicking" a node to show its label???
                            saveSel = selNode;      // save in case of click
                            selNode = i;    // remember
                            return;         // found, exit
                        }
    Last edited by Norm; 09-19-2005 at 09:36 AM.

  6. #6
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Here it is....

    ...it can serve as a basis for further development.
    It has some useful basic features:

    Popup menu:
    -add node (and enter properties for it, currently just a name)
    -remove node
    -remove line
    -nodes properties window that interacts w. the node drawing panel

    CTRL+left mouse: draw connection line between nodes.
    CTRL+right mouse: drag node & connected lines

    All movement and drawing is done w. continuous screen update.

    Attached Files Attached Files
    eschew obfuscation

  7. #7
    Join Date
    Sep 2005
    Posts
    14
    sjalle,

    YOU'RE SIMPLY A GENIUS!!! Thanks a million!!!!

  8. #8
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Thanks (blush) , that's a big word.....

    ...especially since I discovered a couple of bugs. They are located in the
    NodeLinePanel class in two different methods. You should replace them
    with these two:

    Code:
    /**
       * Bring up the properties frame for the selected object
       * - at the correct location
       */
      private void showObjectProperties() {
        VisibleObject vO=checkForHit(clickPoint,true);
        propFrame.setVisibleObject(vO, voList);
    
        Point scp = imgScroller.getViewport().getViewPosition();
        Point scp1 = imgScroller.getLocationOnScreen();    
        this.propFrame.setLocation((int)(scp1.x - scp.x + clickPoint.getX()),
                                   (int)(scp1.y - scp.y + clickPoint.getY()));
        propFrame.setVisible(true);
      }
    and this one

    Code:
    /**
       * Scans all visibles for a mouse hit
       * @return the visible objec or null
       */
      public VisibleObject checkForHit(Point hitPoint, boolean select)  {
        if (select) resetHits();
        for (int i = 0; i < voList.size(); i++) {
          VisibleObject vO = (VisibleObject) voList.get(i);
          /**
           * If dragging then this node may be the dragged node,
           * if so then ignore the hit.  Omitting this test will
           * sometimes allow the user to drag a node over another.
           * The outcome depends on the visual objects sequence in
           * the vOList.
           */
          if (dragNode!=null && vO.equals(dragNode)) {
            continue;
          }
          if (vO.getHit(hitPoint, select)) {
            pFrame.showStatus("Clicked: " + vO.toString());
            return vO;
          }
        }
        return null;
      }
    eschew obfuscation

  9. #9
    Join Date
    Jul 2005
    Location
    SW MO, USA
    Posts
    299

    Difference between Swing and AWT execution speeds

    I was interested in your version of a graph of nodes as I'd written a simple one long ago. I downloaded yours and ran it and noticed that the drawing lagged the mouse a lot. I'm on a 333MHz machine.
    I tried using Swing several years ago, but it was so slow I gave up and have stayed with AWT. Not as fancy, but noticeably faster on my machine.

    I attached a jar file(renamed to zip) with my simple example. It contains source, class and manifest. Rename to jar to execute.

    Norm
    Attached Files Attached Files

  10. #10
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560
    I have had a look at your nodes program and it looks ok, as an exercise in
    graphics interactions programming (I must include the hand-cursor !).
    I assume you would experience some mouse lag if you tried it with some 20-
    30 nodes and 50+ connection lines, and moving a node with 10+ lines
    attatched to it.

    However, I am unable to test that since I cannot compile it:
    (one of many missing implementations for the 1.4 version of Shape)
    "DrawGraph.java": Error #: 454 : class norms.GraphNode should be declared abstract; it does not define method getPathIterator(java.awt.geom.AffineTransform, double) in interface java.awt.Shape at line 157, column 1
    ... unless I revert to some older java version. I'm already behind in that
    respect, as I haven't moved from 1.4 to 1.5, - can't afford the JBuilder 10
    yet

    As for awt I left that in the late 90's. I had to, in order to do my work. I
    still code some applets using only awt when required, but they don't look very
    good.

    You have my sympathy for your 333mHz machine, those were hot stuff some
    six years ago. On my 1.8 gHz machine my node app runs smoooothly. You
    should be able to aquire an "old" 1,5(+)gHz machine for very little money.
    Here in Norway you get one of those for 100-150 euro. I say this cause it's
    a drag not being able to venture into the word of swing just because your
    machine can't handle it.
    Last edited by sjalle; 09-20-2005 at 01:26 PM.
    eschew obfuscation

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center