java - 如何在 GWT 中实现 JQueryUI slider

标签 java javascript jquery jquery-ui gwt

我最近需要在 GWT 中实现一个 slider 来捕获用户在任务上取得的进度百分比。我对 GWT 孵化器中的 slider 不满意,也不太热衷于使用像 spiffy UI 或 SmartGWT 这样的外部库。我可以使用哪些替代方案来在 GWT 中实现有效的 slider 而不需要做太多笨拙的工作?

最佳答案

经过大量搜索后,我决定使用 JQuery-Ui slider ,该 slider 将通过 Java 包装器类实现。 GWT 和 JQuery slider 之间的交互将通过 GWT Java Script Native Interface 进行。为了尽可能减少对所需库的添加,我下载了一个非常轻量级的自定义 Jquery-Ui 包(只是 core+slider)。结果满足了我们的需求,符合我们的 MVP 设计模式并且是 UI Bound。

slider 包装如下:

package za.co.bsg.ems.client.framework.ui.slider;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;

import java.util.ArrayList;
import java.util.List;


/**
 * This widget wraps the JQuery UI Slider and allows for single slider .
 * 
 * All options can be get or set using generic get/setIntOption, get/setStringOption, get/setBooleanOption
 * methods, but some convenience methods are provided for most popular such as
 * setValues and setMinimum and setMaximum.  See SliderOptions for full list of options.
 * @see SliderOption
 *
 */
@SuppressWarnings("Convert2Diamond")
public class SingleSlider extends Widget {

    private JSONObject defaultOptions;
    private List<SliderListener> listeners = new ArrayList<SliderListener>();

    /**
     * Create the default slider with the specified ID.  The ID is required
     * because the slider needs a specific ID to connect to.
     * @param id - id of the element to create
     */
    public SingleSlider(String id) {
        this(id, null);        
    }

    /**
     * Create a slider with the specified ID.  The ID is required
     * because the slider needs a specific ID to connect to.
     * @param id - id of the element to create
     * @param options - JSONObject of any possible option, can be null for defaults
     */
    public SingleSlider(String id, JSONObject options) {
        super();
        Element divEle = DOM.createDiv();
        setElement(divEle);
        divEle.setId(id);

        defaultOptions = options;
        if (defaultOptions == null) {
            defaultOptions = getOptions(0, 100, 0);
        }        
    }

    /**
     * A convenient way to create an options JSONObject.  Use SliderOption for keys.
     * @param min - default minimum of the slider
     * @param max - default maximum of the slider
     * @param defaultValue - default point of anchor
     * @return a JSONObject of Slider options
     */
    public static JSONObject getOptions(int min, int max, int defaultValue) {
        JSONObject options = new JSONObject();
        options.put(SliderOption.MIN.toString(), new JSONNumber(min));
        options.put(SliderOption.MAX.toString(), new JSONNumber(max));
        options.put(SliderOption.VALUE.toString(), new JSONNumber(defaultValue));
        options.put(SliderOption.RANGE.toString(), new JSONString("min"));
        return options;
    }

    @Override
    protected void onLoad() {
        createSliderJS(this, getElement().getId(), defaultOptions.getJavaScriptObject());
        super.onLoad();
    }

    @Override
    protected void onUnload() {
        destroySliderJS(this, getElement().getId());
        super.onUnload();        
    }
    /**
     * Gets the minimum possible value for the slider
     * @return Returns the minimum.
     */
    public int getMinimum() {
        return getIntOptionJS(getElement().getId(), SliderOption.MIN.toString());
    }

    /**
     * Sets the minimum possible value for the slider
     * @param minimum The minimum to set.
     */
    public void setMinimum(int minimum) {
        setIntOptionJS(getElement().getId(), SliderOption.MIN.toString(), minimum);
    }

    /**
     * Gets the maximum possible value for the slider
     * @return Returns the maximum.
     */
    public int getMaximum() {
        return getIntOptionJS(getElement().getId(), SliderOption.MAX.toString());
    }

    /**
     * Sets the maximum possible value for the slider
     * @param maximum The maximum to set.
     */
    public void setMaximum(int maximum) {
        setIntOptionJS(getElement().getId(), SliderOption.MAX.toString(), maximum);
    }

    /**
     * Convenience method for only 1 anchor
     * @param value to set.
     */
    public void setValue(int value) {
        setValueJS(getElement().getId(), value);
    }


    /**
     * Set an option numeric value
     * @param option the SliderOption
     * @param value the numeric
     */
    public void setIntOption(SliderOption option, int value) {
        setIntOptionJS(getElement().getId(), option.toString(), value);
    }

    /**
     * Get an option numeric value
     * @param option the SliderOption
     * @return value the numeric
     */
    public int getIntOption(SliderOption option) {
        return getIntOptionJS(getElement().getId(), option.toString());
    }

    /**
     * Set an option boolean value
     * @param option the SliderOption
     * @param value the boolean
     */
    public void setBooleanOption(SliderOption option, boolean value) {
        setBooleanOptionJS(getElement().getId(), option.toString(), value);
    }

    /**
     * Get an option boolean value
     * @param option the SliderOption
     * @return value the boolean
     */
    public boolean getBooleanOption(SliderOption option) {
        return getBooleanOptionJS(getElement().getId(), option.toString());
    }

    /**
     * Set an option string value
     * @param option the SliderOption
     * @param value the String
     */
    public void setStringOption(SliderOption option, String value) {
        setStringOptionJS(getElement().getId(), option.toString(), value);
    }

    /**
     * Set an option string value
     * @param option the SliderOption
     * @return value the String
     */
    public String setStringOption(SliderOption option) {
        return getStringOptionJS(getElement().getId(), option.toString());
    }

    /**
     * Add a SliderListener
     * @param l - SliderListener
     */
    public void addListener(SliderListener l) {
        listeners.add(l);
    }

    /**
     * Removes the SliderListener
     * @param l - SliderListener
     */
    public void removeListener(SliderListener l) {
        listeners.remove(l);
    }


    private void fireOnStartEvent(Event evt, int value) {
        SliderEvent e = new SliderEvent(evt, this, value);

        for (SliderListener l : listeners) {
            l.onStart(e);
        }
    }

    private boolean fireOnSlideEvent(Event evt, int value) {
        SliderEvent e = new SliderEvent(evt, this, value);

        for (SliderListener l : listeners) {
            l.onStart(e);
        }

        boolean ret = true;

        for (SliderListener l : listeners) {
            if (!l.onSlide(e)) {
                //if any of the listeners returns false, return false,
                //but let them all do their thing
                ret = false;
            }
        }

        return ret;
    }

    private void fireOnChangeEvent(Event evt, int value, boolean hasOriginalEvent) {
        SliderEvent e = new SliderEvent(evt, this, value, hasOriginalEvent);

        for (SliderListener l : listeners) {
            l.onChange(e);
        }
    }

    private void fireOnStopEvent(Event evt, int value) {
        SliderEvent e = new SliderEvent(evt, this, value);

        for (SliderListener l : listeners) {
            l.onStop(e);
        }
    }


    private native void setIntOptionJS(String id, String option, int value) /*-{
        $wnd.$("#" + id).slider("option", option, value);
    }-*/;


    private native int getIntOptionJS(String id, String option) /*-{
        return $wnd.$("#" + id).slider("option", option);
    }-*/;


    private native void setBooleanOptionJS(String id, String option, boolean value) /*-{
        $wnd.$("#" + id).slider("option", option, value);
    }-*/;


    private native boolean getBooleanOptionJS(String id, String option) /*-{
        return $wnd.$("#" + id).slider("option", option);
    }-*/;


    private native void setStringOptionJS(String id, String option, String value) /*-{
        $wnd.$("#" + id).slider("option", option, value);
    }-*/;


    private native String getStringOptionJS(String id, String option) /*-{
        return $wnd.$("#" + id).slider("option", option);
    }-*/;

    private native void setValueJS(String id, int value) /*-{
        $wnd.$("#" + id).slider("option", "value", value);
    }-*/;


    private native void createSliderJS(SingleSlider x, String id, JavaScriptObject options) /*-{
        options.start = function(event, ui) {
            x.@za.co.bsg.ems.client.framework.ui.slider.SingleSlider::fireOnStartEvent(Lcom/google/gwt/user/client/Event;I)(event, ui.value);
        };
        options.slide = function(event, ui) {
            return x.@za.co.bsg.ems.client.framework.ui.slider.SingleSlider::fireOnSlideEvent(Lcom/google/gwt/user/client/Event;I)(event, ui.value);
        };
        options.change = function(event, ui) {
            var has = event.originalEvent ? true : false;
            x.@za.co.bsg.ems.client.framework.ui.slider.SingleSlider::fireOnChangeEvent(Lcom/google/gwt/user/client/Event;IZ)(event, ui.value, has);
        };
        options.stop = function(event, ui) {
            x.@za.co.bsg.ems.client.framework.ui.slider.SingleSlider::fireOnStopEvent(Lcom/google/gwt/user/client/Event;I)(event, ui.value);
        };

        $wnd.$("#" + id).slider(options);
    }-*/;


    private native void destroySliderJS(SingleSlider x, String id) /*-{
        $wnd.$("#" + id).slider("destroy");
    }-*/;
}

然后将此 slider 合并到以下小部件中以创建百分比 slider

package za.co.bsg.ems.client.framework.ui.slider;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.IntegerBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import za.co.bsg.ems.client.event.IntegerValueChangeEvent;

import java.util.HashSet;
import java.util.Set;

public class PercentageSliderWidget extends Composite implements SliderListener, HasValueChangeHandlers<Integer> {

    interface PercentageSliderUiBinder extends UiBinder<Widget, PercentageSliderWidget> {}
    private static final PercentageSliderUiBinder UI_BINDER = GWT.create(PercentageSliderUiBinder.class);

    @UiField
    Label headingLabel;
    @UiField(provided = true)
    SingleSlider singleSlider;
    @UiField
    IntegerBox percentBox;
    @UiField
    Label percentageSignLabel;

    private Set<ValueChangeHandler<Integer>> valueChangeHandlers;

    public PercentageSliderWidget(long taskId, String heading, int existingProgress) {
        valueChangeHandlers = new HashSet<>();
        JSONObject options = SingleSlider.getOptions(0, 100, existingProgress);
        singleSlider = new SingleSlider("singleSlider" + taskId, options);
        singleSlider.setTitle(existingProgress + "%");
        initWidget(UI_BINDER.createAndBindUi(this));
        singleSlider.addListener(this);
        percentBox.setValue(existingProgress);
        percentBox.addValueChangeHandler(new ValueChangeHandler<Integer>() {
            @Override
            public void onValueChange(ValueChangeEvent<Integer> event) {
                updateValues(event.getValue(), true);
            }
        });
        headingLabel.setText(heading);
        percentageSignLabel.setText("%");
    }

    public void setValue(int value) {
        updateValues(value, false);
    }

    @Override
    public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<Integer> handler) {
        valueChangeHandlers.add(handler);
        return new HandlerRegistration() {
            @Override
            public void removeHandler() {
                valueChangeHandlers.remove(handler);
            }
        };
    }

    @Override
    public boolean onSlide(SliderEvent e) {
        percentBox.setValue(e.getValue());
        return true;
    }

    @Override
    public void onChange(SliderEvent e) {
        // do nothing
    }

    @Override
    public void onStop(SliderEvent e) {
        updateValues(e.getValue(), true);
    }

    @Override
    public void onStart(SliderEvent e) {
        // do nothing
    }

    private void updateValues(int progressValue, boolean fireEvents) {
        singleSlider.setTitle(progressValue + "%");
        singleSlider.setValue(progressValue);
        percentBox.setValue(progressValue);
        if (fireEvents) {
            for (ValueChangeHandler<Integer> valueChangeHandler : valueChangeHandlers) {
                valueChangeHandler.onValueChange(new IntegerValueChangeEvent(progressValue));
            }
        }
    }

}

我的起始资源如下 http://www.zackgrossbart.com/hackito/gwt-slider/

关于java - 如何在 GWT 中实现 JQueryUI slider ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25665322/

相关文章:

javascript - 无法使用 jquery 按类访问嵌套 <p> 元素

jquery - 多个 Bootstrap 选择: z-index issue

jquery - 使用 jquery 将淡入淡出的垂直子菜单添加到一页 html

java - 即使 fetchtype 是惰性的,JPA 也会加载太多数据

java - 我如何解决在 android :onClick attribute? 的父或祖先上下文中找不到方法

Java 预处理器 - 将代码插入每个函数

javascript - 分离 javascript 和 html 以获得可读代码

javascript - 调度程序未在 Jest 单元测试中注册回调

javascript - else if 语句没有在点击 jquery 时运行

java - struts2 在操作类中获取值(value)