JLabelとJLabelを結ぶ直線をJComponentとしてカプセル化する方法

このQ&Aのポイント
  • JPanel上のJComponentを繋ぐ直線を表すクラスを作成する方法について教えてください。
  • 線をオブジェクトとしてカプセル化するための効果的な方法はありますか?
  • ピュアJavaのライブラリでこの機能を実装するためのヒントを教えてください。
回答を見る
  • ベストアンサー

JLabelとJLabelを結ぶ直線をJComponentとしてカプセル化

別にJLabelでなくてもよいのですが、JPanel上のJComponentを繋ぐ直線を表すクラスをJComponentを継承したクラスとして扱いたいのですが、どのようにすればよいでしょうか? というのもやりたいことは、JPanel上のJComponentを移動させたときにそれを繋ぐ線も動くとともに、その線上で発生するイベント(たとえばMouseEvent)を処理したいからです。 現段階ではJPanelに直に線を描画し、JPanelと同じ大きさのオフスクリーンに各線の識別IDを色とした線を描画することで、カーソルの位置から当たり判定をするという荒い方法で対処しています。 なんとかこの線をオブジェクととしてカプセル化したいのですが、なにかよい方法はないでしょうか? ピュアJavaで実装したいため、SWT+EMF(+Draw2D)は考えていません。 またそのようなピュアJavaのライブラリがあれば教えてください。

  • Java
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • HarukaV49
  • ベストアンサー率53% (48/89)
回答No.2

>OriginalPanelに実装したMouseListenerやMouseMotionListenerの中で、 >カーソルがどのOriginalLine上にあるか判定しなければいけないという >ことでしょうか。 いかにも面倒で処理が重そうに感じるという意味での疑問でしょうか? 私は、何の疑問も持たずに以前そのように実装した経験を持ちます(^^; 別の意味での質問でしたら、再質問をお願いいたします。 他の方法があるとすれば、私としても知りたい限りです。 なお私の場合、具体的な当たり判定には、マウス周りの(微小)正方形領域と OriginalComponentをintersectsで判定していたと思います。 containsを使って、思い通りに判定できていれば問題ありませんが。

unchikun
質問者

お礼

> いかにも面倒で処理が重そうに感じるという意味での疑問でしょうか? おっしゃる通り、リスナの全てのメソッド実装部で、forループを回すのが面倒だな~と感じたのと、追加する部品が増えると重くなるのでは、と感じたためです。 心配することでもないようなので、気にしないようにします。 > containsを使って、思い通りに判定できていれば問題ありませんが。 直線の判定はうまくいかなかったので、おっしゃる通りintersectsで判定するようにしました。 あとは、mouseEnteredやmouseExitedをどうエミュレートしようか迷っているところですが、教えていただいた方法も無事理解でき、実装できたので今回はここまでにしたいと思います。 大変助かりました。 ご回答ありがとうございました。

その他の回答 (1)

  • HarukaV49
  • ベストアンサー率53% (48/89)
回答No.1

JPanel上に描画した直線をJComponentのサブクラスとする発想は 少し無理があると思います。 代替案として、まずShapeインターフェースを実装したOriginalLine クラスを実装します。そこに、座標、色、結合しているJComponentの 情報等を持たせます。 (今回の場合には、これを描画するパネルも独自に作成するため  Shapeインターフェースを実装しなくても大丈夫ですが) このクラスに、addMouseIntersectListener(MouseIntersectListener l)等の オリジナルのメソッドを実装して、MouseIntersectListenerクラスを 描画したパネルのMouseMotionListenerから呼び出されるようなListenerクラスと Eventクラスを作ります。 そして、JPanelを継承したOriginalPanelクラスを作成して、 add(OriginalLine line), remove(OriginalLine line)メソッドを 実装して、OriginalLineをArrayListに格納しておいて、paint(Grarhics g) をオーバーライドし、OriginalLineを描画するようにします。 このようにすることで、JComponent同士を結ぶ直線は、addメソッドで 追加できますし、イベントを生成することも出来るようになるため、 JComponentと違わない、使いやすさを実現できるでしょう。 非常に大雑把な説明ですが、概略は以上です。 具不明な点がありましたら、追加質問をお願いいたします。

unchikun
質問者

お礼

ご回答ありがとうございます。 なるほど、大体の流れはつかむことが出来ました。 結局Shapeのメソッドは実装しました。 というのも後々あたり判定をする際に必要になってくると感じたためです。 しかし全て1から実装するのは面倒だったので、OriginalLineの内部にGeneralPathを持たせて処理を委譲するという形にしました。 また、OriginalLineに、OriginalPanelに描画するオリジナルのコンポーネントを表すクラス abstract class OriginalComponent implements Shape {  List<MouseIntersectListener> listener;  ...  abstract void paint(Graphics g);  addMouseIntersectListener(MouseIntersectListener l) {   listener.add(l);  }  public boolean contains(double x, double y){} ... } を継承させて、描画処理を実装し class OriginalPanel extends JPanel {  List<OriginalComponent> components;  void paint(Graphics g) {   for (OriginalComponent c : components)    c.paint(g);  } } みたいな感じで描画することにしました。 1つ疑問なのですが、パネル上で発生したイベントを、OriginalLine上で発生したイベントとして扱うためには(どのOriginalLineに登録されたリスナにイベントを渡すか)は、OriginalPanelに実装したMouseListenerやMouseMotionListenerの中で、カーソルがどのOriginalLine上にあるか判定しなければいけないということでしょうか。たとえば、 public void OriginalPanel#mouseClicked(MouseEvent me) {  Point p = me.getPoint();  <オリジナルイベントオブジェクト生成>  for (OriginalComponent c : components) {   // 当たり判定   if (c.contaions((double) p.x, (double)p.y) {    for(MouseIntersectListener l : c.listener) {     l.mouseClicked(オリジナルイベントオブジェクト);    }    break;//1つのコンポーネントに対してイベントを処理したら終わり   }  } }

関連するQ&A

  • ボタンクリック後パネルを再描画repaintしたい

    ボタンをクリック後にstaticで保持していた値にプラス1して その値をパネルに再描画したいと思っています。 下記のプログラムだとボタンをクリックすると (<1<2<3<4)となって画像と数字が増えてしまいます 行いたいのは数字の部分だけが再描画されて カウントされて<3と表示されるだけになってもらいたい クラス1つ目 import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.event.MouseEvent; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class Sample extends JFrame{ static int value=1; JPanel work = new JPanel(); public static void main(String[] args) { Sample frame = new Sample(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(100, 200, 200, 100); frame.add(frame.createPanel(), BorderLayout.LINE_END); frame.setVisible(true); } public JPanel createPanel() { ImageIcon icon = new ImageIcon("./img/left.gif"); JLabel label = new JLabel(); Cursor c = new Cursor(Cursor.HAND_CURSOR); label.setCursor(c); label.setIcon(icon); JLabel strLabel = new JLabel(); String str = Integer.toString(value); strLabel.setText(str); work.add(label); work.add(strLabel); label.addMouseListener(new myListener()); return work; } class myListener extends MouseAdapter{ public void mouseClicked(MouseEvent e){ System.out.print(Sample.value++); createPanel().repaint(); setVisible(true); } } } クラス2つ目 import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class MouseAdapter implements MouseListener{ public void mouseClicked(MouseEvent e){} public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mousePressed(MouseEvent e){} public void mouseReleased(MouseEvent e){} }

    • ベストアンサー
    • Java
  • JPanelで宣言したメソッドについて

    JPanelを継承したクラスで、引数をもらってその引数を表示するメソッドを作成します。そして別のJFrameを継承したクラスの中で、さきほど作成したメソッドを利用したいのですが、どうすればできるのでしょうか?そもそもこのやり方できちんと表示されるのでしょうか? ぜひともご教授のほど宜しくお願いします。 以下はプログラムになります。 import java.awt.*; import java.awt.event.*; import javax.swing.*; class Ptest extends JPanel { public void paintComponent(Graphics g) { super.paintComponent(g); g.drawString("よろしく", 50, 50); } public void draw(String s) { Graphics g = getGraphics(); g.drawString(s, 100, 100); } } class Ftest extends JFrame { JLabel jlb; public Ftest() { setSize(350, 300); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); Container c = getContentPane(); Ptest p = new Ptest(); p.draw("yoroshiku"); c.add(p); p.setLayout(null); jlb = new JLabel("frame"); p.add(jlb); jlb.setBounds(70, 70, 50, 50); } } public class Test1 { public static void main(String[] args) { JFrame w = new Ftest(); w.show(); } }

    • ベストアンサー
    • Java
  • 音ファイルの配置場所を変更したい

    イメージラベルをクリックしたらクリック音が鳴るように プログラムしたいです。下記のプログラムでクリック後 クリック音が鳴るようになったのですが音ファイル(sound.wav) の格納ディレクトリがスマートではないと考えています。 というのもクラスファイルが置いてある場所に音ファイルがあるからです。 ですから、この音ファイルをbeepというフォルダを作ってその中に sound.wavファイルを置きたいと考えています。 添付画像に表示されているようなディレクトリに音ファイルを配置したいのです。 ディレクトリをどうプログラムしてもファイルがありませんというエラーが 出てしまいます。 どうすれば、音ファイルのディレクトリを変更できるでしょうか。 教えて下さい。 package audio; import java.applet.Applet; import java.applet.AudioClip; import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class ClickSound extends JFrame implements MouseListener{ AudioClip pong; public static void main(String[] args) { ClickSound frame = new ClickSound(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setBounds(100, 200, 350, 180); frame.setVisible(true); } public ClickSound() { JPanel panel = new JPanel(); panel.setCursor(new Cursor(Cursor.WAIT_CURSOR)); ImageIcon icon = new ImageIcon("./img/left.gif"); JLabel label = new JLabel(); Cursor c = new Cursor(Cursor.HAND_CURSOR); label.setCursor(c); label.setIcon(icon); panel.add(label); java.awt.Toolkit.getDefaultToolkit().beep(); URL soundUrl = getClass().getResource("./sound.wav"); pong = Applet.newAudioClip(soundUrl); label.addMouseListener(this); this.add(panel, BorderLayout.LINE_END); } public void mouseClicked(MouseEvent e) { // 効果音を鳴らす pong.play(); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } }

    • ベストアンサー
    • Java
  • Java 15パズルを作ったのですが・・・

    こんにちは。 趣味でプログラミングをしているものです。 さっそくですが質問させていただきます。 Javaで15パズルを、eclipseをしろうとなりに使って 作ってみたのですが、 以下のURLにソースコードの全文を 載せてありますので、 (判定、完成させたときの何らかのイベントは  まだできたいない途中のものですが・・・) http://www.eonet.ne.jp/~mycabinet よろしければ、500*500のピース用、背景用の jpg画像を用意していただき、 imageという名前のフォルダに格納して 実行して動作を試していただきたいのですが・・・ その上で、いくつか質問させていただきたいのです。 (1) JPanelを継承したクラスにswing のTimerクラスを 持たせ、ピースの移動をアニメーションのように 描画させようとしたのですが、 動くことは動くのですが、 簡単に言えばダブルバッファリングが必要なように 描画されてしまいます。 (2) BlankPieceクラスの描画は スーパークラスの抽象メソッドを オーバーライドして何もしないように すれば、背景の画像が描画される、 と思ったのですが、 グレーの通常のパネルのようなものが 描画されてしまいます。 以上の点をどのように修正すれば よいのでしょうか? また、修正できたとして、 それをアプレットにするには、 どのようにすればよいのでしょうか? ご存知の方よろしければ、教えていただけないでしょうか? よろしくお願いします。

    • ベストアンサー
    • Java
  • 【java】座標の値をテキストファイルに出力

    javaを勉強中の者です。 座標の値をクリックした際にテキストファイルに出力したいのですが、どうしてもうまくできません。 調べてはいるのですが、わかりませんでした。 javaに詳しい方がいらっしゃれば、ご教示ください。 import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; public class clickpoint extends JFrame implements MouseMotionListener, MouseListener { JLabel label; JPanel panel; public static void main(String args[]) { clickpoint MF = new clickpoint(); MF.setSize(300, 320); MF.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); }; }); MF.setTitle("Click Point"); MF.setVisible(true); }; clickpoint() { panel = new JPanel(); panel.addMouseMotionListener(this); panel.setBackground(Color.green); label = new JLabel("座標を指定"); getContentPane().add(panel, BorderLayout.CENTER); getContentPane().add(label, BorderLayout.PAGE_END); } public void mouseMoved(MouseEvent e) { Point point = e.getPoint(); label.setText("x:" + point.x + ",y:" + point.y); } public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mousePressed(MouseEvent e){} public void mouseReleased(MouseEvent e){} public void mouseDragged(MouseEvent e) {} public void mouseClicked(MouseEvent ec) { try { File OF = new File("d:\\zahyou.txt"); FileWriter FW = new FileWriter(OF, true); FW.write(MakeData(ec.getX(), ec.getY())); FW.close(); } catch (Exception ex) { System.out.println(ex.toString()); System.exit(0); }; }; String MakeData(int x, int y) { String LS = System.getProperty("line.separator"); StringBuffer s = new StringBuffer(); s.append(x * 100 / getWidth() + ",90,0,"); s.append(y * 100 / getHeight()); s.append(LS); return(s.toString()); } }

    • ベストアンサー
    • Java
  • MouseEventのつけ方

    MouseEventのMouseEneterdに関することなのですが、 扇形をいくつか合わせて円を描画する、いわゆるパイメニューみたいなものを作成するときに、 各パイ上にマウスポインタがきた時に選択されたことがわかるように色を変えたりしたいのですが、 四角形ではなく扇形なので座標指定方法がよくわかりません。 public void paint(Graphics g) { Graphics2D g2 = (Graphics2D)g; g2.setColor(Color.BLACK); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.draw(new Arc2D.Double(100,100,200,200,0,120,Arc2D.PIE)); g2.draw(new Arc2D.Double(100,100,200,200,120,120,Arc2D.PIE)); g2.draw(new Arc2D.Double(100,100,200,200,240,120,Arc2D.PIE)); }}; どのようにしたらうまく描画できるのでしょうか。 ちなみにプログラム全体は大きなウィンドウ(JFrame)を表示しその一部分にこの円を描画しています。JDesktopPane上で実装しているので、実際はJPanelにこの円を描画してパネルを貼り付けています。 いろいろ調べてみたのですが、よくわかりません。 もっと他にいい描画方法等があればそちらも教えていただけると幸いです。 よろしくお願いします。

    • ベストアンサー
    • Java
  • Java JFrameにJPanelを・・・

    こんにちは。趣味でプログラミングをしているものです。 さっそくですが、質問させていただきます。 Java で電卓を作っているのですが、 文具店で1000円くらいで販売している電卓を再現したいのですが、 いろいろなボタンの操作はなんとなくわかってきたのですが、 電卓のGUIについて質問させていただきます。 JFrame を継承したクラスに背景の画像を描画し その上に、計算の経過、結果を表示するJPanelを 継承したクラスのインスタンスを 特定の座標に配置したいのですが、 うまくいきません。 以下に自分の作ったコードを載せますので、 どこが悪いのか、教えていただけないでしょうか。 よろしくお願いします。 package test01_frame; import java.awt.*; import javax.swing.*; public class TestFrame extends JFrame { Image bgimage; JPanel jp01; TestFrame() { super(); setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); setSize( 384, 576 ); setLocationRelativeTo( null ); bgimage = new ImageIcon( "images/image01.jpg").getImage(); repaint(); //コメントアウトした部分がわからない箇所です。 //jp01 = new JPanel(); //jp01.setPreferredSize( new Dimension( 360, 50 )); //jp01.setBackground(Color.RED); //add( jp01 ); //jp01.setLocation( new Point( 10, 30 )); setVisible( true ); } public void update( Graphics g ) { paint( g ); } public void paint( Graphics g ) { g.drawImage( bgimage, 0, 0, null ); } /** * @param args */ public static void main(String[] args) { // TODO 自動生成されたメソッド・スタブ new TestFrame(); } }

    • ベストアンサー
    • Java
  • クラスメソッドのみのクラスのオブジェクト生成は不可??

    あるテキストのjavaの問題です。 public class Draw{   static void pixel(int x,int y){     /*座標(x、y)に点を描画*/   }   static void line(int x1,int y1,int x2,int y2){     /*座標(x1、y1)~(x2、y2)に線を引く*/   } } で、これを実行するための以下のようなクラス public class TestDraw{ <ここに入力> } という問題なのですが2つまでは絞れたのですが、 (1) public static void main(String args[]){   Draw d = new Draw().line(10,10,20,30); } ↑× (2) public static void main(String args[]){   Draw.line(10,10,20,30); } ↑○ (2)はlineメソッドがstaticメソッドだからオブジェクト生成しなくても良い、ということなんですが (1)も正解のような気がするのですが・・・ 解説によると「lineはvoidなのでnew Draw().line(10,10,20,30);とすれば正解、とあります。 どうもいまいち理解できません。 クラスメソッドはオブジェクト生成しなくとも良い→オブジェクト生成できない ということなのでしょうか? それからちなみに、public classって2つ記述できないんではありませんでしたか?

    • ベストアンサー
    • Java
  • javaでgraphicsの描画の件

    今日は javaでgraphicsの描画を行っていますが、CENTERのペインには、描画できますが、 それ以外のペイン(NORTH,WEST、EAST,、SOUTH)には、描画できないように思います。 Q1)この件について、コメント頂けますと大変助かります。 下記に、ソースコードを添付いたします。 =================== package pkg; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.Line2D; import javax.swing.JFrame; import javax.swing.JPanel; public class SampleApp extends JFrame { public SampleApp(){ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setSize(600, 300); this.add(new GPanel(), BorderLayout.WEST); this.add(new GPanel(), BorderLayout.CENTER); } public static void main(String[] args) { new SampleApp().setVisible(true); } } class GPanel extends JPanel { @Override public void paintComponent(Graphics g) { super.paintComponent(g); // int w = this.getWidth(); // int h = this.getHeight(); int w=200; int h=200; g.setColor(Color.RED); g.fillOval(0, 0, w/2, h/2); Graphics2D g2 = (Graphics2D)g; g2.draw(new Line2D.Double(40, 40, w,h)); g.setColor(Color.BLUE); g.setFont(new Font("Serif", Font.BOLD, 36)); g.drawString("Graphics draw!", 10, h - 50); // g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.draw(new Line2D.Double(30.0d, 50.0d, 180.0d, 140.0d)); g2.setPaint(Color.PINK); BasicStroke wideStroke = new BasicStroke(8.0f); g2.setStroke(wideStroke); g2.draw(new Line2D.Double(30.0d, 120.0d, 250.0d, 70.0d)); } }

    • ベストアンサー
    • Java
  • JPanelの切り替えと再描画

    ContainerにJPanelをaddし、ボタンを押すことで現在addされているJPanelとは違うJPanelを生成し、再描画させようとしているのですが、うまくいかないため、質問致しました。 -- src --- public class Test extends JFrame implements ActionListener {   Container container;   JPanel panel;   JButton btn;      public Test() {     container = getContentPane();     container.setLayout(new BorderLayout());     // ボタン用パネル     JPanel btnp = new JPanel();     btnp.setLayout(new FlowLayout());     container.add(btnp, BorderLayout.NORTH);          btn = new JButton("aaa");     btn.addActionListener(this);     btnp.add(btn);          // 対象のパネル     panel = new JPanel();       (略)panelの設定     container.add(panel, BorderLayout.CENTER);     setVisible(true);     setBounds(50, 50, 300, 300);     setDefaultCloseOperation(EXIT_ON_CLOSE);   }      public void actionPerformed(ActionEvent e) {     if (e.getSource() == btn) {       container.remove(1);       panel = new JPanel();  // 本来はJPanelを継承したクラスをnewしています       container .add(panel);       repaint();       // ※     }   }      public static void main(String args[]) {     Test t = new Test();   } } ※の箇所をcontainer.repaint() にしたり、paintImmediaely() にしたり出来そうな事を色々試したつもりではいるのですが、うまくいきません… ボタン押下後に、ウィンドウの枠をクリックすると描画されるのですが、いまいちよくわかりません… なにか分かる方いらっしゃいましたらご教授願います。

専門家に質問してみよう