JButtonの矢印線での繋ぎこみとatan2()について
戻る
::::::::::::::
AbstractStep.java
::::::::::::::
public abstract class AbstractStep {
public abstract void addNextStep( AbstractStep nextStep );
}
::::::::::::::
DrawingPanel.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class DrawingPanel extends JPanel implements ActionListener, MouseListener {
/** ポップアップメニューのインスタンス */
private JPopupMenu popup = null;
private int xPos = 0;
private int yPos = 0;
/** 操作モード(リンク、整列)を表す値 */
private Operation.Mode mode = Operation.Mode.DEFAULT;
private StepView linkSource = null;
private StepView linkTarget = null;
/** 各ステップのリストを格納するマネージャクラス */
private StepManager stepManager;
/** コンストラクタ */
public DrawingPanel() {
popup = new JPopupMenu();
popup.setPopupSize( 120, 50 );
JMenuItem menuItem1 = new JMenuItem( "ステップ作成" );
menuItem1.setActionCommand( "CREATE_STEP" );
menuItem1.addActionListener( this );
popup.add( menuItem1 );
JMenuItem menuItem2 = new JMenuItem( "シリアライズ" );
menuItem2.setActionCommand( "SERIALIZE" );
menuItem2.addActionListener( this );
popup.add( menuItem2 );
// レイアウトマネージャを使用しない
setLayout( null );
addMouseListener( this );
stepManager = new StepManager();
}
public void actionPerformed( ActionEvent e ) {
if ( e.getSource() instanceof JMenuItem ) {
//
// 右クリックからのメニューを選択した場合
//
JMenuItem source = ( JMenuItem ) ( e.getSource() );
System.out.println( "Action Command is " + source.getText() );
String command = e.getActionCommand();
// ポップアップメニューを開いた座標値を求める
// System.out.printf( "x=%3d, y=%3d: commnad=%s\n", xPos, yPos, command );
if ( "CREATE_STEP".equals( command ) ) {
StepView stepView = new StepView();
// setBounds()はJButtonから継承したメソッド
stepView.setBounds( xPos, yPos, 100, 20 );
stepView.addActionListener( this );
this.add( stepView );
// マウスドラッグのモーションリスナを登録
MouseMotionListener motionListener = new MouseDraggedEventHandler( this, stepView );
stepView.addMouseMotionListener( motionListener );
// ステップマネージャーに登録
stepManager.addStepView( stepView );
}
}
if ( e.getSource() instanceof StepView ) {
//
// ボタンをクリックした場合
//
StepView source = ( StepView ) ( e.getSource() );
// System.out.println( source );
if ( mode == Operation.Mode.LINK ) {
linkTarget = source;
// 色を元に戻す
linkSource.restoreBackground();
// sourceとtargetをリンクする
stepManager.connect( linkSource, linkTarget );
stepManager.dumpList();
// 再描画
repaint();
System.out.println( "リンク先が設定されました!" );
// 設定を元にもどす
restoreMode();
}
if ( mode == Operation.Mode.DELINK ) {
linkTarget = source;
// 色を元に戻す
linkSource.restoreBackground();
// sourceとtargetをリンクする
stepManager.disconnect( linkSource, linkTarget );
stepManager.dumpList();
// 再描画
repaint();
System.out.println( "リンク先が解除されました!" );
// 設定を元にもどす
restoreMode();
}
}
}
/** 設定を元に戻す */
private void restoreMode() {
mode = Operation.Mode.DEFAULT;
linkSource = null;
linkTarget = null;
}
public void mousePressed( MouseEvent e ) {
if ( e.isPopupTrigger() ) {
/* JPopupMenuを表示 */
popup.show( e.getComponent(), e.getX(), e.getY() );
xPos = ( int ) e.getX();
yPos = ( int ) e.getY();
popup.pack();
}
}
public void mouseReleased( MouseEvent e ) {
if ( e.isPopupTrigger() ) {
/* JPopupMenuを表示 */
popup.show( e.getComponent(), e.getX(), e.getY() );
xPos = ( int ) e.getX();
yPos = ( int ) e.getY();
popup.pack();
}
}
/** マウスがクリックされた時の処理 */
public void mouseClicked( MouseEvent e ) {
int modifier = e.getModifiers();
// SHIFT,ALT,CTRLキーの押下の判別
String s = getShiftAltCtrl( modifier );
System.out.println( s );
if ( ( modifier & InputEvent.BUTTON1_MASK ) != 0 ) {
/** 左クリック **/
System.out.println( "LEFT CLICK!" );
} else if ( ( modifier & InputEvent.BUTTON2_MASK ) != 0 ) {
/** DO NOTHING */
} else if ( ( modifier & InputEvent.BUTTON3_MASK ) != 0 ) {
/** 右クリック **/
// ここは通らなくなってしまいます
System.out.println( "ポップアップメニューが表示されます!" );
}
}
private String getShiftAltCtrl( int modifier ) {
StringBuffer sb = new StringBuffer();
if ( ( modifier & InputEvent.SHIFT_MASK ) != 0 ) {
sb.append( "SHIFT " );
}
if ( ( modifier & InputEvent.ALT_MASK ) != 0 ) {
sb.append( "ALT " );
}
if ( ( modifier & InputEvent.CTRL_MASK ) != 0 ) {
sb.append( "CTRL " );
}
return ( new String( sb ) );
}
public void mouseEntered( MouseEvent e ) {}
public void mouseExited( MouseEvent e ) {}
/**
in case when repaint() method is invoked, this method is also executed.
*/
public void paintComponent( Graphics g ) {
System.out.println( "paintComponet:" );
int width = getWidth();
int height = getHeight();
// 画面クリア
g.setColor( Color.black );
// このコンポーネントのサイズを取得する
g.fillRect( 0 , 0 , width , height );
//=====================================-
// 各オブジェクトを線で繋ぐ
//=====================================-
g.setColor( Color.blue );
java.util.List connections = stepManager.getList();
for ( int i = 0;i < connections.size();i++ ) {
JComponent from = ( JComponent ) connections.get( i );
java.util.List links = ( ( StepView ) from ).getLinks();
Iterator iterator = links.iterator();
while ( iterator.hasNext() ) {
StepView link = ( StepView ) iterator.next();
if ( !connections.contains( link ) ) {
continue;
}
JComponent to = ( JComponent ) link;
Rectangle fromRect = from.getBounds();
Rectangle toRect = to.getBounds();
// System.out.println( fromRect + "\t" + toRect );
//--------------------------------------
// 矢印を描画する
//--------------------------------------
LineDrawer.draw( g, fromRect, toRect );
}
}
}
/** リンク元の選択 */
public void setLinkSource( StepView stepView, Operation.Mode mode ) {
System.out.println( "リンク元が選択されました" );
linkSource = stepView;
// mode should be either Operation.Mode.LINK or Operation.Mode.DELINK
this.mode = mode;
}
/** 現在の操作モードを取得する */
public Operation.Mode getOperationMode() {
return mode;
}
public void disposeStepView( StepView stepView ) {
stepManager.removeStepView( stepView );
// 再描画
repaint();
}
}
::::::::::::::
EntryPoint.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class EntryPoint extends JComponent implements ActionListener {
public void paintComponent( Graphics g ) {
int width = getWidth();
int height = getHeight();
// 画面クリア
g.setColor( Color.red );
// このコンポーネントのサイズを取得する
g.fillRect( 0 , 0 , width , height );
}
public void addActionListener( ActionListener l ) {
listenerList.add( ActionListener.class, l );
}
public void actionPerformed( ActionEvent e ) {
System.out.println( this );
}
}
::::::::::::::
ExitPoint.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class ExitPoint extends JComponent implements ActionListener {
public void paintComponent( Graphics g ) {
int width = getWidth();
int height = getHeight();
// 画面クリア
g.setColor( Color.white );
// このコンポーネントのサイズを取得する
g.fillRect( 0 , 0 , width , height );
}
public void actionPerformed( ActionEvent e ) {
System.out.println( this );
}
}
::::::::::::::
LineDrawer.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class LineDrawer {
public static void draw( Graphics g, Rectangle fromRect, Rectangle toRect ) {
// 最短の距離を求める
int[] position = ShortestDistanceObtainer.getShortest( fromRect, toRect );
int fromX = position[ 0 ];
int fromY = position[ 1 ];
int toX = position[ 2 ];
int toY = position[ 3 ];
g.drawLine( fromX, fromY, toX, toY );
// 線分の傾きを求める
double[] fromDouble = new double[] {fromX, fromY};
double[] toDouble = new double[] {toX, toY};
double angle = StepUtils.getAngle( fromDouble, toDouble );
double oneAngle = angle + 150.0;
double anotherAngle = angle - 150.0;
System.out.printf( "%3.0f,%3.0f,%3.0f\n",
angle, oneAngle, anotherAngle );
// 矢印の部分を表示する
double pitch = 15.0;
g.drawLine( ( int ) ( toX + pitch * Math.cos( StepUtils.degreeToRadian( oneAngle ) ) ),
( int ) ( toY + pitch * Math.sin( StepUtils.degreeToRadian( oneAngle ) ) ),
toX, toY );
g.drawLine( ( int ) ( toX + pitch * Math.cos( StepUtils.degreeToRadian( anotherAngle ) ) ),
( int ) ( toY + pitch * Math.sin( StepUtils.degreeToRadian( anotherAngle ) ) ),
toX, toY );
}
}
::::::::::::::
MouseDraggedEventHandler.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.io.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class MouseDraggedEventHandler implements MouseMotionListener {
private JComponent component;
private Container container;
public MouseDraggedEventHandler( Container container, JComponent component ) {
this.container = container;
this.component = component;
}
public void mouseDragged( MouseEvent argEvent ) {
System.out.printf( "(%3d,%3d)\n", argEvent.getX() , argEvent.getY() );
if ( argEvent.getX() < 0 || argEvent.getY() < 0 ) {
Rectangle objBounds = component.getBounds();
component.setLocation( objBounds.x + argEvent.getX(), objBounds.y + argEvent.getY() );
} else {
Rectangle objBounds = component.getBounds();
if ( objBounds.x <= objBounds.x + argEvent.getX() && objBounds.x + argEvent.getX() <= objBounds.x + objBounds.width &&
objBounds.y <= objBounds.y + argEvent.getY() && objBounds.y + argEvent.getY() <= objBounds.y + objBounds.height ) {
component.setLocation( objBounds.x + argEvent.getX(), objBounds.y + argEvent.getY() );
} else {
component.setLocation( argEvent.getX(), argEvent.getY() );
}
}
container.repaint();
}
public void mouseMoved( MouseEvent argEvent ) { }
}
::::::::::::::
MyAbstractAction.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class MyAbstractAction extends AbstractAction {
public MyAbstractAction() {
super();
}
public void actionPerformed( ActionEvent event ) {
String eventname = event.getActionCommand();
// 実行されたコマンドをダンプします
System.out.println( "..." );
}
}
::::::::::::::
Operation.java
::::::::::::::
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class Operation {
static public enum Mode {DEFAULT /** デフォルト */
, LINK /** リンク設定モード */
, DELINK /** リンク解除モード */
, ALIGNMENT /** 整列 */}
}
::::::::::::::
ShortestDistanceObtainer.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class ShortestDistanceObtainer {
public static int[] getShortest( Rectangle source , Rectangle destination ) {
int[] position = new int[ 4 ];
Point[] sourceMidPoints = getMidPoints( source );
Point[] destinationMidPoints = getMidPoints( destination );
double min = Double.MAX_VALUE;
for ( int i = 0;i < 4;i++ ) {
Point from = sourceMidPoints[ i ].getLocation();
for ( int j = 0;j < 4;j++ ) {
Point to = destinationMidPoints[ j ].getLocation();
double value = ( from.getX() - to.getX() ) * ( from.getX() - to.getX() )
+ ( from.getY() - to.getY() ) * ( from.getY() - to.getY() );
if ( value < min ) {
min = value;
position[ 0 ] = ( int ) from.getX();
position[ 1 ] = ( int ) from.getY();
position[ 2 ] = ( int ) to.getX();
position[ 3 ] = ( int ) to.getY();
}
}
}
return position;
}
// 矩形の各辺の中点を求める
private static Point[] getMidPoints( Rectangle rectangle ) {
Point[] midPoints = new Point[ 4 ];
for ( int i = 0;i < midPoints.length;i++ ) {
midPoints[ i ] = new Point();
}
/**
System.out.println( "--" + rectangle );
System.out.println( "--" + rectangle.x );
System.out.println( "--" + rectangle.y );
System.out.println( "--" + rectangle.width );
System.out.println( "--" + rectangle.height );
*/
// 上の中点
midPoints[ 0 ].setLocation( rectangle.x + rectangle.width / 2.0, rectangle.y );
// 右の中点
midPoints[ 1 ].setLocation( rectangle.x + rectangle.width, rectangle.y + rectangle.height / 2.0 );
// 下の中点
midPoints[ 2 ].setLocation( rectangle.x + rectangle.width / 2.0, rectangle.y + rectangle.height );
// 左の中点
midPoints[ 3 ].setLocation( rectangle.x , rectangle.y + rectangle.height / 2.0 );
return midPoints;
}
}
::::::::::::::
StepDrawingTest.java
::::::::::::::
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class StepDrawingTest extends JFrame {
private int width = 640;
private int height = 480;
public StepDrawingTest() {
super( "フローチャートのステップを追加したり変更・削除してみたりする。[矢印を使って繋ぐ]" );
Container contentPane = getContentPane();
contentPane.setLayout( new FlowLayout() );
DrawingPanel dp = new DrawingPanel();
dp.setPreferredSize( new Dimension( width, height ) );
contentPane.add( dp );
}
public static void main( String[] args ) {
StepDrawingTest frame = new StepDrawingTest();
/* 終了処理を追加 */
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e ) {
System.exit( 0 );
}
}
);
/** サイズと位置を指定 */
frame.setBounds( 0, 0, frame.width, frame.height );
frame.setVisible( true );
frame.pack();
}
}
::::::::::::::
StepManager.java
::::::::::::::
import java.util.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class StepManager {
private List list;
public StepManager() {
list = new LinkedList();
}
public void addStepView( StepView stepView ) {
list.add( stepView );
}
public void removeStepView( StepView stepView ) {
list.remove( stepView );
}
/** リンクする */
public void connect( StepView one, StepView another ) {
if ( !list.contains( one ) ) {
System.err.println( one.getText() + " はリンク対象外です" );
return ;
}
if ( !list.contains( another ) ) {
System.err.println( another.getText() + " はリンク対象外です" );
return ;
}
try {
// 片方向である
if ( one.hasLinkTo( another ) || another.hasLinkTo( one ) ) {
// すでにどちらかの方向でリンクされている場合は何もしない
return ;
}
one.link( another );
} catch ( Exception e ) {
e.printStackTrace();
}
}
/** リンク解除する */
public void disconnect( StepView one, StepView another ) {
try {
// リンク解除する場合は、リンクしている側およびリンクされている側のどちらからも解除できる
if ( one.hasLinkTo( another ) ) {
one.delink( another );
}
if ( another.hasLinkTo( one ) ) {
another.delink( one );
}
} catch ( Exception e ) {
e.printStackTrace();
}
}
public List getList() {
return list;
}
public void dumpList() {
Iterator iterator = list.iterator();
while ( iterator.hasNext() ) {
StepView view = ( StepView ) iterator.next();
System.out.print( view.getText() + ": " );
Iterator itrt = view.getLinks().iterator();
while ( itrt.hasNext() ) {
StepView link = ( StepView ) itrt.next();
if ( list.contains( link ) ) {
// マネージャが管轄しているものだけを取り出す
System.out.print( link.getText() + " " );
}
}
System.out.println();
}
System.out.println();
}
public static void main( String[] args ) {
StepManager manager = new StepManager();
StepView view1 = new StepView();
StepView view2 = new StepView();
StepView view3 = new StepView();
StepView view4 = new StepView();
manager.addStepView( view1 );
manager.addStepView( view2 );
manager.addStepView( view3 );
manager.addStepView( view4 );
manager.dumpList();
manager.removeStepView( view2 );
manager.dumpList();
manager.connect( view1, view2 );
manager.connect( view1, view1 );
manager.connect( view1, view3 );
manager.connect( view1, view3 );
manager.dumpList();
manager.disconnect( view1, view3 );
manager.disconnect( view1, view3 );
manager.dumpList();
}
}
::::::::::::::
StepUtils.java
::::::::::::::
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class StepUtils {
/** 線分の傾きを角度で返す
* @param from 開始点
* @param to 終了点
* @return 角度
*/
static double getAngle( double[] from , double[] to ) {
double xDiff = to[ 0 ] - from[ 0 ];
double yDiff = to[ 1 ] - from[ 1 ];
// 【注意】
// DEGREE(度)で返す -- atan(傾き)だと傾きの正負を意識する必要がでてくる
//
return Math.atan2( yDiff, xDiff ) * 180.0 / Math.PI;
}
/** 角度をラジアンに変換して返す */
static double degreeToRadian( double angle ) {
return angle * Math.PI / 180.0;
}
}
::::::::::::::
StepView.java
::::::::::::::
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
@author KISHI Yasuhiro
*/
public class StepView extends JButton implements ActionListener {
static int serialNo = 0;
/** ポップアップメニューのインスタンス */
private JPopupMenu popup = null;
/** もともとの背景色 */
private Color originalBackgroundColor;
/** リンク先 */
private java.util.List links;
/** コンストラクタ */
public StepView() {
super();
serialNo ++;
super.setText( "step" + serialNo );
originalBackgroundColor = this.getBackground();
popup = new JPopupMenu();
// popup.setPopupSize( 120, 50 );
popup.setBackground( Color.yellow );
addMenuItem( "プロパティ編集", "EDIT" );
addMenuItem( "削除", "KILL_ITSELF" );
addMenuItem( "リンク設定", "LINK" );
addMenuItem( "リンク解除", "DELINK" );
addMouseListener( new MouseAdapter() {
public void mousePressed( MouseEvent e ) {
if ( e.isPopupTrigger() ) {
/* JPopupMenuを表示 */
popup.show( e.getComponent(), e.getX(), e.getY() );
}
}
public void mouseReleased( MouseEvent e ) {
if ( e.isPopupTrigger() ) {
/* JPopupMenuを表示 */
popup.show( e.getComponent(), e.getX(), e.getY() );
}
}
}
);
links = new LinkedList();
}
/** 対象StepViewに対してリンクしているかどうか */
public boolean hasLinkTo( StepView stepView ) {
return links.contains( stepView );
}
/** リンクを設定する */
public void link( StepView stepView ) throws Exception {
if ( stepView.equals( this ) ) {
throw new StepViewLinkException( "自分自身にはリンク設定できません" );
}
if ( links.contains( stepView ) ) {
throw new StepViewLinkException( "既にリンクされています" );
}
links.add( stepView );
}
/** リンクを解除する */
public void delink( StepView stepView ) throws Exception {
if ( stepView.equals( this ) ) {
throw new StepViewLinkException( "自分自身はリンク解除できません" );
}
if ( !links.contains( stepView ) ) {
throw new StepViewLinkException( "リンクされていません" );
}
links.remove( stepView );
}
/** リンク先一覧を返す */
public java.util.List getLinks() {
return links;
}
/** ポップアップメニューにメニューアイテムを追加する */
private void addMenuItem( String text, String commandName ) {
JMenuItem menuItem = new JMenuItem( text );
menuItem.setBackground( Color.green );
menuItem.setActionCommand( commandName );
menuItem.addActionListener( this );
popup.add( menuItem );
}
/** ポップアップメニュー内で選択した結果により実行する内容を決定 */
public void actionPerformed( ActionEvent e ) {
Container parent = this.getParent();
DrawingPanel drawingPanel = ( DrawingPanel ) parent;
String command = e.getActionCommand();
System.out.println( "COMMAND=" + command + " : " + this );
if ( "KILL_ITSELF".equals( command ) ) {
// 親オブジェクトからこのインスタンスを削除する
parent.remove( this );
// このメソッドを呼ばないと即時に反映されないので必ず再描画する!
parent.repaint();
// ステップマネージャの管理対象外とする
drawingPanel.disposeStepView( this );
}
if ( "LINK".equals( command ) ) {
if ( drawingPanel.getOperationMode() == Operation.Mode.DEFAULT ) {
drawingPanel.setLinkSource( this, Operation.Mode.LINK );
this.setBackground( Color.yellow );
}
}
if ( "DELINK".equals( command ) ) {
if ( drawingPanel.getOperationMode() == Operation.Mode.DEFAULT ) {
drawingPanel.setLinkSource( this, Operation.Mode.DELINK );
this.setBackground( Color.red );
}
}
}
/** 背景色を元に戻す */
public void restoreBackground() {
this.setBackground( originalBackgroundColor );
}
}
::::::::::::::
StepViewLinkException.java
::::::::::::::
/**
$Id: arrow-and-atan2.html,v 1.1 2009/06/22 16:12:04 kishi Exp kishi $
*/
public class StepViewLinkException extends Exception {
public StepViewLinkException() {
super();
}
public StepViewLinkException( String message ) {
super( message );
}
}
戻る