-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathMarqueePanel.java
More file actions
365 lines (318 loc) · 8.94 KB
/
MarqueePanel.java
File metadata and controls
365 lines (318 loc) · 8.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* The MarqueePanel is used to scroll components from the right edge of the
* panel to the left edge. Scrolling is continuous. To simulate the scrolling
* of text you can simply add a JLabel to the panel.
*
* Various properties control the scrolling of the components on the panel.
* Changes to the properties are dynamic and will take effect the next time
* the components are scrolled.
*/
public class MarqueePanel extends JPanel
implements ActionListener, AncestorListener, WindowListener
{
protected boolean paintChildren;
protected boolean scrollingPaused;
protected int scrollOffset;
protected int wrapOffset;
private int preferredWidth = -1;
private int scrollAmount;
private int scrollFrequency;
private boolean wrap = false;
private int wrapAmount = 50;
private boolean scrollWhenFocused = true;
private Timer timer = new Timer(1000, this);
/**
* Convenience constructor that sets both the scroll frequency and
* scroll amount to a value of 5.
*/
public MarqueePanel()
{
this(5, 5);
}
/**
* Create an AnimatedIcon that will continuously cycle with the
* default (500ms).
*
* @param component the component the icon will be painted on
* @param icons the Icons to be painted as part of the animation
*/
public MarqueePanel(int scrollFrequency, int scrollAmount)
{
setScrollFrequency( scrollFrequency );
setScrollAmount( scrollAmount );
setLayout( new BoxLayout(this, BoxLayout.X_AXIS) );
addAncestorListener( this );
}
/*
* Translate the location of the children before they are painted so it
* appears they are scrolling left to right
*/
@Override
public void paintChildren(Graphics g)
{
// Need this so we don't see a flicker of the text before scrolling
if (! paintChildren) return;
// Normal painting as the components scroll right to left
Graphics2D g2d = (Graphics2D)g;
g2d.translate(-scrollOffset, 0);
super.paintChildren(g);
g2d.translate(scrollOffset, 0);
// Repaint the start of the components on the right edge of the panel once
// all the components are completely visible on the panel.
// (Its like the components are in two places at the same time)
if (isWrap())
{
wrapOffset = scrollOffset - super.getPreferredSize().width - wrapAmount;
g2d.translate(-wrapOffset, 0);
super.paintChildren(g);
g2d.translate(wrapOffset, 0);
}
}
/*
* The default preferred size will be half the size of the components added to
* the panel. This will allow room for components to be scrolled on and off
* the panel.
*
* The default width can be overriden by using the setPreferredWidth() method.
*/
@Override
public Dimension getPreferredSize()
{
Dimension d = super.getPreferredSize();
d.width = (preferredWidth == -1) ? d.width / 2 : preferredWidth;
return d;
}
@Override
public Dimension getMinimumSize()
{
return getPreferredSize();
}
public int getPreferredWidth()
{
return preferredWidth;
}
/**
* Specify the preferred width on the panel. A value of -1 will cause the
* default preferred with size calculation to be used.
*
* @param preferredWidth preferred width of the panel in pixels
*/
public void setPreferredWidth(int preferredWidth)
{
this.preferredWidth = preferredWidth;
revalidate();
}
/**
* Get the scroll amount.
*
* @return the scroll amount in pixels
*/
public int getScrollAmount()
{
return scrollAmount;
}
/**
* Specify the scroll amount. The number of pixels to scroll every time
* scrolling is done.
*
* @param scrollAmount scroll amount in pixels
*/
public void setScrollAmount(int scrollAmount)
{
this.scrollAmount = scrollAmount;
}
/**
* Get the scroll frequency.
*
* @return the scroll frequency
*/
public int getScrollFrequency()
{
return scrollFrequency;
}
/**
* Specify the scroll frequency. That is the number of times scrolling
* should be performed every second.
*
* @param scrollFrequency scroll frequency
*/
public void setScrollFrequency(int scrollFrequency)
{
this.scrollFrequency = scrollFrequency;
int delay = 1000 / scrollFrequency;
timer.setInitialDelay( delay );
timer.setDelay( delay );
}
/**
* Get the scroll only when visible property.
*
* @return the scroll only when visible value
*/
public boolean isScrollWhenFocused()
{
return scrollWhenFocused;
}
/**
* Specify the scrolling property for unfocused windows.
*
* @param scrollWhenVisible when true scrolling pauses when the window
* loses focus. Scrolling will continue when
* the window regains focus. When false
* scrolling is continuous unless the window
* is iconified.
*/
public void setScrollWhenFocused(boolean scrollWhenFocused)
{
this.scrollWhenFocused = scrollWhenFocused;
}
/**
* Get the wrap property.
*
* @return the wrap value
*/
public boolean isWrap()
{
return wrap;
}
/**
* Specify the wrapping property. Normal scrolling is such that all the text
* will scroll from left to right. When the last part of the text scrolls off
* the left edge scrolling will start again from the right edge. Therefore
* there is a time when the component is blank as nothing is displayed.
* Wrapping implies that as the end of the text scrolls off the left edge
* the beginning of the text will scroll in from the right edge. So the end
* and the start of the text is displayed at the same time.
*
* @param wrap when true the start of the text will scroll in from the right
* edge while the end of the text is still scrolling off the left
* edge. Otherwise the panel must be clear of text before
* will begin again from the right edge.
*/
public void setWrap(boolean wrap)
{
this.wrap = wrap;
}
/**
* Get the wrap amount.
*
* @return the wrap amount value
*/
public int getWrapAmount()
{
return wrapAmount;
}
/**
* Specify the wrapping amount. This specifies the space between the end of the
* text on the left edge and the start of the text from the right edge when
* wrapping is turned on.
*
* @param wrapAmount the amount in pixels
*/
public void setWrapAmount(int wrapAmount)
{
this.wrapAmount = wrapAmount;
}
/**
* Start scrolling the components on the panel. Components will start
* scrolling from the right edge towards the left edge.
*/
public void startScrolling()
{
paintChildren = true;
scrollOffset = - getSize().width;
timer.start();
}
/**
* Stop scrolling the components on the panel. The conponents will be
* cleared from the view of the panel
*/
public void stopScrolling()
{
timer.stop();
paintChildren = false;
repaint();
}
/**
* The components will stop scrolling but will remain visible
*/
public void pauseScrolling()
{
if (timer.isRunning())
{
timer.stop();
scrollingPaused = true;
}
}
/**
* The components will resume scrolling from where scrolling was stopped.
*/
public void resumeScrolling()
{
if (scrollingPaused)
{
timer.restart();
scrollingPaused = false;
}
}
// Implement ActionListener
/**
* Adjust the offset of the components on the panel so it appears that
* they are scrolling from right to left.
*/
public void actionPerformed(ActionEvent ae)
{
scrollOffset = scrollOffset + scrollAmount;
int width = super.getPreferredSize().width;
if (scrollOffset > width)
{
scrollOffset = isWrap() ? wrapOffset + scrollAmount : - getSize().width;
}
repaint();
}
// Implement AncestorListener
/**
* Get notified when the panel is added to a Window so we can use a
* WindowListener to automatically start the scrolling of the components.
*/
public void ancestorAdded(AncestorEvent e)
{
SwingUtilities.windowForComponent( this ).addWindowListener( this );
}
public void ancestorMoved(AncestorEvent e) {}
public void ancestorRemoved(AncestorEvent e) {}
// Implement WindowListener
public void windowActivated(WindowEvent e)
{
if (isScrollWhenFocused())
resumeScrolling();
}
public void windowClosed(WindowEvent e)
{
stopScrolling();
}
public void windowClosing(WindowEvent e)
{
stopScrolling();
}
public void windowDeactivated(WindowEvent e)
{
if (isScrollWhenFocused())
pauseScrolling();
}
public void windowDeiconified(WindowEvent e)
{
resumeScrolling();
}
public void windowIconified(WindowEvent e)
{
pauseScrolling();
}
public void windowOpened(WindowEvent e)
{
startScrolling();
}
}