回答編集履歴

4

追記

2024/07/29 17:51

投稿

jimbe
jimbe

スコア13168

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

3

サンプルを改造する形のコードを追加

2024/07/29 17:42

投稿

jimbe
jimbe

スコア13168

test CHANGED
@@ -147,3 +147,136 @@
147
147
  }
148
148
  }
149
149
  ```
150
+
151
+ ---
152
+
153
+ 具体的なコードを提示されたので、改造する形で作ってみました。
154
+ また、フェードアウトが危険な構造だったため ScheduledExecutorService を用いるようにし、クリック位置に表示する矩形自体をフェードアウト処理をするオブジェクトとして扱っています。
155
+ ```java
156
+ import java.awt.*;
157
+ import java.awt.event.MouseEvent;
158
+ import java.util.ArrayList;
159
+ import java.util.List;
160
+ import java.util.concurrent.*;
161
+
162
+ import javax.swing.*;
163
+
164
+ public class TestFrame extends JFrame {
165
+ public static void main(String[] args) {
166
+ SwingUtilities.invokeLater(() -> new TestFrame().setVisible(true));
167
+ }
168
+
169
+ TestFrame() {
170
+ super("test");
171
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
172
+
173
+ add(new MainPanel());
174
+
175
+ pack();
176
+ setLocationRelativeTo(null);
177
+ }
178
+
179
+ private static class MainPanel extends JPanel {
180
+ MainPanel() {
181
+ super(null);
182
+ setSize(300, 200);
183
+ setPreferredSize(getSize());
184
+ setBackground(Color.GRAY);
185
+
186
+ add(new EffectLabel(0, 0, 300, 200));
187
+ add(new ClickLabel(90, 55, 100, 50));
188
+
189
+ enableEvents(MouseEvent.MOUSE_EVENT_MASK);
190
+ }
191
+
192
+ @Override
193
+ protected void processMouseEvent(MouseEvent e) {
194
+ Component[] components = getComponents();
195
+ for(Component c : components) {
196
+ if(c.getBounds().contains(e.getX(), e.getY()) && c instanceof MouseEventReceiver) {
197
+ ((MouseEventReceiver)c).receiveMouseEvent(SwingUtilities.convertMouseEvent(this, e, c));
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+
204
+ interface MouseEventReceiver {
205
+ void receiveMouseEvent(MouseEvent e);
206
+ }
207
+
208
+ interface Shape {
209
+ void paint(Graphics g);
210
+ }
211
+
212
+ class EffectLabel extends JLabel implements MouseEventReceiver {
213
+ private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);
214
+ private List<Shape> shapeList = new ArrayList<>();
215
+
216
+ private class FadeoutableSquare implements Runnable, Shape {
217
+ private static int SIZE = 20;
218
+ private int x, y, count;
219
+ private ScheduledFuture<?> future;
220
+
221
+ FadeoutableSquare(int x, int y) {
222
+ this.x = x - SIZE / 2;
223
+ this.y = y - SIZE / 2;
224
+ count = 255;
225
+ shapeList.add(this);
226
+ }
227
+ void setScheduledFuture(ScheduledFuture<?> future) {
228
+ this.future = future;
229
+ }
230
+ @Override
231
+ public void run() {
232
+ repaint();
233
+ SwingUtilities.invokeLater(() -> {
234
+ if(future == null) return;
235
+ if(count-- <= 0) {
236
+ future.cancel(false);
237
+ future = null;
238
+ shapeList.remove(this);
239
+ }
240
+ });
241
+ }
242
+ @Override
243
+ public void paint(Graphics g) {
244
+ g.setColor(new Color(255, 255, 255, count));
245
+ g.fillRect(x, y, SIZE, SIZE);
246
+ }
247
+ }
248
+
249
+ EffectLabel(int x, int y, int w, int h) {
250
+ super();
251
+ setBounds(x, y, w, h);
252
+ }
253
+
254
+ @Override
255
+ public void receiveMouseEvent(MouseEvent e) {
256
+ if(e.getID() == MouseEvent.MOUSE_CLICKED) {
257
+ FadeoutableSquare fs = new FadeoutableSquare(e.getX(), e.getY());
258
+ fs.setScheduledFuture(scheduler.scheduleAtFixedRate(fs, 1, 1, TimeUnit.MILLISECONDS));
259
+ }
260
+ }
261
+ @Override
262
+ protected void paintComponent(Graphics g) {
263
+ super.paintComponent(g);
264
+
265
+ for(Shape shape : shapeList) shape.paint(g);
266
+ }
267
+ }
268
+
269
+ class ClickLabel extends JLabel implements MouseEventReceiver {
270
+ ClickLabel(int x, int y, int w, int h) {
271
+ super();
272
+ setOpaque(true);
273
+ setBackground(Color.RED);
274
+ setBounds(x, y, w, h);
275
+ }
276
+
277
+ @Override
278
+ public void receiveMouseEvent(MouseEvent e) {
279
+ if(e.getID() == MouseEvent.MOUSE_CLICKED) System.out.println("Click!!");
280
+ }
281
+ }
282
+ ```

2

追加

2024/07/29 09:51

投稿

jimbe
jimbe

スコア13168

test CHANGED
@@ -78,3 +78,72 @@
78
78
  123 clicked.
79
79
  123 existed.
80
80
  ```
81
+ ---
82
+
83
+ ラベルの載っているパネルにマウスイベントを受信させて、その位置にある全ての子コンポーネントのメソッドを呼ぶようにするとこんな感じになります。
84
+ この場合、 MOUSE_ENTERED や MOUSE_EXITED は来ないのでそれが必要ならパネルが判断したりが必要になります。
85
+ ```java
86
+ import java.awt.Color;
87
+ import java.awt.Component;
88
+ import java.awt.event.MouseEvent;
89
+
90
+ import javax.swing.*;
91
+
92
+ public class MainFrame extends JFrame {
93
+ public static void main(String[] args) {
94
+ SwingUtilities.invokeLater(() -> new MainFrame().setVisible(true));
95
+ }
96
+
97
+ MainFrame() {
98
+ super("重なりイベント");
99
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
100
+
101
+ add(new MainPanel());
102
+
103
+ pack();
104
+ setLocationRelativeTo(null);
105
+ }
106
+
107
+ private static class MainPanel extends JPanel {
108
+ MainPanel() {
109
+ super(null);
110
+ setSize(320, 320);
111
+ setPreferredSize(getSize());
112
+ setBackground(Color.YELLOW);
113
+
114
+ add(new MyLabel("ABC", 20, 20, 200, 200, Color.GREEN, JLabel.TOP));
115
+ add(new MyLabel("123", 100, 100, 200, 200, Color.RED, JLabel.BOTTOM));
116
+
117
+ enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK);
118
+ }
119
+
120
+ @Override
121
+ protected void processMouseEvent(MouseEvent e) {
122
+ Component[] components = getComponents();
123
+ for(Component c : components) {
124
+ if(c.getBounds().contains(e.getX(), e.getY()) && c instanceof MyLabel) {
125
+ ((MyLabel)c).receiveMouseEvent(SwingUtilities.convertMouseEvent(this, e, c));
126
+ }
127
+ }
128
+ }
129
+ @Override
130
+ protected void processMouseMotionEvent(MouseEvent e) {
131
+ processMouseEvent(e);
132
+ }
133
+ }
134
+
135
+ private static class MyLabel extends JLabel {
136
+ MyLabel(String text, int x, int y, int w, int h, Color bg, int valign) {
137
+ super(text);
138
+ setBounds(x,y,w,h);
139
+ setOpaque(true);
140
+ setBackground(bg);
141
+ setVerticalAlignment(valign);
142
+ }
143
+ //MouseListener 等の代わりになるメソッド
144
+ void receiveMouseEvent(MouseEvent e) {
145
+ System.out.println(getText() + " receive " + e);
146
+ }
147
+ }
148
+ }
149
+ ```

1

追記

2024/07/28 20:20

投稿

jimbe
jimbe

スコア13168

test CHANGED
@@ -1,5 +1,6 @@
1
- 下だけにリスナを登録すれば重なっている部分でも下が受け取ります。
2
- 重なりの状態が変わるのなら、変わった時にリスナを付け替えることで出来るでしょう。
1
+ 下だけにリスナを登録すれば重なっている部分でも下が受け取ます。重なりの状態が変わるのなら、変わった時にリスナを付け替えることで出来るでしょう。
2
+ もしくは、各ラベルで受け取るのでは無くコンテナ(回答のコードでは MainPanel )が受け取って、 Z オーダーからラベルを決めて処理させるというテもあります。
3
+
3
4
  もっとちゃんと(?)やるなら、 Swing のコンポーネント間でイベントがどう伝わっているのかを調べられると良いと思います。(分かり易い図を何処かで見た気がしたんですが見つかりませんでした。)
4
5
  ```java
5
6
  import java.awt.Color;