Creating Control Customizers

Customizers are a type of per instance design-time metadata. The ClassInfo class defines metadata that is specific to the class; in contrast, the customizer provides access to more advanced design-time functionality. By creating a Customizer object, you can add functionality to your control such as specifying design-time activation, adding control verbs, and creating design pages (custom property pages).

As with the value editors, there is a default implementation of com.ms.wfc.core.ICustomizer — com.ms.wfc.core.Customizer. You can override the getCustomizer method in ClassInfo to return an instance of a customizer.

In this topic you can find information about the following:

Specifying Design-Time Activation

WFC supports design-time activation of controls, such as design-time scrolling or item expansion, through a simple hit testing scheme. When a control is selected, hit test requests will be passed to the control’s customizer. If the hit test returns true then the control will be considered active at that location. This simple architecture allows for very seamless activation of regions of a control, such as the tab area of a tab strip.

The following example illustrates a simple hit testing method that allows the control to receive messages when the mouse is over the top 50 pixels of the control:

Note   A control is only activated (and the getHitTest event is fired) when it is the primary selected component.

import com.ms.wfc.ui.*;
import com.ms.wfc.core.*;

public class MyTabControl extends Control { 
    
    public static class ClassInfo extends Control.ClassInfo {
        public ICustomizer getCustomzier(Object comp) {
            return ((MyTabControl)comp).new Customizer();
        }
    }
    
    public class Customizer extends com.ms.wfc.core.Customizer {
        public boolean getHitTest(Point pt) {
            if (pt.y < 50) {
                return true;
            }
            return false;
        }
    }
}

Specifying Control Verbs

Verbs allow you to define design-time actions that can be performed on an object. Verbs typically appear on the shortcut menu for the control in the designer.

To create a verb, subclass the Customizer class and then create a CustomizerVerb object, which allows you to specify the text for your verb and to create a delegate that binds the action of the verb to a method that you specify.

The following example illustrates how to create a verb called About. The About class offers one verb that reads "About" in the context menu and displays a simple message box. The method to display the results of the Action verb is included in this class:

// About.java
import com.ms.wfc.ui.*;
import com.ms.wfc.core.*;

public class About extends Control {
    public static class ClassInfo extends Control.ClassInfo {
        public ICustomizer getCustomizer(Object comp) {
            return ((About)comp).new Customizer();
        }
    }
    public class Customizer extends com.ms.wfc.core.Customizer {
        public CustomizerVerb[] getVerbs() {
            CustomizerVerb v = new CustomizerVerb("About", 
               new VerbExecuteEventHandler(About.this.showAbout));
            return new CustomizerVerb[] {v};
        }
    }
    
    private void showAbout(Object sender, VerbExecuteEvent event) {
        MessageBox.show("This control was written in WFC", "About",
         MessageBox.OK);
    }
}

In addition to the data and the delegate, you can specify the checked and enabled state of the item and associate a bitmap with the item. Although currently Visual J++ will not display a bitmap specified in a customizer (for instance, in a shortcut menu), other hosts might support this feature.

Specifying Design Pages

Design pages are the WFC equivalent of property pages. Design pages can be edited in the design-time environment. To implement a design page, you create a class that extends DesignPage class and overrides the onReadProperty and onWriteProperty methods.

Note    Although WFC supports design pages, you are encouraged to provide functionality for your control through custom editors, verbs, and design-time activation. For details, see Creating a Custom Properties Value Editor.

The following example illustrates how to create a design page for an alignment property. The alignment values (left, center, right) are implemented as group of option buttons. In the onReadProperty method, the code checks for the alignment property and returns the object value of the property as it is set in the design page. In the onWriteProperty method, the code again checks for alignment and displays its value in the design page. In the handle for all the radio buttons, the setDirty method is called, which marks the design page as dirty and enables the Apply button in the Properties window:

// SuperLabelDP.java
import com.ms.wfc.core.*;
import com.ms.wfc.ui.*;

public class SuperLabelDP extends DesignPage { 
    public SuperLabelDP() { 
        initForm();
    }

    private void setAlign(int value) {
        switch (value) {
            case AlignStyle.LEFT:
                radioButton1.setChecked(true);
                break;
            case AlignStyle.CENTER:
                radioButton2.setChecked(true);
                break;
            case AlignStyle.RIGHT:
                radioButton3.setChecked(true);
                break;
        }
    }

    private int getAlign() {
        int align = AlignStyle.LEFT;
        if (radioButton1.getChecked()) {
            align = AlignStyle.LEFT;
        }
        else if (radioButton2.getChecked()) {
            align = AlignStyle.CENTER;
        }
        else if (radioButton3.getChecked()) {
            align = AlignStyle.RIGHT;
        }
        return align;
    }
    
    private void radioClicked(Object sender, Event e) { 
        setDirty();
    }

    protected Object onReadProperty(String name) { 
        if (name.equals("alignment")) {
            return new Integer(getAlign());
        }
        return null;
    }

    protected void onWriteProperty(String name, Object value) { 
        if (name.equals("alignment") && value instanceof Integer) {
            setAlign(((Integer)value).intValue());
        }
    }
    
    Container components = new Container();
    GroupBox groupBox1 = new GroupBox();
    RadioButton radioButton1 = new RadioButton();
    RadioButton radioButton2 = new RadioButton();
    RadioButton radioButton3 = new RadioButton();

    private void initForm() { 
        this.setText("Alignment");
        this.setAutoScaleBaseSize(13);
        this.setBorderStyle(FormBorderStyle.NONE);
        this.setClientSize(new Point(307, 131));
        this.setControlBox(false);
        this.setMaxButton(false);
        this.setMinButton(false);

        groupBox1.setLocation(new Point(8, 8));
        groupBox1.setSize(new Point(128, 112));
        groupBox1.setTabIndex(0);
        groupBox1.setTabStop(false);
        groupBox1.setText("Alignment ");

        radioButton1.setLocation(new Point(8, 16));
        radioButton1.setSize(new Point(112, 25));
        radioButton1.setTabIndex(0);
        radioButton1.setTabStop(true);
        radioButton1.setText("Left");
        radioButton1.setChecked(true);
        radioButton1.addOnClick(new EventHandler(this.radioClicked));

        radioButton2.setLocation(new Point(8, 48));
        radioButton2.setSize(new Point(112, 25));
        radioButton2.setTabIndex(1);
        radioButton2.setText("Center");
        radioButton2.addOnClick(new EventHandler(this.radioClicked));

        radioButton3.setLocation(new Point(8, 80));
        radioButton3.setSize(new Point(112, 25));
        radioButton3.setTabIndex(2);
        radioButton3.setText("Rigt");
        radioButton3.addOnClick(new EventHandler(this.radioClicked));

        this.setNewControls(new Control[] {
            groupBox1});
        groupBox1.setNewControls(new Control[] {
            radioButton3, 
            radioButton2, 
            radioButton1});
    }
}