ClockAnalogView.java
1 |
|
2 |
|
3 |
import be.uhasselt.oo2.mvc.Controller; |
4 |
import be.uhasselt.oo2.mvc.View; |
5 |
import java.awt.Color; |
6 |
import java.awt.Dimension; |
7 |
import java.awt.Graphics; |
8 |
import java.awt.Graphics2D; |
9 |
import java.awt.RenderingHints; |
10 |
import java.awt.geom.AffineTransform; |
11 |
import java.awt.geom.Ellipse2D; |
12 |
import java.awt.geom.GeneralPath; |
13 |
import java.util.Calendar; |
14 |
import java.util.Observable; |
15 |
import javax.swing.JComponent; |
16 |
|
17 |
/** |
18 |
* An analog clock View for the ClockModel. This View has no user inputs, so |
19 |
* no controller is required. This class implements the View interface, and |
20 |
* subclasses JComponent directly, to illustrate that not all Views need to |
21 |
* inherit from AbstractView. |
22 |
* |
23 |
* Note: it is not necessary to understand all the details of the rendering |
24 |
* of the analog clock. |
25 |
* |
26 |
* @author jvermeulen (inspired by IBM Java2D tutorial) |
27 |
*/ |
28 |
public class ClockAnalogView extends JComponent implements View { |
29 |
|
30 |
private Observable mModel; |
31 |
private Controller mController; |
32 |
|
33 |
int mHour; |
34 |
int mMinute; |
35 |
int mSecond; |
36 |
|
37 |
ClockAnalogView(Observable model, Controller controller) { |
38 |
mModel = model; |
39 |
mController = controller; |
40 |
} |
41 |
|
42 |
@Override |
43 |
public void setController(Controller controller) { |
44 |
mController = controller; |
45 |
} |
46 |
|
47 |
@Override |
48 |
public Controller getController() { |
49 |
return mController; |
50 |
} |
51 |
|
52 |
@Override |
53 |
public void setModel(Observable model) { |
54 |
mModel = model; |
55 |
} |
56 |
|
57 |
@Override |
58 |
public Observable getModel() { |
59 |
return mModel; |
60 |
} |
61 |
|
62 |
@Override |
63 |
public Controller defaultController(Observable model) { |
64 |
return null; |
65 |
} |
66 |
|
67 |
@Override |
68 |
public void update(Observable o, Object info) { |
69 |
// Cast info to ClockUpdate type. |
70 |
ClockUpdate clockInfo = (ClockUpdate) info; |
71 |
|
72 |
// Store hour, minute, second for repainting. |
73 |
mHour = clockInfo.getHour(); |
74 |
mMinute = clockInfo.getMinute(); |
75 |
mSecond = clockInfo.getSecond(); |
76 |
|
77 |
// Using a little trigonometry, set the transforms to rotate |
78 |
// each hand into the proper position. Center the rotation |
79 |
// around the pivot point (50, 50) instead of the origin |
80 |
hourTransform.setToRotation(((double) mHour) * |
81 |
(Math.PI / 6.0), 50, 50); |
82 |
minuteTransform.setToRotation(((double) mMinute) * |
83 |
(Math.PI / 30.0), 50, 50); |
84 |
secondTransform.setToRotation(((double) mSecond) * |
85 |
(Math.PI / 30.0), 50, 50); |
86 |
|
87 |
repaint(); |
88 |
} |
89 |
|
90 |
|
91 |
/** |
92 |
* Sets this components preferred size to 150x150. |
93 |
* @return |
94 |
*/ |
95 |
@Override |
96 |
public Dimension getPreferredSize() { |
97 |
return new Dimension(100, 100); |
98 |
} |
99 |
|
100 |
// Create a shape for the face of the clock |
101 |
protected static Ellipse2D face = new Ellipse2D.Float(3, 3, 94, 94); |
102 |
|
103 |
// Create a path that represents a tick mark |
104 |
protected static GeneralPath tick = new GeneralPath(); |
105 |
static // http://www.jusfortechies.com/java/core-java/static-blocks.php |
106 |
{ |
107 |
tick.moveTo(100, 100); |
108 |
tick.moveTo(49, 0); |
109 |
tick.lineTo(51, 0); |
110 |
tick.lineTo(51, 6); |
111 |
tick.lineTo(49, 6); |
112 |
tick.lineTo(49, 0); |
113 |
} |
114 |
|
115 |
// Create a cool hour hand |
116 |
protected static GeneralPath hourHand = new GeneralPath(); |
117 |
static |
118 |
{ |
119 |
hourHand.moveTo(50, 15); |
120 |
hourHand.lineTo(53, 50); |
121 |
hourHand.lineTo(50, 53); |
122 |
hourHand.lineTo(47, 50); |
123 |
hourHand.lineTo(50, 15); |
124 |
} |
125 |
|
126 |
// Create a cool minute hand |
127 |
protected static GeneralPath minuteHand = new GeneralPath(); |
128 |
static |
129 |
{ |
130 |
minuteHand.moveTo(50, 2); |
131 |
minuteHand.lineTo(53, 50); |
132 |
minuteHand.lineTo(50, 58); |
133 |
minuteHand.lineTo(47, 50); |
134 |
minuteHand.lineTo(50, 2); |
135 |
} |
136 |
|
137 |
// And a cool second hand |
138 |
protected static GeneralPath secondHand = new GeneralPath(); |
139 |
static |
140 |
{ |
141 |
secondHand.moveTo(49, 5); |
142 |
secondHand.lineTo(51, 5); |
143 |
secondHand.lineTo(51, 62); |
144 |
secondHand.lineTo(49, 62); |
145 |
secondHand.lineTo(49, 5); |
146 |
} |
147 |
|
148 |
// Create some colors for the pieces of the clock |
149 |
protected static Color faceColor = new Color(220, 220, 220); |
150 |
protected static Color hourColor = Color.red.darker(); |
151 |
protected static Color minuteColor = Color.blue.darker(); |
152 |
protected static Color secondColor = new Color(180, 180, 0); |
153 |
protected static Color pinColor = Color.gray.brighter(); |
154 |
|
155 |
// Create circles for the pivot and center pin |
156 |
protected Ellipse2D pivot = new Ellipse2D.Float(47, 47, 6, 6); |
157 |
protected Ellipse2D centerPin = new Ellipse2D.Float(49, 49, 2, 2); |
158 |
|
159 |
|
160 |
// Create three transforms that center around the pivot point |
161 |
protected AffineTransform hourTransform = |
162 |
AffineTransform.getRotateInstance(0, 50, 50); |
163 |
protected AffineTransform minuteTransform = |
164 |
AffineTransform.getRotateInstance(0, 50, 50); |
165 |
protected AffineTransform secondTransform = |
166 |
AffineTransform.getRotateInstance(0, 50, 50); |
167 |
|
168 |
// Create a timer that fires once a second and a Calendar |
169 |
// instance for getting the time values |
170 |
// protected Timer timer = new Timer(1000, this); |
171 |
protected Calendar calendar = Calendar.getInstance(); |
172 |
|
173 |
// This is an alternative to creating a UI delegate. Since JPanel's |
174 |
// paint() method only paints the border and backgound, we can just |
175 |
// override the paint method of the component to do the graphics. |
176 |
public void paint(Graphics g) |
177 |
{ |
178 |
// Call the superclass first to paint the border (if one is assigned) |
179 |
super.paint(g); |
180 |
|
181 |
|
182 |
// Get the graphics context and turn on anti-aliasing |
183 |
Graphics2D g2 = (Graphics2D) g; |
184 |
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
185 |
RenderingHints.VALUE_ANTIALIAS_ON); |
186 |
|
187 |
// Set the paint for the clock face and fill it in |
188 |
g2.setPaint(faceColor); |
189 |
g2.fill(face); |
190 |
|
191 |
// Set the paint to black and draw the clock's outline |
192 |
g2.setPaint(Color.black); |
193 |
g2.draw(face); |
194 |
|
195 |
// Fill in the 12 ticks around the face of the clock |
196 |
for (double p = 0.0; p < 12.0; p += 1.0) |
197 |
{ |
198 |
// This is probably terribly inefficient and should be |
199 |
// done statically or in the constructor - draw the |
200 |
// tick as a transformed shape that is rotated. |
201 |
g2.fill(tick.createTransformedShape( |
202 |
AffineTransform.getRotateInstance((Math.PI / 6.0) * p, |
203 |
50, 50))); |
204 |
} |
205 |
|
206 |
// Set the paint and draw the hour hand. It is lowest in the |
207 |
// 'z-order' so will appear underneath the other hands. Notice |
208 |
// how each hand is transformed by a different <AffineTransform>. |
209 |
g2.setPaint(hourColor); |
210 |
g2.fill(hourHand.createTransformedShape(hourTransform)); |
211 |
|
212 |
// Set the paint and draw the minute hand, the second hand, |
213 |
// the pivot and the center pin |
214 |
g2.setPaint(minuteColor); |
215 |
g2.fill(minuteHand.createTransformedShape(minuteTransform)); |
216 |
g2.setPaint(secondColor); |
217 |
g2.fill(secondHand.createTransformedShape(secondTransform)); |
218 |
g2.fill(pivot); |
219 |
g2.setPaint(pinColor); |
220 |
g2.fill(centerPin); |
221 |
} |
222 |
} |
223 |