🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.jbuilder.java.swing
4 messages
4 total messages Started by Rudy Wed, 31 Dec 2003 00:36
Design Panel
#1301
Author: Rudy
Date: Wed, 31 Dec 2003 00:36
25 lines
2011 bytes
Hi,

I thought I had almost completed the final module of a project i am
developing.  However, i have realised i have to re think the design and
would greatly appreciate some help.  As you may or may not have known, i
have been doing this for some time and have learnt a lot from doing this,
however i have no idea how to tackle this problem.

It is defined below:
- Need to be able to add, and remove images for circuit diagrams e.g.
lights, sockets etc.
    - Need to be able to select the image so that it can be manipulated,
e.g. moved, rotated
- Need to be able to draw lines for walls in any direction, but these will
also need to be selectable so that they can be changed.
- The components ie light images, socket images, walls etc will be added
using constraints for the x and y position but the image sizes are constant.
However walls can be of any length.

If anyone has any idea how to implement such a class, it would be helpful.
The class will be told the URL, x and y positions, for the image from the
'parent' class.

Thanks in advance
Rudy
Re: Design Panel
#1313
Author: John McGrath [TeamB]
Date: Sat, 03 Jan 2004 10:02
20 lines
1431 bytes
On 12/30/2003 at 7:36:17 PM, Rudy wrote:

> i have no idea how to tackle this problem.
> 
> It is defined below:
[snip]

This sounds like a fairly standard object drawing application.  As I
recall, there was a good example of developing such a program in Kim
Topley's "Core Java Foundation Classes".  Unfortunately, I do not have
a copy to check.

-- 
Regards,

John McGrath [TeamB]

---------------------------------------------------
Before sending me e-mail, please read:
    http://www.JPMcGrath.net/newsgroups/e-mail.html
Re: Design Panel
#1341
Author: Tad Frysinger [TeamB]
Date: Wed, 14 Jan 2004 19:37
20 lines
1600 bytes
John McGrath [TeamB] wrote:

> On 12/30/2003 at 7:36:17 PM, Rudy wrote:
> 
> 
>>i have no idea how to tackle this problem.
>>
>>It is defined below:
> 
> [snip]
> 
> This sounds like a fairly standard object drawing application.  As I
> recall, there was a good example of developing such a program in Kim
> Topley's "Core Java Foundation Classes".  Unfortunately, I do not have
> a copy to check.
> 
Ditto with the Geary book.

-- 
Tad Frysinger [TeamB]
Re: Design Panel
#1343
Author: Tad Frysinger [TeamB]
Date: Wed, 14 Jan 2004 20:11
364 lines
15537 bytes
Rudy wrote:

> Hi,
> 
> I thought I had almost completed the final module of a project i am
> developing.  However, i have realised i have to re think the design and
> would greatly appreciate some help.  As you may or may not have known, i
> have been doing this for some time and have learnt a lot from doing this,
> however i have no idea how to tackle this problem.
> 
> It is defined below:
> - Need to be able to add, and remove images for circuit diagrams e.g.
> lights, sockets etc.
>     - Need to be able to select the image so that it can be manipulated,
> e.g. moved, rotated
> - Need to be able to draw lines for walls in any direction, but these will
> also need to be selectable so that they can be changed.
> - The components ie light images, socket images, walls etc will be added
> using constraints for the x and y position but the image sizes are constant.
> However walls can be of any length.
> 
> If anyone has any idea how to implement such a class, it would be helpful.
> The class will be told the URL, x and y positions, for the image from the
> 'parent' class.
> 
> Thanks in advance
> Rudy
> 
> 
I have implemented this in a number of different contexts. There really 
isn't any 'single' class - there are various classes that work together. 
It is beyond the scope of a single return message to lay all this out 
for you - the last time I implemented this, I had a "designer core" 
package that handled most of the nuts and bolts of the drawing - it was 
11 classes and two interfaces. Here are some ideas to get you started:

Base drawing area class was a JLayeredPane so I could place objects at 
different layers and let Java's rendering do the work for me of making 
objects appear below (images) and above (lines representing connections).

It needs to have mouse listeners to know when the user is clicking on 
it. When the drawing surface is clicked on, all components 'selected' 
get deselected:

public abstract class DesignerPanelCore extends JLayeredPane
{
    public DesignerPanelCore()
    {
       jbInit();
    }

    private void jbInit()
    {
       setOpaque( true );
       setLayout(null);
       addMouseListener( new MouseAdapter()
       {
          public void mousePressed(MouseEvent event)
          {
             handleDPMouseEvent( event );
          }
          public void mouseClicked(MouseEvent event)
          {
             handleDPMouseEvent( event );
          }
          public void mouseReleased(MouseEvent event)
          {
             handleDPMouseEvent( event );
          }
       });
       addMouseMotionListener( new MouseMotionAdapter()
       {
          public void mouseDragged( MouseEvent event )
          {
             handleDPMouseEvent( event );
          }
       });

    }

    protected void handleDPMouseEvent( MouseEvent e )
    {
     switch ( e.getID() )
     {
       case MouseEvent.MOUSE_PRESSED:
          // Right mouse pressed is ignored here, handled in the
          // mouse click handler below
          if (e.getModifiers() == Event.META_MASK)
             break;
          // Mouse pressed outside any component
          stretcher = new StretcherRect(this, iMoveRectThickness);
          DeSelectAll();
          stretcher.setActive( true );
          stretcher.startStretch( e.getPoint() );
          break;

       case MouseEvent.MOUSE_CLICKED:
          if (e.getModifiers() == Event.META_MASK)  // because 
e.isPopupTrigger() isn't working
          {
             // right-button mouse click on designer panel
             doRightClick(e);
          }
          break;

       case MouseEvent.MOUSE_RELEASED:
          if ( bChildIsStretching )
          {
             // End dragging the stretcher for a Nib
             endChildStretch( e.getPoint() );
          }
          else if ( stretcher.isActive() )
          {
             stretcher.endStretch(e.getPoint() );
             Rectangle r = stretcher.getBounds();
             stretcher.setActive(false);
             // Select all components in bounds of rectangle as selected
             Vector trapped = new Vector();
             for ( int i = 0; i < vChildren.size(); i ++ )
             {
                DPComponent dp = (DPComponent)vChildren.elementAt(i);
                if ( r.intersects( dp.getBounds() ) )
                  trapped.addElement( dp );
             }
             if ( trapped.size() > 0 )
             {
                if ( trapped.size() == 1 )
                  selectChild( (DPComponent)trapped.firstElement(),
                               DPComponent.SELECT_SINGLE );
                else
                   for ( int i = 0; i < trapped.size(); i ++ )
                   {
                    selectChild( (DPComponent)trapped.elementAt(i),
                                 DPComponent.SELECT_MULTIPLE );
                   }
             }
          }
          break;

       case MouseEvent.MOUSE_DRAGGED:
          if (bChildIsStretching)
          {
             doChildStretch( e.getPoint() );
          }
          else if ( stretcher.isActive() )
             stretcher.doStretch( e.getPoint() );
          break;
       }
    }

You need a 'Stretcher' equivalent class to handle the "rubberbanding" 
effect you will need when creating a line, or a rectanble. I created an 
abstract base (Stretcher.java), and then extended that to lines 
(StretcherLine.java) and rectangles (StretcherRect). I use the line to 
draw lines, and the rectangle to create selection areas.

I created a 'Nib' class (essentially a small JPanel) that becomes the 
selection points on the corners of my components that allow me to resize 
them. It sounds like you don't need that for your images, but you will 
for other areas. One trick here is to associate a Nib with your base 
component class in an abstract way so that extenders of your base 
component class can handle selection, movement, etc. in a way that makes 
sense to them. I have two classes extending from my base DPComponnt 
class: (DPRectangle, DPLine) which implement some of the abstract 
methods that tell that particular component how to behave when it is 
selected, moved, etc.

One of the harder things to do is deal with mouse activity on one or 
more components of the drawing surface.  Issues here include:

1. Do you allow single/multiple select? If so, for what purpose?
2. Can the user move components around on the drawing surface?
3. Is each mode atomic?

In the base component class, I set mouse listeners for click, press, 
movement. These handlers essentially pass the mouse event up to the 
drawing surface to handle (note that there is a fair amount of work 
deciding that when a child component is clicked on, what should happen: 
do we let the user move the component around, do we just deslect, what? 
In my case, I abstracted out the region that allows a component to be 
moved so that the component implementor could tell ME what should happen):

public void handleChildMouseEvent( MouseEvent e, DPComponent dp ) {
    JComponent source = (JComponent)e.getSource();
    switch(e.getID()) {
       case MouseEvent.MOUSE_ENTERED:
          if (bBatchMove ) {
             // Mode is set to be moving components in a batch
             source.setCursor(
                Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
             break;
          }
          if ( dp.inNoMoveRegion( e ) ) {
             // The mouse entered that part of the DPComponent that
             // houses the region that we don't want to consider
             // activating a move
             source.setCursor(
               Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
             break;
          }
          // If we are this far, we are not in batch move mode
          int iSelected = dp.getSelectStatus();
          if ( iSelected > DPComponent.SELECT_NONE ) {
             // If here, we have either single selected or multiselected
             if( (source instanceof Nib) &&
               ( iSelected == DPComponent.SELECT_SINGLE ) ) {
                // Only change to stretch cursors if this is the only
                // component selected.
                dp.setNibCursor( (Nib)source );
             }
             else {
                source.setCursor(Cursor.getPredefinedCursor(Cursor.
                   MOVE_CURSOR));
             }
          } else {
             source.setCursor(
                 Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
          }
          break;

       case MouseEvent.MOUSE_EXITED:
          // batch move mode means that the cursor should always remain
          // in MOVE state, no matter which component caused the mouse
          // exit.
          if ( bBatchMove ) {
             source.setCursor(
                 Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
          } else {
             source.setCursor(Cursor.getPredefinedCursor(Cursor.
                DEFAULT_CURSOR));
          }
          break;

       case MouseEvent.MOUSE_CLICKED:
          if (e.getModifiers() == Event.META_MASK) {
             // Right clicked on designer panel
             doRightClick(e);
          }
          break;

       case MouseEvent.MOUSE_PRESSED:
          // Right mouse press ignored here
          if (e.getModifiers() == Event.META_MASK) {
             break;
          }

          if ( dp.inNoMoveRegion( e ) ) {
             break;
          }

          if ( dp.getSelectStatus() == DPComponent.SELECT_NONE ) {
             // Component isn't yet selected
             if ( !dp.isSelectable() ) {
                break;
             }
             // Mouse press on a non-selected component means we need to
             // select it.  Selection can be either
             // DPComponent.SELECT_SINGLE (black) or
             // DPComponent.SELECT_MULTIPLE (gray).
             source.setCursor(
                Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
             if ( vSelecteds.size() == 0 ) {
                // First component in the designer to be selected
                moveToFront( dp );
                selectChild( dp, DPComponent.SELECT_SINGLE );
             } else {
                if ( e.isControlDown() ) {
                   // adding to a list of selected components?
                   if (vSelecteds.size() == 1) {
                      // one prior selected element that will be in
                      // black. So make it gray, then select the new
                      // component in gray
                      ( (DPComponent) (Selecteds.firstElement()).
                            setSelection(DPComponent.SELECT_MULTIPLE);
                   }
                   selectChild( dp, DPComponent.SELECT_MULTIPLE );
                } else {
                   // Control key not down, so if there are already any
                   // other selected components, deselect them and select
                   // the new one.
                   DeSelectAll();
                   moveToFront(dp);
                   selectChild( dp, DPComponent.SELECT_SINGLE );
                }
             }
             // Once selected (whether single or multiple), the
             // component(s) can be moved around the drawing surface.
             startBatchMove(e.getPoint());
             break;
          }

          /*
            At this point, we know they pressed the mouse on some part of
            a DPComponent (b/c we wouldn't be in this method if that
            weren't the case), and that the DPComponent so pressed is
            selected.  Conditions to deal with are:

            1) The mouse press occurred on a Nib and there is only one
               component currently selected.  In this case, we should
               invoke the stretcher on the component, as the user wants
               to resize it.

            2) The mouse press occurred anywhere but a Nib, and there is
               only one component selected.  In this case, the user wants
               to move a single component.

            3) The mouse press occurred anywhere on the component, and
               there is more than one component currently selected.  In
               this case, the user wants to move all components.

            Note: items 2 & 3 are both handled as 'batch moves'.  Item
            two is just a 'batch move' of one component.
          */
          if ( (dp.getSelectStatus() == DPComponent.SELECT_SINGLE) &&
               ( source instanceof Nib ) ) {
             // Stretcher for component, based on Nib.  The point values
             // here are in the DPCore coordinate system.
             Point[] pts = dp.getInitialStretchPoints((Nib) source,
                                                       e.getPoint() );
             startChildStretch( pts[0],   // anchor
                                pts[1],   // stretched
                                dp );
          } else {
             // If control key down, delselect this individual component
             if ( e.isControlDown() ) {
                selectChild(dp, DPComponent.SELECT_NONE);
             } else {
                // Batch move all selected components.
                startBatchMove(e.getPoint());
             }
          }
          break;

       case MouseEvent.MOUSE_RELEASED:
          if ( bBatchMove ) {
             endBatchMove();
          }
          else if (bChildIsStretching) {
             // End dragging the stretcher for a Nib
             endChildStretch( dp.getStretchPoint( e.getPoint() ) );
          }
         break;

       case MouseEvent.MOUSE_DRAGGED:
          if ( bBatchMove ) {
            doBatchMove( e.getPoint() );
          } else if (bChildIsStretching) {
            // Dragging the stretcher for a Nib
            doChildStretch( dp.getStretchPoint( e.getPoint() ) );
          }
          break;
    }
}



For the actual drawing code, the only thing that is a little weird is 
the line drawing, and rubberbanding. I did everything else with stock 
Swing components (i.e. JPanels, etc.). I'd suggest you get Topley or 
Geary's book, perhaps an intro to Java 2D would help as well.


-- 
Tad Frysinger [TeamB]
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads