質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

Q&A

解決済

1回答

315閲覧

paintComponent で書いている図形をクリックした時だけ mouseClicked() を反応させたい

ikigamikita

総合スコア8

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Swing

SwingはJavaに標準で付属するグラフィック関連のクラスライブラリを指します。

Eclipse

Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

0グッド

1クリップ

投稿2024/02/15 01:00

編集2024/02/15 04:26

実現したいこと

CirclePanelというJPanelを継承したクラスがあり、その中で作っている図形をクリックした時だけmouseClicked()を反応させたいのですが、どこをクリックしてもmouseClicked()が反応します。どうすれば「特定のpaintComponent(Graphics g)」だけを指定してmouseClicked()メソッドが反応するようになるのかどなたか教えてください。よろしくお願いします。

発生している問題・エラーメッセージ

なし

該当のソースコード

java

1 2 3import java.awt.Color; 4import java.awt.Graphics; 5import java.awt.Graphics2D; 6import java.awt.event.MouseEvent; 7import java.awt.event.MouseListener; 8import java.awt.geom.Ellipse2D; 9 10import javax.swing.JFrame; 11import javax.swing.JLabel; 12import javax.swing.JPanel; 13import javax.swing.JSlider; 14import javax.swing.event.ChangeEvent; 15import javax.swing.event.ChangeListener; 16 17 18public class TestFrame extends JFrame implements ChangeListener,MouseListener { 19 public static void main(String[] args) { 20 new TestFrame().setVisible(true); 21 } 22 23 private JSlider slider; 24 private JLabel label; 25 private CirclePanel circlePanel; //stateChanged メソッドで使うのでフィールド化 26 27 TestFrame() { 28 super("Swingサンプル(円の描画)"); 29 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30 setSize(800, 800); 31 32 circlePanel = new CirclePanel(); 33 circlePanel.addMouseListener(this); 34 setContentPane(circlePanel); 35 36 label = new JLabel("test"); 37 label.setBounds(300, 10, 100, 100); 38 add(label); 39 40 JLabel label2 = new JLabel("テスト"); 41 label2.setBounds(300, 500, 100, 100); 42 add(label2); 43 44 slider = new JSlider(50, 150, 100); //最小値, 最大値, 初期値 45 slider.addChangeListener(this); 46 JPanel p = new JPanel(); 47 p.add(slider); 48 p.setBounds(300, 300, 200, 50); //見易いようにちょっと大きく 49 add(p); 50 } 51 52 public void stateChanged(ChangeEvent e) { 53 label.setText("値:" + slider.getValue()); 54 int value = slider.getValue(); 55 circlePanel.setDiameter(value); //直径をスライダーの値に変更 56 } 57 58 59 private static class CirclePanel extends JPanel { 60 private final int X = 350, Y = 250; //円の中心 61 private int diameterOfCircle = 100; //円の直径 62 63 CirclePanel() { 64 super(null); //レイアウトマネージャ無し 65 setBackground(Color.WHITE); //背景色 66 } 67 68 /** 69 * 円の直径を設定する 70 * @param diameter 直径 [px] 71 */ 72 void setDiameter(int diameter) { 73 this.diameterOfCircle = diameter; 74 repaint(); //再描画依頼(後に Swing が paintComponent を呼んでくれる) 75 } 76 77 @Override 78 protected void paintComponent(Graphics g) { 79 super.paintComponent(g); 80 81 Graphics2D g2 = (Graphics2D) g; 82 g2.setColor(Color.BLUE); 83 Ellipse2D ellipse = new Ellipse2D.Double(X-diameterOfCircle/2, Y-diameterOfCircle/2, diameterOfCircle, diameterOfCircle); 84 g2.fill(ellipse); 85 } 86 } 87 88 89@Override 90public void mouseClicked(MouseEvent e) { 91 // TODO 自動生成されたメソッド・スタブ 92 System.out.println("合計="); 93 94} 95 96@Override 97public void mousePressed(MouseEvent e) { 98 // TODO 自動生成されたメソッド・スタブ 99 100} 101 102@Override 103public void mouseReleased(MouseEvent e) { 104 // TODO 自動生成されたメソッド・スタブ 105 106} 107 108@Override 109public void mouseEntered(MouseEvent e) { 110 // TODO 自動生成されたメソッド・スタブ 111 112} 113 114@Override 115public void mouseExited(MouseEvent e) { 116 // TODO 自動生成されたメソッド・スタブ 117 118} 119}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2024/02/15 04:29 編集

>paintComponent(Graphics g)を個別的にクリック 書き方の問題だけかもしれませんが念のため。 paintComponent は常にコンポーネントの表示域全体を書いていますので、『個別』というものはありません。 「paintComponent で書いている図形をクリックした時だけ mouseClicked() を反応させたい」という方がより合っていると思います。
ikigamikita

2024/02/15 04:26

コメントありがとうございます。質問を修正したのでご確認よろしくお願いいたします。
jimbe

2024/02/15 04:29

編集有難う御座います。
guest

回答1

0

ベストアンサー

MouseListener はコンポーネントに登録するものなので、その一部で反応させたいなら自分でクリックした座標から図形内かを調べてクリック時の動作をするかしないか判断する必要があります。

最終的に図形クリック時にどのような動作をさせるのかによって作りを考える必要がありますが、取り合えず単に何か表示して確認する感じなら、円のクリック時の処理も CirclePanel に任せる形が簡単です。

以下は MouseListener のアダプタ版である MouseAdapter を継承したクラスを CirclePanel 内で定義し、 paintComponent で作成した円とクリックされた座標を比較して標準出力に座標と図形内/外を表示しています。

java

1import java.awt.*; 2import java.awt.event.MouseAdapter; 3import java.awt.event.MouseEvent; 4import java.awt.geom.Ellipse2D; 5 6import javax.swing.*; 7import javax.swing.event.ChangeEvent; 8import javax.swing.event.ChangeListener; 9 10public class TestFrame extends JFrame implements ChangeListener { 11 public static void main(String[] args) { 12 new TestFrame().setVisible(true); 13 } 14 15 private JSlider slider; 16 private JLabel label; 17 private CirclePanel circlePanel; //stateChanged メソッドで使うのでフィールド化 18 19 TestFrame() { 20 super("Swingサンプル(円の描画)"); 21 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 22 setSize(800, 800); 23 24 circlePanel = new CirclePanel(); 25 26 setContentPane(circlePanel); 27 28 label = new JLabel("test"); 29 label.setBounds(300, 10, 100, 100); 30 add(label); 31 32 JLabel label2 = new JLabel("テスト"); 33 label2.setBounds(300, 500, 100, 100); 34 add(label2); 35 36 slider = new JSlider(50, 150, 100); //最小値, 最大値, 初期値 37 slider.addChangeListener(this); 38 JPanel p = new JPanel(); 39 p.add(slider); 40 p.setBounds(300, 300, 200, 50); //見易いようにちょっと大きく 41 add(p); 42 } 43 44 public void stateChanged(ChangeEvent e) { 45 label.setText("値:" + slider.getValue()); 46 int value = slider.getValue(); 47 circlePanel.setDiameter(value); //直径をスライダーの値に変更 48 } 49 50 private static class CirclePanel extends JPanel { 51 private final int X = 350, Y = 250; //円の中心 52 private int diameterOfCircle = 100; //円の直径 53 private Ellipse2D ellipse; //EllipseClickListener で使用する為にフィールド化 54 55 //円の範囲に反応するクラス 56 private class EllipseClickListener extends MouseAdapter { 57 @Override 58 public void mouseClicked(MouseEvent e) { 59 if(ellipse.contains(e.getPoint())) { //クリック位置が円に含まれるなら 60 System.out.println(e.getPoint() + "=図形内"); 61 } else { 62 System.out.println(e.getPoint() + "=図形外"); 63 } 64 } 65 } 66 67 CirclePanel() { 68 super(null); //レイアウトマネージャ無し 69 setBackground(Color.WHITE); //背景色 70 addMouseListener(new EllipseClickListener()); 71 } 72 73 /** 74 * 円の直径を設定する 75 * @param diameter 直径 [px] 76 */ 77 void setDiameter(int diameter) { 78 this.diameterOfCircle = diameter; 79 repaint(); //再描画依頼(後に Swing が paintComponent を呼んでくれる) 80 } 81 82 @Override 83 protected void paintComponent(Graphics g) { 84 super.paintComponent(g); 85 86 Graphics2D g2 = (Graphics2D) g; 87 g2.setColor(Color.BLUE); 88 ellipse = new Ellipse2D.Double(X - diameterOfCircle / 2, Y - diameterOfCircle / 2, diameterOfCircle, diameterOfCircle); 89 g2.fill(ellipse); 90 } 91 } 92}

円のクリックで CirclePanel の外で何かしたい場合、例えばクリックが円の中なのか外なのかを label2 に表示するような場合は、 MouseListener のように「何かが起きたら特定のメソッドを呼んでくれる」構造を CirclePanel に作る感じにすると、 Swing の標準的なコンポーネントと似て(慣れている向きには)分かり易いです。
ちょっとコードが増えてきたので主に追加変更点のみの説明になりますが、 CirclePanel 内に interface を定義して、その型のフィールドと設定メソッドも作ります。(以下の 2~13 行目)

java

1 private static class CirclePanel extends JPanel { 2 interface CircleClickListener { 3 void onClick(TestFrame.CirclePanel circlePanel, boolean contains); 4 } 5 private CircleClickListener circleClickListener = null; 6 7 /** 8 * CircleClickListener を登録する 9 * @param listener 10 */ 11 void setCircleClickListener(CircleClickListener listener) { 12 this.circleClickListener = listener; 13 }

回答で追加した EllipseClickListener クラスの mouseClicked メソッドの最後に、 circleClickListener が設定されていたら onClick メソッドを呼ぶ処理を追加します。(以下の 10 行目)

java

1 //円の範囲に反応するクラス 2 private class EllipseClickListener extends MouseAdapter { 3 @Override 4 public void mouseClicked(MouseEvent e) { 5 if(ellipse.contains(e.getPoint())) { //クリック位置が円に含まれるなら 6 System.out.println(e.getPoint() + "=図形内"); 7 } else { 8 System.out.println(e.getPoint() + "=図形外"); 9 } 10 if(circleClickListener != null) circleClickListener.onClick(CirclePanel.this, ellipse.contains(e.getPoint())); //リスナを実行 11 } 12 }

これで CirclePanel 側は準備完了です。
後は TestFrame のコンストラクタで label2 を定義している後辺りで (以下の 5~15 行目)

java

1 JLabel label2 = new JLabel("テスト"); 2 label2.setBounds(300, 500, 100, 100); 3 add(label2); 4 5 //円がクリックされたら実行するものを設定 6 circlePanel.setCircleClickListener(new CirclePanel.CircleClickListener() { //無名クラスとして定義・設定 7 @Override 8 public void onClick(CirclePanel circlePanel, boolean contains) { 9 if(contains) { 10 label2.setText("内"); 11 } else { 12 label2.setText("外"); 13 } 14 } 15 });

とすると、 CirclePanel をクリックする度に label2 にも内/外と表示されるようになります。

最後の「無名クラス」というのが慣れていないかもしれません。これを利用するとクラスを別途定義したり変数をフィールド化したりしなくても済む等で良く使われます。
Google検索: java swing 無名クラス
Javaコード入門 TOP > 継承、インターフェイス > 無名クラスを定義する

slider に設定している ChangeListener も無名クラスを利用すると label 等をフィールドにする必要が無くなったりします。

投稿2024/02/15 04:27

編集2024/02/15 17:37
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikigamikita

2024/02/15 05:07

回答ありがとうございます。 試したところ問題が解決しました! ベストアンサーに選ばせていただきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問