从Vaadin 7中的枚举中创建OptionGroup(单选按钮)? [英] Make an OptionGroup (radio buttons) from an enum in Vaadin 7?

查看:196
本文介绍了从Vaadin 7中的枚举中创建OptionGroup(单选按钮)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有吸气剂的Java枚举,用于所需的显示文本。如何使用它在Vaadin 7中填充OptionGroup?

解决方案

在Vaadin 7中有以下三种方法: / p>


  • 我建的一个类, EnumBackedOptionGroup 。 Vaadin 7中的 OptionGroup 的子类

  • 滚动您自己的简单甜蜜的方式。




子类



这是我写的一个新的子类的源代码 OptionGroup

  package com.basilbourque; 

import com.vaadin.ui.OptionGroup;
import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import org.slf4j.LoggerFactory;

/ **
* Vaadin 7 OptionGroup(单选按钮或一组复选框)小部件的子类,将其作为其选项集
*枚举的实例。
*
*在规范使用中,传递您的枚举类,并引用要调用的方法来获取用于显示给用户的文本
*标签。
*
*或者,如果你的枚举覆盖了`toString`方法,那么你只能传递一个没有
*函数的枚举类。这种方法是不推荐使用的类文档解释`toString`应该只使用
*调试消息。然而,有些人覆盖`toString`来提供一个用户可读的标签,所以我们支持
*这个。
*
*即使您的枚举不覆盖`toString`,您可以选择省略传递Function参数。作为默认值,
*将调用Enum的内置toString方法,返回枚举实例的名称。这对于
*快速肮脏的原型设计很方便。再次,我和班级文件都不推荐这种认真的工作方法。
*
*如果要显示枚举实例的子集而不是全部,请传递集合。
*
*本源代码根据ISC许可证条款提供。 https://en.wikipedia.org/wiki/ISC_license
*
*版权所有(c)2015,Basil Bourque
*允许使用,复制,修改和/或分发本软件出于任何目的,无论是否支付费用,均为
*,条件是上述版权声明和本许可声明均出现在所有副本中。该软件是按原样提供的,作者不承担任何有关本软件的担保,包括所有隐含的b $ b *适销性和适用性的保证。在任何情况下,作者不得因任何特殊,直接,间接,
*或间接损失或任何由于使用,数据或利润损失而导致的任何损害,无论是否采取行动,由于使用或执行本
*软件引起的或与之相关的其他侵权行为或其他侵权行为。
*
* @author Basil Bourque
* @version 2015-08-27T21:00:00Z
* @since 2015-08-27T21:00:00Z
* /
public class EnumBackedOptionGroup< T extends Enum>扩展OptionGroup
{

final org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());

/ **
*构造函数。用于自动检测枚举的所有实例的通常构造函数,用作Vaadin 7 OptionGroup中的
*选项。传递一个函数,用于提供每个选项的显示标签。
*
*示例用法:
*
* myRadios = new EnumBackedOptionGroup&DogBreed>(选择品种:,DogBreed.class,DogBreed :: getTitle);
*
* @param caption
* @param enumClass
* @param f
* /
public EnumBackedOptionGroup(final String caption,final Class&T ; enumClass,final函数< T,String> f){
super(caption);
函数< T,String> func = f;
//如果为函数传递一个null,则返回使用'toString'。
if(func == null){
func = T - > T.toString();
}
this.buildAndAssignCaptions(enumClass,func);
}

/ **
*构造函数。类似于通常的构造函数,但是在这里,您可以另外传递Enum
*实例子集的集合。
*
*对于业务逻辑规定您只给出一些枚举值一个选项而不是全部
*的用途。省略的选项有效地从用户隐藏。
*
* @param caption
* @param enumClass
* @param enumValues
* @param f
* /
public EnumBackedOptionGroup final String< T> enumClass,final Collection< T> enumValues,final Function< T,String> f){
super(caption);
函数< T,String> func = f;
//如果为函数传递一个null,则返回使用'toString'。
if(func == null){
func = T - > T.toString();
}
收藏< T> ev =枚举值
//处理调用方法向我们传递一个空或空集合。
if((ev == null)|| ev.isEmpty()){
this.buildAndAssignCaptions(enumClass,f); //回退以将所有枚举的实例作为OptionGroup中的选项。
} else {
this.addItems(enumValues); //将传递的枚举实例子集添加到支持我们的OptionGroup的项目中。
this.assignCaptions(enumValues,f);
}
}

/ **
*构造函数。与通常的构造函数类似,但省略了提供屏幕标签的方法。相反,
*使用在Enum子类中明确定义的toString方法或隐式调用Enum类'
* own'toString'。
*
*不推荐,因为枚举文档强烈建议在枚举上使用'toString'方法仅用于
*调试。然而,这对于快速和脏的原型设计来说非常方便。
*
* @param caption
* @param enumClass
* /
public EnumBackedOptionGroup(final String caption,final Class< T> enumClass){
超级(标题);
//用户传递无函数调用获取标题。所以回到使用'toString'。
this.buildAndAssignCaptions(enumClass,T - > T.toString());
}

// Helper方法。 (子例程)
//提取枚举的所有实例,并将其用作OptionGroup中的选项。
//还可以使用传递方法返回的String为每个选项分配一个标签,以便为每个枚举的实例调用该方法。
private void buildAndAssignCaptions(final Class< T> enumClass,final Function< T,String> f){
if(enumClass.isEnum()){//此检查对于泛型代码 ; T扩展枚举>在这个班的顶部。
收藏< T> enumValues = Arrays.asList(enumClass.getEnumConstants());
this.addItems(enumValues); //将枚举的所有实例添加到支持我们的OptionGroup的项目中。
this.assignCaptions(enumValues,f);
} else {
//否则传递的类不是枚举。
//由于此类< T extends Enum>标记的泛型是不可能的。
logger.error(传递一个类不是Enum的子类消息#f2098672-ab47-47fe-b720-fd411411052e);
throw new IllegalArgumentException(传递一个不是Enum子类的类);
}
}

//帮助方法。 (子例程)
//使用通过传递的方法返回的String赋值每个选项一个标签,以便为枚举的每个实例调用
private void assignCaptions(Collection< T> enumValues,final Function< T,String> ; f){
for(T选项:enumValues){
//对于我们的OptionGroup中的每个选项,确定并设置其标题,为每个单选按钮或复选框旁边的用户显示标签。
//要确定标签(第二个参数),我们调用必须返回String的已传递方法。使用Lambda语法。
this.setItemCaption(option,f.apply(option));
}
}

}

我期望您将使用这样的枚举, DogBreed 。请注意,此枚举如何具有构造函数,在该构造函数中,我们传递要用作呈现给用户的标签的文本。我们添加了一个方法 getTitle 以检索此标题文本。

  package com 。例; 

/ **
*虚假示例枚举。
* /
public enum DogBreed {

AUSSIE(Australian Shepherd),
BORDER_COLLIE(Border Collie),
BLACK_LAB(Labrador ,Black),
MUTT(Mixed Breed);

private String title = null;

DogBreed(final String titleArg){
this.title = titleArg;
}

public String getTitle(){
return this.title;
}

}



我只能通过本答案 WillShackleford 对我的问题,用于传递和调用方法引用的lambda语法



要使用此 EnumBackedGroupOption 类,传递其类和该标题呈现方法的方法引用。这需要Java 8中的新的 Lambda语法,但不需要需要掌握你对Lambda的理解,只需按照你在这里看到的模式。

  OptionGroup optionGroup = new EnumBackedOptionGroup&DogBreed> ;(选择品种:,DogBreed.class,DogBreed :: getTitle); 

对于快速和脏的原型,您可以定义一个简单的枚举,没有这样的构造函数和getter。在这种情况下,只传递您的标题和枚举类。 EnumBackedOptionGroup 类可以回到使用内置的 toString 方法。我和 枚举 类别文档不推荐这条路线进行认真的工作

 ; 

/ **
*虚假示例枚举。
* /
public enum SaySo {

YES,NO,MAYBE;
}

OptionGroup optionGroup = new EnumBackedOptionGroup< SaySo>(Says you:,SaySo.class);

有时您可能不想在OptionGroup中使用所有枚举的实例值。如果是,请使用中解释的隐式方法提取这些实例的集合这个问题。删除不需要的。注意我们如何从 Arrays.asList 的输出中实例化一个新的 ArrayList ,以允许此修改。然后将该集合传递给另一个构造函数 EnumBackedOptionGroup



您可以传递null作为最后一个参数,以使用 toString 作为演示文稿标签。



您可能可以使用 EnumMap EnumSet ,而不是 .values ,但我没有经验。

 集合&T> enumValues = new ArrayList(Arrays.asList(SaySo.values())); 
enumValues.remove(SaySo.MAYBE);
OptionGroup optionGroup = new EnumBackedOptionGroup< SaySo>(Says you:,SaySo.class,null);



自行转载



想像一下这个 CRITTER_FILTER 枚举嵌套在 SomeClass

  public enum CRITTER_FILTER 
{

CANINE(Dogs),//将要显示的文本作为单选按钮的标题(标签)传递给用户。
FELINE(猫),
COCKATIEL(Cockatiel鸟);

private String title;

CRITTER_FILTER(String t)
{
this.title = t;
}

//为更灵活的方法添加此方法。
// JavaBeansgetter用于BeanItemContainer。
public String getTitle()
{
return this.title;
}

//为简单的方法添加此方法。
@Override
public String toString()
{
return this.title;
}

}

添加构造函数使我们能够通过在每个枚举实例中显示所需的显示文本,然后将该文本存储在私有成员String变量中。



简单方法



如果在确定显示文本中没有任何花哨的工作,只需覆盖 toString 方法返回存储的显示文本。



我不是推荐这种方法。 文档建议覆盖 toString 只有在创建一个特殊值才能显示给程序员的调试工作中。但是,我确实尝试了这种方法,它的工作正常。


public String toString()



...此方法可能会被覆盖,但通常不是必需或不可取的。枚举类型应该覆盖此方法,当一个更程序员友好的字符串形式存在。




  this.filterRadios = new OptionGroup(Filter:,Arrays.asList(SomeClass.CRITTER_FILTER.values())); //通过调用实用程序方法Arrays.asList将枚举实例(值)的普通数组转换成Collection对象。 
this.filterRadios.setMultiSelect(false); //单选按钮是单选。



toString的完整示例方法



A Person class,带有嵌套枚举。

  package com.example.vaadinradiobuttons; 

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

/ **
*
* @author Basil Bourque
* /
public class Person {

// Members
字符串名称;
Person.VITAL_STATUS vitalStatus;

public enum VITAL_STATUS {

LIVING(Alive and Kicking),
DECEASED(Dead),
UNKNOWN(DUNNO) ;

private String captionText;

VITAL_STATUS(String t){
this.captionText = t;
}

@Override
public String toString(){
return this.captionText;
}

}

//构造函数
public Person(String nameArg,VITAL_STATUS vitalStatusArg){
this.name = nameArg;
this.vitalStatus = vitalStatusArg;
}

}

还有一个小小的Vaadin 7.4。 3应用程序使用该嵌套枚举来填充选项组。查找 //核心示例。查看重要行。

  package com.example.vaadinradiobuttons; 

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.Widgetset;
import com.vaadin.data.Property;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import java.util.Arrays;
import java.util.Collection;

/ **
*
* /
@Theme(mytheme)
@Widgetset(com.example.vaadinradiobuttons.MyAppWidgetset)
public class MyUI extends UI {

@Override
protected void init(VaadinRequest vaadinRequest){
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);

//核心的例子。
集合< Person.VITAL_STATUS> v = Arrays.asList(Person.VITAL_STATUS.values());
OptionGroup radios = new OptionGroup(Vital Status:,v);
radios.setImmediate(true);
radios.addValueChangeListener((Property.ValueChangeEvent事件) - > {
Person.VITAL_STATUS vitalStatus =(Person.VITAL_STATUS)event.getProperty()。getValue();
System.out。 println(User selected a vital status name:+ vitalStatus.name()+,标有:+ vitalStatus.toString());
});
layout.addComponent(radioos);



@WebServlet(urlPatterns =/ *,name =MyUIServlet,asyncSupported = true)
@VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet扩展VaadinServlet {
}
}



更灵活的方法



请注意在上面的枚举中添加了 getTitle 方法。您可以使用任何您想要的方法名称,除了 getName 名称 已被定义为Java中枚举的一部分。 >

创建一个BeanItemContainer,填写我们枚举的实例,并告诉Vaadin提供显示文本的属性(用于反射寻找匹配的getter方法)的名称。 / p>

除了更灵活,根据文档对 toString 的注意事项,这种方法可能会更加明智。

  BeanItemContainer< SomeClass.CRITTER_FILTER> radiosBic = new BeanItemContainer< SomeClass.CRITTER_FILTER>(SomeClass.CRITTER_FILTER.class); 
radiosBic.addAll(Arrays.asList(SomeClass.CRITTER_FILTER.values())); //将值的数组转换为Collection对象。
this.filterRadios = new OptionGroup(Critter Filter:,radiosBic);
this.filterRadios.setMultiSelect(false); //单选按钮是单选。
this.filterRadios.setItemCaptionMode(AbstractSelect.ItemCaptionMode.PROPERTY);
this.filterRadios.setItemCaptionPropertyId(title); //匹配定义为枚举一部分的getter方法。

有效。我希望它可以在Vaadin 6和7中工作。



BeanItemContainer 方法



我们来调整 Person 和Vaadin应用程序的示例。



Person 类中,使用JavaBeans Property getter替换 toString 方法, getCaptionText 。该方法的名称可以是任何东西,只要它符合以下Vaadin应用程序中的 setItemCaptionPropertyId 的调用。

  package com.example.vaadinradiobuttons; 

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

/ **
*
* @author Basil Bourque
* /
public class Person {

// Members
字符串名称;
Person.VITAL_STATUS vitalStatus;

public enum VITAL_STATUS {

LIVING(Alive and Kicking),
DECEASED(Dead),
UNKNOWN(DUNNO) ;

private String captionText;
static public String CAPTION_TEXT_PROPERTY_NAME =captionText; //

VITAL_STATUS(String t){
this.captionText = t;
}

// JavaBeans属性getter。
public String getCaptionText(){
return this.captionText;
}

}

//构造函数
public Person(String nameArg,VITAL_STATUS vitalStatusArg){
this.name = nameArg;
this.vitalStatus = vitalStatusArg;
}

}

Vaadin应用更改为使用一个 BeanItemContainer 。通过调用 setItemCaptionPropertyId ,您可以指定该容器中的哪些属性应用作要显示的文本。

  package com.example.vaadinradiobuttons; 

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.Widgetset;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import java.util.Arrays;
import java.util.Collection;

/ **
*
* /
@Theme(mytheme)
@Widgetset(com.example.vaadinradiobuttons.MyAppWidgetset)
public class MyUI extends UI {

@Override
protected void init(VaadinRequest vaadinRequest){
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);

//核心的例子。
集合< Person.VITAL_STATUS> v = Arrays.asList(Person.VITAL_STATUS.values());
BeanItemContainer< Person.VITAL_STATUS> bic = new BeanItemContainer<>(Person.VITAL_STATUS.class,v);
OptionGroup radios = new OptionGroup(Vital Status,bic);
radios.setItemCaptionPropertyId(Person.VITAL_STATUS.CAPTION_TEXT_PROPERTY_NAME); // ...或...(captionText);
radios.setImmediate(true);
radios.addValueChangeListener((Property.ValueChangeEvent事件) - > {
Person.VITAL_STATUS vitalStatus =(Person.VITAL_STATUS)event.getProperty()。getValue();
System.out。 println(User selected a vital status name:+ vitalStatus.name()+,标有:+ vitalStatus.toString());
});
layout.addComponent(radioos);



@WebServlet(urlPatterns =/ *,name =MyUIServlet,asyncSupported = true)
@VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public static class MyUIServlet扩展VaadinServlet {
}
}


I have a Java enum with a getter for the desired display text. How can I use this to populate an OptionGroup in Vaadin 7?

解决方案

Here are three ways to do this in Vaadin 7:

  • A class I built, EnumBackedOptionGroup. A subclass of OptionGroup in Vaadin 7.
  • Roll-your-own the short sweet way.
  • Roll-your-own the more flexible way.

Subclass of OptionGroup

Here is the source code of a new subclass of OptionGroup I wrote.

package com.basilbourque;

import com.vaadin.ui.OptionGroup;
import java.util.Arrays;
import java.util.Collection;
import java.util.function.Function;
import org.slf4j.LoggerFactory;

/**
 * A subclass of the Vaadin 7 OptionGroup (radio buttons or bunch of checkboxes) widget, taking as its set of options
 * the instances of an Enum.
 *
 * In canonical usage, pass the class of your Enum and a reference to the method to be called for obtaining a textual
 * label for display to the user.
 *
 * Alternatively, if your Enum overrides the `toString` method, you may pass only the class of the Enum without a
 * Function. This approach is not recommended per the class documentation which explains `toString` should only be used
 * for debugging message. Nevertheless, some people override `toString` to provide a user-readable label, so we support
 * this.
 *
 * Even if your Enum does not override `toString` you may choose to omit passing the Function argument. As a default,
 * the Enum’s built-in `toString` method will be called, returning the "name" of the Enum’s instance. This is handy for
 * quick-and-dirty prototyping. Again, neither I nor the class doc recommend this approach for serious work.
 *
 * If you want to display a subset of your enum’s instances rather than all, pass a Collection.
 *
 * This source code available under terms of ISC License.  https://en.wikipedia.org/wiki/ISC_license
 * 
 * Copyright (c) 2015, Basil Bourque
 * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
 * granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS
 * PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * @author Basil Bourque
 * @version 2015-08-27T21:00:00Z
 * @since 2015-08-27T21:00:00Z
 */
public class EnumBackedOptionGroup<T extends Enum> extends OptionGroup
{

    final org.slf4j.Logger logger = LoggerFactory.getLogger( this.getClass() );

    /**
     * Constructor. The usual constructor for automatically detecting all the instances of an enum for use as the
     * options in a Vaadin 7 OptionGroup. Pass a function to be called for providing each option’s displayed labeling.
     *
     * Example usage:
     *
     * myRadios = new EnumBackedOptionGroup<DogBreed>( "Choose breed:" , DogBreed.class , DogBreed :: getTitle );
     *
     * @param caption
     * @param enumClass
     * @param f
     */
    public EnumBackedOptionGroup ( final String caption , final Class<T> enumClass , final Function<T , String> f ) {
        super( caption );
        Function<T , String> func = f;
        // If passed a null for the Function, fallback to using 'toString'.
        if ( func == null ) {
            func = T -> T.toString();
        }
        this.buildAndAssignCaptions( enumClass , func );
    }

    /**
     * Constructor. Similar to usual constructor, but here you may additionally pass a Collection of the subset of Enum
     * instances.
     *
     * For use where business logic dictates that you give only some of the Enum values an options rather than all of
     * them. The omitted options are effectively hidden from the user.
     *
     * @param caption
     * @param enumClass
     * @param enumValues
     * @param f
     */
    public EnumBackedOptionGroup ( final String caption , final Class<T> enumClass , final Collection<T> enumValues , final Function<T , String> f ) {
        super( caption );
        Function<T , String> func = f;
        // If passed a null for the Function, fallback to using 'toString'.
        if ( func == null ) {
            func = T -> T.toString();
        }
        Collection<T> ev = enumValues;
        // Handle where calling method passed us a null or empty collection.
        if ( ( ev == null ) || ev.isEmpty() ) {
            this.buildAndAssignCaptions( enumClass , f ); // Fallback to assiging all the instances of enum as options in our OptionGroup.
        } else {
            this.addItems( enumValues );  // Add the passed subset of instances of the enum as items backing our OptionGroup.
            this.assignCaptions( enumValues , f );
        }
    }

    /**
     * Constructor. Similar to the usual constructor, but omits the method for providing on-screen labeling. Instead
     * uses the 'toString' method defined either explicitly in the Enum subclass or implicitly calls to the Enum class’
     * own 'toString'.
     *
     * Not recommended, as the Enum documentation strongly suggests the 'toString' method on an Enum be used only for
     * debugging. Nevertheless this is handy for quick-and-dirty prototyping.
     *
     * @param caption
     * @param enumClass
     */
    public EnumBackedOptionGroup ( final String caption , final Class<T> enumClass ) {
        super( caption );
        // User passed no Function to call for getting the title. So fallback to using 'toString'.
        this.buildAndAssignCaptions( enumClass , T -> T.toString() );
    }

    // Helper method. (sub-routine)
    // Extracts all the instances of the enum, and uses them as options in our OptionGroup.
    // Also assigns each option a labeling using String returned by passed method to be called for each instance of enum.
    private void buildAndAssignCaptions ( final Class<T> enumClass , final Function<T , String> f ) {
        if ( enumClass.isEnum() ) {  // This check may be unnecessary with Generics code "<T extends Enum>" at top of this class.
            Collection<T> enumValues = Arrays.asList( enumClass.getEnumConstants() );
            this.addItems( enumValues );  // Add all the instances of the enum as items backing our OptionGroup.
            this.assignCaptions( enumValues , f );
        } else {
            // Else the passed class is not an enum.
            // This case should not be possible because of the Generics marked on this class "<T extends Enum>".
            logger.error( "Passed a class that is not a subclass of Enum. Message # f2098672-ab47-47fe-b720-fd411411052e." );
            throw new IllegalArgumentException( "Passed a class that is not a subclass of Enum." );
        }
    }

    // Helper method. (sub-routine)
    // Assigns each option a labeling using String returned by passed method to be called for each instance of enum
    private void assignCaptions ( Collection<T> enumValues , final Function<T , String> f ) {
        for ( T option : enumValues ) {
            // For each option in our OptionGroup, determine and set its title, the label displayed for the user next to each radio button or checkbox.
            // To determine the label (the second argument), we invoke the passed method which must return a String. Using Lambda syntax.
            this.setItemCaption( option , f.apply( option ) );
        }
    }

}

I expect you would use with an enum like this one, DogBreed. Note how this enum has a constructor in which we pass the text to be used as a label for presentation to the user. We added a method getTitle to retrieve this titling text.

package com.example;

/**
 * Bogus example Enum.
 */
public enum DogBreed {

    AUSSIE("Australian Shepherd") ,
    BORDER_COLLIE("Border Collie"),
    BLACK_LAB("Labrador, Black"),
    MUTT("Mixed Breed");

    private String title = null;

    DogBreed ( final String titleArg) {
        this.title = titleArg;
    }

    public String getTitle() {
        return this.title;
    }

}

I was only able to accomplish that class thanks to this Answer by WillShackleford on my Question, Lambda syntax to pass and invoke a method reference.

To use this EnumBackedGroupOption class, pass its class and a method reference for that title-rendering method. This requires the new Lambda syntax in Java 8. But no need to have yet mastered your understanding of Lambda yet, just follow the pattern you see here.

OptionGroup optionGroup = new EnumBackedOptionGroup<DogBreed>( "Choose Breed:" , DogBreed.class , DogBreed :: getTitle );

For quick-and-dirty prototyping, you can define a simple enum with no such constructor and getter. Pass just your caption and the enum class in this case. The EnumBackedOptionGroup class falls back to using the built-in toString method. Neither I nor the Enum class doc recommend this route for serious work where toString should be used only for debugging.

package com.example;

/**
 * Bogus example Enum.
 */
public enum SaySo {

    YES, NO, MAYBE;
}

OptionGroup optionGroup = new EnumBackedOptionGroup<SaySo>( "Says you:" , SaySo.class );

Occasionally you may not want to use all of the enum’s instance values in your OptionGroup. If so, extract a Collection of those instances, using the implicit method values explained in this Question. Remove the unwanted ones. Note how we instantiated a fresh ArrayList from output of Arrays.asList to allow this modification. Then pass that collection to another constructor of EnumBackedOptionGroup.

You can pass null as the last argument to fall back on using toString as the presentation labeling.

You might be able to use either an EnumMap or EnumSet instead of .values, but I have no experience with that.

Collection<T> enumValues = new ArrayList( Arrays.asList( SaySo.values() ) );
enumValues.remove( SaySo.MAYBE );
OptionGroup optionGroup = new EnumBackedOptionGroup<SaySo>( "Says you:" , SaySo.class , null );

Roll-Your-Own

Imagine this CRITTER_FILTER enum nested in SomeClass.

public enum CRITTER_FILTER
{

    CANINE ( "Dogs" ), // Pass the text to be displayed to user as the radio button’s Caption (label).
    FELINE ( "Cats" ),
    COCKATIEL ( "Cockatiel birds" );

    private String title;

    CRITTER_FILTER ( String t )
    {
        this.title = t;
    }

    // Add this method for the more flexible approach.
    // JavaBeans "getter" for use in BeanItemContainer.
    public String getTitle ()
    {
        return this.title;
    }

    // Add this method for the short simple approach.
    @Override
    public String toString ()
    {
        return this.title;
    }

}

Adding a constructor enables us to pass in to each enum instance the desired display text, and then store that text in a private member String variable.

Short Simple Approach

If there is no fancy work to be done in determining the display text, simply override the toString method to return the stored display text.

I am not recommending this approach. The documentation recommends overriding toString only if you want to create an special value for display to the programmer in debugging work. However, I did try this approach and it does work.

public String toString()

… This method may be overridden, though it typically isn't necessary or desirable. An enum type should override this method when a more "programmer-friendly" string form exists.

this.filterRadios = new OptionGroup( "Filter:" , Arrays.asList( SomeClass.CRITTER_FILTER.values() ) );  // Convert plain array of the enum instances (the values) into a `Collection` object by calling utility method `Arrays.asList`.
this.filterRadios.setMultiSelect( false ); // Radio buttons are single-select.

Full Example Of toString Approach

A Person class, with a nested enum.

package com.example.vaadinradiobuttons;

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

/**
 *
 * @author Basil Bourque
 */
public class Person {

    // Members
    String name;
    Person.VITAL_STATUS vitalStatus;

    public enum VITAL_STATUS {

        LIVING( "Alive and Kicking" ),
        DECEASED( "Dead" ),
        UNKNOWN( "DUNNO" );

        private String captionText;

        VITAL_STATUS ( String t ) {
            this.captionText = t;
        }

        @Override
        public String toString () {
            return this.captionText;
        }

    }

    // Constructor
    public Person ( String nameArg , VITAL_STATUS vitalStatusArg ) {
        this.name = nameArg;
        this.vitalStatus = vitalStatusArg;
    }

}

And a tiny little Vaadin 7.4.3 app using that nested enum to populate an Option Group. Look for the comment // Core of example. to see the important lines.

package com.example.vaadinradiobuttons;

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.Widgetset;
import com.vaadin.data.Property;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import java.util.Arrays;
import java.util.Collection;

/**
 *
 */
@Theme ( "mytheme" )
@Widgetset ( "com.example.vaadinradiobuttons.MyAppWidgetset" )
public class MyUI extends UI {

    @Override
    protected void init ( VaadinRequest vaadinRequest ) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin( true );
        setContent( layout );

        // Core of example.
        Collection<Person.VITAL_STATUS> v = Arrays.asList( Person.VITAL_STATUS.values() );
        OptionGroup radios = new OptionGroup( "Vital Status :" , v );
        radios.setImmediate( true );
        radios.addValueChangeListener( ( Property.ValueChangeEvent event ) -> {
            Person.VITAL_STATUS vitalStatus = ( Person.VITAL_STATUS ) event.getProperty().getValue();
            System.out.println( "User selected a vital status name: " + vitalStatus.name() + ", labeled: " + vitalStatus.toString() );
        } );
        layout.addComponent( radios );

    }

    @WebServlet ( urlPatterns = "/*" , name = "MyUIServlet" , asyncSupported = true )
    @VaadinServletConfiguration ( ui = MyUI.class , productionMode = false )
    public static class MyUIServlet extends VaadinServlet {
    }
}

More Flexible Approach

Note the addition of the getTitle method in our enum above. You can use any method name you want, except getName or name which is already defined as part of an enum in Java.

Create a BeanItemContainer, fill with the instances of our enum, and tell Vaadin the name of the "property" (used to reflectively find a matching getter method) providing the display text.

Besides being more flexible, this approach may be wiser given the doc’s cautions about overriding toString.

BeanItemContainer<SomeClass.CRITTER_FILTER> radiosBic = new BeanItemContainer<SomeClass.CRITTER_FILTER>( SomeClass.CRITTER_FILTER.class );
radiosBic.addAll( Arrays.asList( SomeClass.CRITTER_FILTER.values() ) );  // Convert array of values to a `Collection` object.
this.filterRadios = new OptionGroup( "Critter Filter:" , radiosBic );
this.filterRadios.setMultiSelect( false ); // Radio buttons are single-select.
this.filterRadios.setItemCaptionMode( AbstractSelect.ItemCaptionMode.PROPERTY );  
this.filterRadios.setItemCaptionPropertyId( "title" );  // Matches the getter method defined as part of the enum.

That works. I expect it would work in Vaadin 6 as well as 7.

Full Example Of BeanItemContainer Approach

Let's adjust the example Person and Vaadin app shown in section above.

In the Person class, replace the toString method with a JavaBeans Property getter, getCaptionText. The name of this method can be anything, as long as it matches the call to setItemCaptionPropertyId seen in the Vaadin app further below.

package com.example.vaadinradiobuttons;

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

/**
 *
 * @author Basil Bourque
 */
public class Person {

    // Members
    String name;
    Person.VITAL_STATUS vitalStatus;

    public enum VITAL_STATUS {

        LIVING( "Alive and Kicking" ),
        DECEASED( "Dead" ),
        UNKNOWN( "DUNNO" );

        private String captionText;
        static public String CAPTION_TEXT_PROPERTY_NAME = "captionText";  //

        VITAL_STATUS ( String t ) {
            this.captionText = t;
        }

        // JavaBeans Property getter.
        public String getCaptionText () {
            return this.captionText;
        }

    }

    // Constructor
    public Person ( String nameArg , VITAL_STATUS vitalStatusArg ) {
        this.name = nameArg;
        this.vitalStatus = vitalStatusArg;
    }

}

The Vaadin app is changed to use a BeanItemContainer. With a call to setItemCaptionPropertyId, you specify which of the properties in that container should be used as the text to display.

package com.example.vaadinradiobuttons;

import javax.servlet.annotation.WebServlet;

import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.annotations.Widgetset;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.OptionGroup;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import java.util.Arrays;
import java.util.Collection;

/**
 *
 */
@Theme ( "mytheme" )
@Widgetset ( "com.example.vaadinradiobuttons.MyAppWidgetset" )
public class MyUI extends UI {

    @Override
    protected void init ( VaadinRequest vaadinRequest ) {
        final VerticalLayout layout = new VerticalLayout();
        layout.setMargin( true );
        setContent( layout );

        // Core of example.
        Collection<Person.VITAL_STATUS> v = Arrays.asList( Person.VITAL_STATUS.values() );
        BeanItemContainer<Person.VITAL_STATUS> bic = new BeanItemContainer<>( Person.VITAL_STATUS.class , v );
        OptionGroup radios = new OptionGroup( "Vital Status :" , bic );
        radios.setItemCaptionPropertyId(Person.VITAL_STATUS.CAPTION_TEXT_PROPERTY_NAME );  // …or… ( "captionText" );
        radios.setImmediate( true );
        radios.addValueChangeListener( ( Property.ValueChangeEvent event ) -> {
            Person.VITAL_STATUS vitalStatus = ( Person.VITAL_STATUS ) event.getProperty().getValue();
            System.out.println( "User selected a vital status name: " + vitalStatus.name() + ", labeled: " + vitalStatus.toString() );
        } );
        layout.addComponent( radios );

    }

    @WebServlet ( urlPatterns = "/*" , name = "MyUIServlet" , asyncSupported = true )
    @VaadinServletConfiguration ( ui = MyUI.class , productionMode = false )
    public static class MyUIServlet extends VaadinServlet {
    }
}

这篇关于从Vaadin 7中的枚举中创建OptionGroup(单选按钮)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆