Tuesday 18 February 2014

Creating a Custom Java AWT Component – Part 2: Resizing and Segment Control

The whole point of the control is to display a number, so inputting a number is just a case of setting a display value:

private int displayNumber = 8;

public int getDisplayNumber() {
    return displayNumber;
}

public void setDisplayNumber(int displayNumber) {
    this.displayNumber = displayNumber % 10;
    repaint();
}

A simple enough bean compatible getter and setter, but notice that in the setter, I've modulo 10, to restrict the input to single digits. I've also called the repaint method to re-display the component.

Now looking at the paint method, I only display a segment if it's used for a particular number. To determine this, I use the Arrays.binarySearch method on an array of the relevant numbers. For example, on the bottom left segment, which is only used by 2, 6, 8 and zero:

//bottom left
if(Arrays.binarySearch(new int[] {0,2,6,8}, displayNumber) > -1) {
    polygon = createSegment(createSegmentPoints(0, segmentHeight * 2 + segmentWidth, segmentHeight, segmentWidth));
    g2.fill(polygon);
}

Perhaps this is a bit over the top and there's a better way of doing it, but it saves all those OR clauses. This shows the segments and numbers when they are active:

Segment Number
Top 0,2,3,5,6,7,8,9
Top Left 0,4,5,6,8,9
Top Right 0,1,2,3,4,7,8,9
Middle 2,3,4,5,6,8,9
Bottom Left 0,2,6,8
Bottom Right 0,1,3,4,5,6,7,8,9
Bottom 0,2,3,5,6,8

All well and good so far. The only bit left to do is calculating the size of the segments in relation to the size of the panel. If you look at the previous diagram of the component:

SegmentArrangements

you can see that the height is three segment widths and two segment lengths. The width is two segment widths and one length. Using this as a basis, you can than say:

Ws = 2.Wp - Hp

Where Ws is the width of the segment, Wp is the width of the panel and Hp is the height of the panel. Correspondingly:

Ls = 2.Hp - 3.Wp

Where Ls is the length of the segment. You can see that for certain height and width ratios, the width and length of the segments are negative. Therefore:

2.Wp > Hp

and:

3.Wp < 2.Hp

Also:

Ws < Ls

Doing all the maths, we get that 50% < Wp < 60% of Hp. 55% sounds about right. Plugging this into the paint function:

int width = this.getHeight();
width *= 0.55;
int height = this.getHeight();
//set the width as a proportion of the height
this.setSize(width, height);
        
int segmentWidth = 2 * width - height;
int segmentLength = 2 * height - 3 * width;

Testing all this is simple enough. Put it all in a Frame, with a little timer to tick through the numbers:

private LEDPanel led;

public TestFrame(String title){
    //call the superclass constructor with the specified title
    super(title);

    //add the LED panel for testing
    led = new LEDPanel();
    add(led);
    led.setBackground(Color.black);
    led.setForeground(Color.red);
    led.setDisplayNumber(5);

    Timer timer = new Timer();
    timer.schedule(new TimerTask() {
        public void run() {
            led.setDisplayNumber(led.getDisplayNumber() + 1);
        }
    }, 2000, 1000);

    //add the exit listener and set the size
    addWindowListener(new WindowAdapter() {
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });

    setSize(200, 300);
    //show the frame
    setVisible(true);
}

Now it's all working tickety-boo, I thought I'd go over the refectoring of the code in the next part.

No comments:

Post a Comment