OOP2

ClockAnalogView.java

1
package be.uhasselt.oo2.mvc.app.clock;
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