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

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

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

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

Swing

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

Q&A

解決済

3回答

834閲覧

Java Swing JLabelを2枚重ねて下のJLabelでもイベントを拾いたい

mipemipe

総合スコア1

Java

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

Swing

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

1グッド

0クリップ

投稿2024/07/28 14:56

編集2024/07/29 14:10

実現したいこと

JavaのSwingでGUIを作ろうとしています。
同じJPanelにJLabelを2枚。
上のラベルはパネル全体を覆っていてクリック位置にエフェクト(仮)を出します。
下のラベルはボタンです。

クリック位置にエフェクトを出しつつ、下のラベルでもMouseEventを受け取りたい。

発生している問題・分からないこと

重なった場所にマウスカーソルが入ると、描画されている上のラベルだけがイベントを拾います。
しかし可能であれば両方のラベルで同じようにイベントをハンドリングしたいです。
いい方法はないでしょうか?

該当のソースコード

Java

1package test; 2 3import java.awt.Color; 4import java.awt.Graphics; 5import java.awt.event.MouseEvent; 6import java.awt.event.MouseListener; 7 8import javax.swing.JFrame; 9import javax.swing.JLabel; 10import javax.swing.JPanel; 11 12public class Test { 13 14 public static void main(String[] args) { 15 16 JFrame window = new JFrame("test"); 17 window.setSize(300, 200); 18 window.setLocationRelativeTo(null); 19 window.setVisible(true); 20 21 JPanel panel_1 = new JPanel(); 22 panel_1.setBounds(0, 0, 300, 200); 23 panel_1.setBackground(Color.GRAY); 24 25 EffectLabel label_1 = new EffectLabel(); 26 label_1.addMouseListener(label_1); 27 label_1.setOpaque(false); 28 label_1.setBounds(0, 0, 300, 200); 29 30 ClickLabel label_2 = new ClickLabel(); 31 label_2.addMouseListener(label_2); 32 label_2.setOpaque(true); 33 label_2.setBackground(Color.RED); 34 label_2.setBounds(90, 55, 100, 50); 35 36 window.add(panel_1); 37 panel_1.add(label_1); 38 panel_1.add(label_2); 39 40 JLabelThread thread = new JLabelThread(); 41 thread.setJLabel(label_1); 42 thread.start(); 43 44 } 45} 46 47class EffectLabel extends JLabel implements MouseListener{ 48 49 private boolean click = false; 50 private int point_x, point_y; 51 private int count = 255; 52 53 @Override 54 public void mouseClicked(MouseEvent e) { 55 point_x = e.getX() - 10; 56 point_y = e.getY() - 10; 57 click = true; 58 } 59 60 @Override 61 public void mousePressed(MouseEvent e) { 62 } 63 64 @Override 65 public void mouseReleased(MouseEvent e) { 66 } 67 68 @Override 69 public void mouseEntered(MouseEvent e) { 70 } 71 72 @Override 73 public void mouseExited(MouseEvent e) { 74 } 75 76 @Override 77 protected void paintComponent(Graphics g) { 78 super.paintComponent(g); 79 80 if(click) { 81 g.setColor(new Color(255,255,255,count)); 82 g.fillRect(point_x, point_y, 20, 20); 83 count -= 1; 84 if(count < 0) { 85 click = false; 86 count = 255; 87 } 88 } 89 } 90} 91 92class ClickLabel extends JLabel implements MouseListener{ 93 94 @Override 95 public void mouseClicked(MouseEvent e) { 96 System.out.println("Click!!"); 97 } 98 99 @Override 100 public void mousePressed(MouseEvent e) { 101 } 102 @Override 103 public void mouseReleased(MouseEvent e) { 104 } 105 106 @Override 107 public void mouseEntered(MouseEvent e) { 108 } 109 110 @Override 111 public void mouseExited(MouseEvent e) { 112 } 113} 114 115class JLabelThread extends Thread{ 116 117 JLabel label = null; 118 119 public void setJLabel(JLabel l) { 120 label = l; 121 } 122 123 @Override 124 public void run() { 125 super.run(); 126 while(true) { 127 if(label != null) label.repaint();; 128 } 129 } 130}

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

使えそうな情報が見つからなかった。

補足

特になし

TN8001😄を押しています

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

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

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

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

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

jimbe

2024/07/28 19:00 編集

具体的に現在のどのようなコードで、どのような操作をした時にどのような結果(表示の変化等)となるようにしたいのかを示してください。(コピペして実行出来ると良いです。)
TN8001

2024/07/29 08:54

何のイベント(相当のもの)が欲しいのかによって、方針も変わってきそうですね。 mouseEntered mouseMoved mousePressed ・・・ 文章で全てを説明するのは大変なので、(理想の動作になっていなくても今の)ソースコードがあると他人にも話が通じやすいです。 [ヘルプ|質問するときのヒント](https://teratail.com/help/question-tips#questionTips35) 「本当にやりたいこと」の内容によっては、全く別の解決法があるかもしれません。 [XY問題 - Wikipedia](https://ja.wikipedia.org/wiki/XY%E5%95%8F%E9%A1%8C) 質問はいつでも何度でも編集できます。
mipemipe

2024/07/29 14:11

ありがとうございます。 サンプルソースを張ってみました。 こちらで、上のラベルと下のラベルの両方でマウスイベントを拾えるようにしたいです。
jimbe

2024/07/29 17:44

コードありがとうございます。改造する形で回答を追加しました。文字数ぎりぎりっぽい^^;
guest

回答3

0

ベストアンサー

「本当にやりたいこと」の内容によっては、全く別の解決法があるかもしれません。
XY問題 - Wikipedia

「本当にやりたいこと」は、下記のようなことではありませんか?

  • X(本当に解決したい課題)
    (他のコンポーネントの動作は阻害せず)クリック位置に(装飾的なあるいは目立たせるための)エフェクトを出したい。
  • Y(二次的な課題)
    JLabelを2枚重ねて下のJLabelでもイベントを拾いたい。

java

1import javax.swing.*; 2import java.awt.*; 3import java.awt.event.*; 4 5public class Sample extends JFrame { 6 public static void main(String[] args) { 7 new Sample().setVisible(true); 8 } 9 10 Sample() { 11 setDefaultCloseOperation(EXIT_ON_CLOSE); 12 setSize(400, 300); 13 setLocationRelativeTo(null); 14 setLayout(new FlowLayout()); 15 16 var label = new JLabel("Label"); 17 add(label); 18 var button = new JButton("Button"); 19 add(button); 20 add(new JCheckBox("CheckBox")); 21 add(new JTextField("TextField", 10)); 22 var textArea = new JTextArea("TextArea\n", 10, 20); 23 add(new JScrollPane(textArea)); 24 add(new JList<>(new String[]{ "aaaaaa", "bbbbbb", "cccccc" })); 25 add(new JComboBox<>(new String[]{ "aaaaaa", "bbbbbb", "cccccc" })); 26 27 label.addMouseListener(new MouseAdapter() { 28 @Override public void mouseClicked(MouseEvent e) { 29 textArea.append("Label Click\n"); 30 } 31 }); 32 button.addActionListener(e -> textArea.append("Button Click\n")); 33 34 var effectPane = new EffectPane(); 35 setGlassPane(effectPane); 36 effectPane.setVisible(true); 37 } 38} 39 40class EffectPane extends JComponent implements AWTEventListener, ActionListener { 41 private final Timer timer; 42 private Point point; 43 private int count; 44 45 public EffectPane() { 46 Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); 47 timer = new Timer(15, this); 48 } 49 50 @Override public void eventDispatched(AWTEvent event) { 51 if (event instanceof MouseEvent e && e.getID() == MouseEvent.MOUSE_CLICKED) { 52 count = 255; 53 point = SwingUtilities.convertPoint((Component) e.getSource(), e.getPoint(), this); 54 timer.start(); 55 } 56 } 57 58 @Override public void actionPerformed(ActionEvent e) { 59 count = (int) (count / 1.1); 60 if (count < 5) { 61 point = null; 62 timer.stop(); 63 } 64 repaint(); 65 } 66 67 @Override protected void paintComponent(Graphics g) { 68 super.paintComponent(g); 69 if (point == null) return; 70 g.setColor(Color.RED); 71 g.drawOval(point.x - count / 2, point.y - count / 2, count, count); 72 } 73}

AWTEventListener (Java Platform SE 8 )

How to Use Root Panes (The Java™ Tutorials > Creating a GUI With Swing > Using Swing Components)

エフェクトはポップアップ(コンボボックスやメニュー等)より上面に出ますが、ポップアップ内のクリックは拾えていません(何か手はあるかもしれませんが調べていません)
アプリ動画

投稿2024/08/03 04:59

TN8001

総合スコア9807

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

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

mipemipe

2024/08/03 05:10

ありがとうございます、参考になります。 >X(本当に解決したい課題) (他のコンポーネントの動作は阻害せず)クリック位置に(装飾的なあるいは目立たせるための)エフェクトを出したい。 そうですね、やりたいこととしてはこれです。 それを、一番上にラベルを置くことで実現しようとしていました。
TN8001

2024/08/03 06:35 編集

> そうですね、やりたいこととしてはこれです。 > それを、一番上にラベルを置くことで実現しようとしていました。 典型的なXY問題でしたね^^; そういった状況に陥ってしまうことは理解できます。 ただ(Xを聞き出そうと)こちらからいろいろ質問をすると、(詮索されていると感じるのか)ストレートに答えてくれない方が多いので、一旦リンクのみの提示で済ませました。 追記内容やコメントから、Xが分かった気がしたので新たに回答しました^^ --- ボタンのホバーが動作していることからわかるように、addAWTEventListenerはイベントを傍受するだけなのでほかに影響を与えません(握り潰すこともできるが) イベントを捏造するより自然で、この場合はより向いていると思います。 ポップアップはあまり検証していないのですが、ウィンドウ外にも出ることがあるため、そもそもが難しくほかのフレームワークでも沼りやすいです。 割り切ることをお勧めしますが、やるとなるとネイティブAPI(Win32等)が必要になったりするかもしれません(調べてないので根拠もないが^^; --- 問題が解決しましたら、質問を「解決済」にしてください。 [ヘルプ|質問を解決済みにしたい](https://teratail.com/help#resolve-question) 回答の疑問点はお気軽にコメントください。 回答の検証を急かす意図はないので、ご自身のペースでどうぞ^^
guest

0

サンプルソースを張ってみました。
こちらで、上のラベルと下のラベルの両方でマウスイベントを拾えるようにしたいです。

上のラベルでイベントを受けた時に、下のラベルに捏造したイベントを送り付けることはできます。

java

1import javax.swing.*; 2import java.awt.*; 3import java.awt.event.*; 4 5public class Test { 6 public static void main(String[] args) { 7 JFrame window = new JFrame("test"); 8 window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 9 window.setSize(300, 200); 10 window.setLocationRelativeTo(null); 11 12 JPanel panel_1 = new JPanel(null); // nullレイアウトじゃないとラベルのsetBoundsが意味ない 13 panel_1.setBackground(Color.GRAY); 14 window.add(panel_1); 15 16 EffectLabel label_1 = new EffectLabel(); 17 label_1.setBounds(0, 0, 300, 200); 18 panel_1.add(label_1); 19 20 ClickLabel label_2 = new ClickLabel("Click!!"); 21 label_2.setBounds(90, 55, 100, 50); 22 panel_1.add(label_2); 23 24 for (int i = 0; i < 5; i++) { 25 ClickLabel label = new ClickLabel("" + i); 26 label.setBounds((i % 3) * 80 + 35, (i / 3) * 80 + 35, 50, 50); 27 label.setBackground(Color.BLUE); 28 panel_1.add(label); 29 } 30 31 JLabelThread thread = new JLabelThread(label_1); 32 thread.start(); 33 34 window.setVisible(true); 35 } 36} 37 38class EffectLabel extends JLabel implements MouseListener { 39 private boolean click; 40 private int point_x, point_y; 41 private int count = 255; 42 43 EffectLabel() { 44 addMouseListener(this); 45 } 46 47 @Override protected void paintComponent(Graphics g) { 48 super.paintComponent(g); 49 50 if (click) { 51 g.setColor(new Color(255, 255, 255, count)); 52 g.fillRect(point_x, point_y, 20, 20); 53 count -= 5; 54 if (count < 0) { 55 click = false; 56 count = 255; 57 } 58 } 59 } 60 61 @Override public void mouseClicked(MouseEvent e) { 62 point_x = e.getX() - 10; 63 point_y = e.getY() - 10; 64 click = true; 65 66 // 親パネル取得 67 Container parent = getParent(); 68 69 // 親パネル基準のクリック座標に変換 70 var p = SwingUtilities.convertPoint(this, e.getPoint(), parent); 71 72 // 親パネルの子をループ(捏造する奴がほかにもいると、イベントを送りあって無限ループしそう) 73 for (Component child : parent.getComponents()) { 74 if (child == this) continue; // 自分は除外 75 76 if (child.getBounds().contains(p)) { // 範囲内かどうか 77 78 // child基準のクリック座標に変換 79 var pp = SwingUtilities.convertPoint(this, e.getPoint(), child); 80 81 // 捏造したイベントを送る 82 child.dispatchEvent(new MouseEvent(child, e.getID(), e.getWhen(), e.getModifiers(), 83 pp.x, pp.y, e.getClickCount(), e.isPopupTrigger())); 84 } 85 } 86 } 87 @Override public void mousePressed(MouseEvent e) { } 88 @Override public void mouseReleased(MouseEvent e) { } 89 @Override public void mouseEntered(MouseEvent e) { } 90 @Override public void mouseExited(MouseEvent e) { } 91} 92 93class ClickLabel extends JLabel { 94 ClickLabel(String text) { 95 addMouseListener(new MouseAdapter() { 96 @Override public void mouseClicked(MouseEvent e) { 97 System.out.println(text); 98 } 99 }); 100 setOpaque(true); 101 setBackground(Color.RED); 102 } 103} 104 105class JLabelThread extends Thread { 106 private final JLabel label; 107 108 JLabelThread(JLabel l) { label = l; } 109 110 @Override public void run() { 111 super.run(); 112 while (true) { 113 label.repaint(); 114 try { 115 Thread.sleep(1); // 多少ウェイト入れないとCPU使いすぎ 116 } catch (InterruptedException ignored) { } 117 } 118 } 119}

SwingUtilities#convertPoint (Java Platform SE 8 )
Component#dispatchEvent (Java Platform SE 8 )
MouseEvent (Java Platform SE 8 )
アプリ動画

いい方法はないでしょうか?

ただそんなに筋がいいとも思えないので、両方に同一ハンドラを登録して(それぞれの)範囲チェックするようにはできないんですかね?

投稿2024/07/29 15:08

編集2024/08/02 04:03
TN8001

総合スコア9807

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

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

mipemipe

2024/07/31 15:11

ありがとうございます。 確かに、コンポーネントの数が少なければ、この方法でもいい気がします。 参考にさせていただきます。
TN8001

2024/07/31 15:42

> 確かに、コンポーネントの数が少なければ、この方法でもいい気がします。 EffectLabelが複数あるんですか?? ClickLabel(相当のもの)はいくつあってもいいように、getComponentsでループさせたのですが。
mipemipe

2024/08/03 05:06

サンプルありがとうございます! >ClickLabel(相当のもの)はいくつあってもいいように、 いえ、ループで全てのコンポーネントを都度チェックしているので、 ClickLabelが多すぎると処理に時間がかかりそうと感じただけです。
TN8001

2024/08/03 06:32

> いえ、ループで全てのコンポーネントを都度チェックしているので、 > ClickLabelが多すぎると処理に時間がかかりそうと感じただけです。 大量にあるとそれなりに時間はかかるでしょう(大量具合にもよるが) それが許容できないほどのものかは、実際に計ってみないと何とも言えないですね。 別回答が実際にやりたいことなら、そっちのほうがいいでしょうね。
guest

0

下だけにリスナを登録すれば重なっている部分でも下が受け取ります。重なりの状態が変わるのなら、変わった時にリスナを付け替えることで出来るでしょう。
もしくは、各ラベルで受け取るのでは無くコンテナ(回答のコードでは MainPanel )が受け取って、 Z オーダーからラベルを決めて処理させるというテもあります。

もっとちゃんと(?)やるなら、 Swing のコンポーネント間でイベントがどう伝わっているのかを調べられると良いと思います。(分かり易い図を何処かで見た気がしたんですが見つかりませんでした。)

java

1import java.awt.Color; 2import java.awt.event.MouseAdapter; 3import java.awt.event.MouseEvent; 4 5import javax.swing.*; 6 7public class MainFrame extends JFrame { 8 public static void main(String[] args) { 9 SwingUtilities.invokeLater(() -> new MainFrame().setVisible(true)); 10 } 11 12 MainFrame() { 13 super("重なりイベント"); 14 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 15 16 add(new MainPanel()); 17 18 pack(); 19 setLocationRelativeTo(null); 20 } 21 22 private static class MainPanel extends JPanel { 23 MainPanel() { 24 super(null); 25 setSize(320, 320); 26 setPreferredSize(getSize()); 27 setBackground(Color.YELLOW); 28 29 addLabel("ABC", 20, 20, 200, 200, Color.GREEN, JLabel.TOP); 30 31 addLabel("123", 100, 100, 200, 200, Color.RED, JLabel.BOTTOM) 32 .addMouseListener(new LoggedMouseAdapter("123")); 33 } 34 private JLabel addLabel(String text, int x, int y, int w, int h, Color bg, int valign) { 35 JLabel label = new JLabel(text); 36 label.setBounds(x,y,w,h); 37 label.setOpaque(true); 38 label.setBackground(bg); 39 label.setVerticalAlignment(valign); 40 add(label); 41 return label; 42 } 43 } 44 45 private static class LoggedMouseAdapter extends MouseAdapter { 46 private String text; 47 LoggedMouseAdapter(String text) { 48 this.text = text; 49 } 50 @Override 51 public void mouseClicked(MouseEvent e) { 52 System.out.println(text + " clicked."); 53 } 54 @Override 55 public void mouseEntered(MouseEvent e) { 56 System.out.println(text + " entered."); 57 } 58 @Override 59 public void mouseExited(MouseEvent e) { 60 System.out.println(text + " existed."); 61 } 62 } 63}

実行時表示

123 entered. 123 existed. 123 entered. 123 clicked. 123 existed. 123 entered. 123 clicked. 123 existed.

ラベルの載っているパネルにマウスイベントを受信させて、その位置にある全ての子コンポーネントのメソッドを呼ぶようにするとこんな感じになります。
この場合、 MOUSE_ENTERED や MOUSE_EXITED は来ないのでそれが必要ならパネルが判断したりが必要になります。

java

1import java.awt.Color; 2import java.awt.Component; 3import java.awt.event.MouseEvent; 4 5import javax.swing.*; 6 7public class MainFrame extends JFrame { 8 public static void main(String[] args) { 9 SwingUtilities.invokeLater(() -> new MainFrame().setVisible(true)); 10 } 11 12 MainFrame() { 13 super("重なりイベント"); 14 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 15 16 add(new MainPanel()); 17 18 pack(); 19 setLocationRelativeTo(null); 20 } 21 22 private static class MainPanel extends JPanel { 23 MainPanel() { 24 super(null); 25 setSize(320, 320); 26 setPreferredSize(getSize()); 27 setBackground(Color.YELLOW); 28 29 add(new MyLabel("ABC", 20, 20, 200, 200, Color.GREEN, JLabel.TOP)); 30 add(new MyLabel("123", 100, 100, 200, 200, Color.RED, JLabel.BOTTOM)); 31 32 enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK); 33 } 34 35 @Override 36 protected void processMouseEvent(MouseEvent e) { 37 Component[] components = getComponents(); 38 for(Component c : components) { 39 if(c.getBounds().contains(e.getX(), e.getY()) && c instanceof MyLabel) { 40 ((MyLabel)c).receiveMouseEvent(SwingUtilities.convertMouseEvent(this, e, c)); 41 } 42 } 43 } 44 @Override 45 protected void processMouseMotionEvent(MouseEvent e) { 46 processMouseEvent(e); 47 } 48 } 49 50 private static class MyLabel extends JLabel { 51 MyLabel(String text, int x, int y, int w, int h, Color bg, int valign) { 52 super(text); 53 setBounds(x,y,w,h); 54 setOpaque(true); 55 setBackground(bg); 56 setVerticalAlignment(valign); 57 } 58 //MouseListener 等の代わりになるメソッド 59 void receiveMouseEvent(MouseEvent e) { 60 System.out.println(getText() + " receive " + e); 61 } 62 } 63}

具体的なコードを提示されたので、改造する形で作ってみました。
また、フェードアウトが危険な構造だったため ScheduledExecutorService を用いるようにし、クリック位置に表示する矩形自体をフェードアウト処理をするオブジェクトとして扱っています。
なお、 paintComponent の中で count を減らすような "状態が変わる処理" をしてはいけません。
paintComponent はアプリコードから repaint() が呼ばれた時以外でも、例えばアプリのウインドウが一部隠されてから再び表示された時でも呼ばれますので、意図しないタイミングで状態が変わる可能性があります。

java

1import java.awt.*; 2import java.awt.event.MouseEvent; 3import java.util.ArrayList; 4import java.util.List; 5import java.util.concurrent.*; 6 7import javax.swing.*; 8 9public class TestFrame extends JFrame { 10 public static void main(String[] args) { 11 SwingUtilities.invokeLater(() -> new TestFrame().setVisible(true)); 12 } 13 14 TestFrame() { 15 super("test"); 16 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 17 18 add(new MainPanel()); 19 20 pack(); 21 setLocationRelativeTo(null); 22 } 23 24 private static class MainPanel extends JPanel { 25 MainPanel() { 26 super(null); 27 setSize(300, 200); 28 setPreferredSize(getSize()); 29 setBackground(Color.GRAY); 30 31 add(new EffectLabel(0, 0, 300, 200)); 32 add(new ClickLabel(90, 55, 100, 50)); 33 34 enableEvents(MouseEvent.MOUSE_EVENT_MASK); 35 } 36 37 @Override 38 protected void processMouseEvent(MouseEvent e) { 39 Component[] components = getComponents(); 40 for(Component c : components) { 41 if(c.getBounds().contains(e.getX(), e.getY()) && c instanceof MouseEventReceiver) { 42 ((MouseEventReceiver)c).receiveMouseEvent(SwingUtilities.convertMouseEvent(this, e, c)); 43 } 44 } 45 } 46 } 47} 48 49interface MouseEventReceiver { 50 void receiveMouseEvent(MouseEvent e); 51} 52 53interface Shape { 54 void paint(Graphics g); 55} 56 57class EffectLabel extends JLabel implements MouseEventReceiver { 58 private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4); 59 private List<Shape> shapeList = new ArrayList<>(); 60 61 private class FadeoutableSquare implements Runnable, Shape { 62 private static int SIZE = 20; 63 private int x, y, count; 64 private ScheduledFuture<?> future; 65 66 FadeoutableSquare(int x, int y) { 67 this.x = x - SIZE / 2; 68 this.y = y - SIZE / 2; 69 count = 255; 70 shapeList.add(this); 71 } 72 void setScheduledFuture(ScheduledFuture<?> future) { 73 this.future = future; 74 } 75 @Override 76 public void run() { 77 repaint(); 78 SwingUtilities.invokeLater(() -> { 79 if(future == null) return; 80 if(count-- <= 0) { 81 future.cancel(false); 82 future = null; 83 shapeList.remove(this); 84 } 85 }); 86 } 87 @Override 88 public void paint(Graphics g) { 89 g.setColor(new Color(255, 255, 255, count)); 90 g.fillRect(x, y, SIZE, SIZE); 91 } 92 } 93 94 EffectLabel(int x, int y, int w, int h) { 95 super(); 96 setBounds(x, y, w, h); 97 } 98 99 @Override 100 public void receiveMouseEvent(MouseEvent e) { 101 if(e.getID() == MouseEvent.MOUSE_CLICKED) { 102 FadeoutableSquare fs = new FadeoutableSquare(e.getX(), e.getY()); 103 fs.setScheduledFuture(scheduler.scheduleAtFixedRate(fs, 1, 1, TimeUnit.MILLISECONDS)); 104 } 105 } 106 @Override 107 protected void paintComponent(Graphics g) { 108 super.paintComponent(g); 109 110 for(Shape shape : shapeList) shape.paint(g); 111 } 112} 113 114class ClickLabel extends JLabel implements MouseEventReceiver { 115 ClickLabel(int x, int y, int w, int h) { 116 super(); 117 setOpaque(true); 118 setBackground(Color.RED); 119 setBounds(x, y, w, h); 120 } 121 122 @Override 123 public void receiveMouseEvent(MouseEvent e) { 124 if(e.getID() == MouseEvent.MOUSE_CLICKED) System.out.println("Click!!"); 125 } 126}

投稿2024/07/28 20:12

編集2024/07/29 17:51
jimbe

総合スコア13168

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

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

mipemipe

2024/07/29 14:35

ありがとうございます。 やりたいこととしてはコレです。 参考にさせていただきます。
mipemipe

2024/07/31 16:27

参考にさせていただきます。 ちなみに >paintComponent の中で count を減らすような "状態が変わる処理" をしてはいけません。 これについては分かるのですが >フェードアウトが危険な構造だったため というのはどういった部分でしょうか? Threadを使うことで何かデメリットがあったのでしょうか。
jimbe

2024/07/31 17:47

>>フェードアウトが危険な構造だったため >というのはどういった部分でしょうか? >Threadを使うことで何かデメリットがあったのでしょうか。 Thread を使うことででは無く、延々と (TN8001 さんの回答コードでもコメントありますが) 何のウエイトも無く repaint を発行し続ける構造をあえて「危険」としました。 大前提としてアプリケーションはその土台となるシステムに無暗に負荷を掛けるべきではありません。 件のスレッドはフェードアウトがあっても無くても repaint し続けますが、本来ならフェードアウトする時だけあれば良い処理です。フェードアウトまでの時間も決めておかないと、速いハードでは早く遅いハードでは遅く消え、その効果が何になるのか分かりませんが一定にはならないでしょう。 回答コードでは、ラベルを矩形毎の 1 ミリ秒毎に repaint し count=255→0 で終了(スケジューラから削除)するようにすることで約 0.25 秒のフェードアウトとし、最大で同時に 4 回のクリックに対応できるようにしました。( 0.25 秒内にもっと多くクリックしそうなら最大スレッド数を増やすとか、各 count の減る・表示更新するタイミングを合わせるようにシングルスレッドでやるとか、この辺りをどうするかも仕様で変わるとは思いますが。) ついでに、 Swing は最初の setVisible(true) 以降に Swing 唯一のスレッド (EDT) 以外から Swing のコンポーネントの操作をしてはいけないことになっています。(repaint() は大丈夫です。)
mipemipe

2024/08/03 05:08

説明ありがとうございます。参考になりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問