Incrementador General

Una de las mayores ventajas de definir componentes en Java es la posibilidad de que sean configurables a través de sus atributos. Como ejemplo, podríamos necesitar que el incrementador trabajase con cualquier número de bits; las dos clases que vienen a continuación muestran como es posible conseguirlo.

Incrementer

package com.cburch.incr;

import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.comp.ComponentDrawContext;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.comp.EndData;
import com.cburch.logisim.comp.ManagedComponent;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeEvent;
import com.cburch.logisim.data.AttributeListener;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Attributes;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;

/** Represents an incrementer that can work with any bit width. This component
 * is designed to illustrate how to use attributes. */
class Incrementer extends ManagedComponent {
    /** The attribute representing the bit width of the input and output. */
    static final Attribute WIDTH_ATTRIBUTE = Attributes.forBitWidth("Bit Width");
    
    /** The default value of the width attribute. */
    static final BitWidth WIDTH_DEFAULT = BitWidth.create(8);
    
    /** Listens for changes to the width attributes, because we need such
     * changes to be reflected in the information about ends managed by the
     * ManagedComponent superclass. */
    private class MyListener implements AttributeListener {
        public void attributeListChanged(AttributeEvent e) { }
        public void attributeValueChanged(AttributeEvent e) {
            if(e.getAttribute() == WIDTH_ATTRIBUTE) computeEnds();
        }
    }
    
    /** Represents the sole instance of MyListener. (The more common
     * idioms for dealing with listeners do not involve such a
     * local variable, but I strongly prefer this idiom, because
     * I often find it useful to store listeners in the listened-to
     * object using weak references to avoid situations analogous
     * to memory leaks when the listened-to object persists beyond
     * the intended life of the listening object. A side effect of
     * this is that the listener would die immediately if the listening
     * object doesn't maintain its own strong reference; hence the
     * instance variable. [It happens that the AttributeSet used here
     * uses strong references, but that's no guarantee that a future
     * version will not.])
     */
    private MyListener myListener = new MyListener();
    
    /** Constructs an incrementer at the given location with the given
     * attributes. */
    Incrementer(Location loc, AttributeSet attrs) {
        super(loc, attrs, 2);
        attrs.addAttributeListener(myListener);
        computeEnds();
    }
    
    /** Sets up the ends of this component. */
    private void computeEnds() {
        // Retrieve information needed for setting the ends - notice the
        // access to the attribute set to retrieve the width.
        Location loc = getLocation();
        BitWidth width = (BitWidth) getAttributeSet().getValue(WIDTH_ATTRIBUTE);
        
        // Now set up the ends.
        setEnd(0, loc.translate(-30, 0), width, EndData.INPUT_ONLY);
        setEnd(1, loc,                   width, EndData.OUTPUT_ONLY);
    }
    
    public ComponentFactory getFactory() {
        return IncrementerFactory.instance;
    }

    public void propagate(CircuitState circuitState) {
        Value in = circuitState.getValue(getEndLocation(0));
        Value out;
        if(in.isFullyDefined()) {
            out = Value.createKnown(in.getBitWidth(), in.toIntValue() + 1);
        } else if(in.isErrorValue()) {
            out = Value.createError(in.getBitWidth());
        } else {
            out = Value.createUnknown(in.getBitWidth());
        }
        circuitState.setValue(getEndLocation(1), out, this,
                in.getBitWidth().getWidth() + 1);
    }

    public void draw(ComponentDrawContext context) {
        context.drawRectangle(this, "+1");
        context.drawPins(this);
    }
}

IncrementerFactory

package com.cburch.incr;

import com.cburch.logisim.comp.AbstractComponentFactory;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.AttributeSets;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Location;

/** Manufactures Incrementer components. */
class IncrementerFactory extends AbstractComponentFactory {
    static final IncrementerFactory instance = new IncrementerFactory();
    
    private IncrementerFactory() { }
    
    public String getName() {
        return "Incrementer";
    }

    public String getDisplayName() {
        return "Incrementer (General)";
    }
    
    /** Creates an attribute set holding all the initial default values. This
     * is the only change from the ByteIncrementerClass class, where
     * we simply kept the definition implemented in the parent class. Here, though,
     * we want to insert the attribute. */
    public AttributeSet createAttributeSet() {
        return AttributeSets.fixedSet(Incrementer.WIDTH_ATTRIBUTE,
                Incrementer.WIDTH_DEFAULT);
    }

    public Component createComponent(Location loc, AttributeSet attrs) {
        return new Incrementer(loc, attrs);
    }

    public Bounds getOffsetBounds(AttributeSet attrs) {
        return Bounds.create(-30, -15, 30, 30);
    }

}

Siguiente: Contador Básico .