Thread View: borland.public.jbuilder.java.swing
4 messages
4 total messages
Started by Rudy
Wed, 31 Dec 2003 00:36
Design Panel
Author: Rudy
Date: Wed, 31 Dec 2003 00:36
Date: Wed, 31 Dec 2003 00:36
25 lines
2011 bytes
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
Author: John McGrath [TeamB]
Date: Sat, 03 Jan 2004 10:02
Date: Sat, 03 Jan 2004 10:02
20 lines
1431 bytes
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
Author: Tad Frysinger [TeamB]
Date: Wed, 14 Jan 2004 19:37
Date: Wed, 14 Jan 2004 19:37
20 lines
1600 bytes
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
Author: Tad Frysinger [TeamB]
Date: Wed, 14 Jan 2004 20:11
Date: Wed, 14 Jan 2004 20:11
364 lines
15537 bytes
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