Skip to content

Instantly share code, notes, and snippets.

@nodamushi
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nodamushi/1bac56d339d62a1631c2 to your computer and use it in GitHub Desktop.
Save nodamushi/1bac56d339d62a1631c2 to your computer and use it in GitHub Desktop.
an utility class of ToggleButton
package nodamushi.jfx.util;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.RadioButton;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
/**
* 複数のToggleButtonを簡単に扱うためのユーティリティ。
* 選択されているToggleは番号(インデックス)で管理される。
* @author nodamushi
*
*/
public class ToggleButtons{
public ToggleButtons(){
final InvalidationListener bind = new InvalidationListener(){
boolean b = true;
@Override
public void invalidated(final Observable o){
if(b){
b = false;
if( o == selectedProperty){
final int s = getSelected();
if(buttons.size()<=s){
setSelected(-1);
}else{
final Toggle t = buttons.get(getSelected());
t.setSelected(true);
}
}else{
final int i = buttons.indexOf(group.getSelectedToggle());
setSelected(i);
}
b = true;
}
}
};
group.selectedToggleProperty().addListener(bind);
selectedProperty.addListener(bind);
buttons.addListener(new ListChangeListener<ToggleButton>(){
@Override
public void onChanged(final Change<? extends ToggleButton> c){
while(c.next()){
if(c.wasPermutated()) {
continue;
}
if(c.wasRemoved()){
for(final ToggleButton t:c.getRemoved()){
if(t.getToggleGroup()==group){
t.setToggleGroup(null);
}
}
}
if(c.wasAdded()){
final List<String> sC=styleClass;
for(final ToggleButton t:c.getAddedSubList()){
t.setToggleGroup(group);
final ObservableList<String> sc = t.getStyleClass();
for(final String s:sC){
if(!sc.contains(s)){
sc.add(s);
}
}
}//end for ToggleButton
}//end if c.wasAdded
}//end while
final Toggle s = group.getSelectedToggle();
final int i = buttons.indexOf(s);
final int si = getSelected();
if(i!=si){
setSelected(i);
}
}});
styleClass.addListener(new ListChangeListener<String>(){
@Override
public void onChanged(final Change<? extends String> c){
while(c.next()){
if(c.wasPermutated()) {
continue;
}
if(c.wasRemoved()){
final List<? extends String> removed = c.getRemoved();
for(final ToggleButton t:buttons){
t.getStyleClass().removeAll(removed);
}
}
if(c.wasAdded()){
final List<? extends String> added = c.getAddedSubList();
for(final ToggleButton t:buttons){
t.getStyleClass().addAll(added);
}
}
}
}});
}
/**
* 保持しているToggleButtonのリスト
* @return
*/
public ObservableList<ToggleButton> getToggleButtons(){
return buttons;
}
/**
* ToggleButtonに付加するStleClass名のリスト
* @return
*/
public ObservableList<String> getStyleClass(){
return styleClass;
}
/**
* ToggleButtonに付加するStleClass名を追加する
* @param name
*/
public void addStyleClass(final String name){
styleClass.add(name);
}
/**
* ToggleButtonのリストと渡されたlistの内容を束縛する
* @param list
* @see ToggleButtons#getToggleButtons()
* @see Bindings#bindContent(List, ObservableList)
*/
public void bindContent(final List<? super ToggleButton> list){
Bindings.bindContent(list, buttons);
}
/**
* RadioButtonを生成する
* @param text
*/
public void createItem(final String text){
final RadioButton r = new RadioButton(text);
buttons.add(r);
}
/**
* graphicに画像を持つRadioButtonを生成する
* @param text
* @param image
*/
public void createItem(final String text,final Image image){
if(image !=null){
createItem(text,new ImageView(image),ContentDisplay.BOTTOM,Pos.TOP_LEFT);
}else{
createItem(text);
}
}
/**
* graphicに画像を持つRadioButtonを生成する
* @param text
* @param imageStream 画像データ
*/
public void createItem(final String text,final InputStream imageStream){
if(imageStream!=null){
final Image img = new Image(imageStream);
createItem(text,img);
}else{
createItem(text);
}
}
/**
* graphicに画像を持つRadioButtonを生成する
* @param text
* @param imagePath 画像のパス
* @throws IOException imagePathを開けなかった場合
*/
public void createItem(final String text,final String imagePath) throws IOException{
try(InputStream in = Files.newInputStream(Paths.get(imagePath));){
createItem(text, in);
}
}
/**
* graphicを指定してRadioButtonを生成する
* @param text
* @param graphic
* @param display
* @see RadioButton#setGraphic(Node)
* @see RadioButton#setContentDisplay(ContentDisplay)
*/
public void createItem(final String text,final Node graphic,final ContentDisplay display){
createItem(text, graphic, display,null);
}
/**
* graphicを指定してRadioButtonを生成する
* @param text
* @param graphic
* @param display
* @param alignment
* @see RadioButton#setGraphic(Node)
* @see RadioButton#setContentDisplay(ContentDisplay)
* @see RadioButton#setAlignment(Pos)
*/
public void createItem(final String text,final Node graphic,final ContentDisplay display,final Pos alignment){
final RadioButton r = new RadioButton(text);
if(graphic!=null){
r.setGraphic(graphic);
if(display!=null){
r.setContentDisplay(display);
}
if(alignment!=null){
r.setAlignment(alignment);
}
}
buttons.add(r);
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したTilePaneを生成します
* @param hgap
* @param vgap
* @return
*/
public TilePane asTilePane(final double hgap,final double vgap){
final TilePane p = new TilePane(hgap, vgap);
bindContent(p.getChildren());
return p;
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したTilePaneを生成します。
* hgap,vgapは10とします。
* @return
*/
public TilePane asTitlePane(){
return asTilePane(10, 10);
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したFlowPaneを生成します
* @param hgap
* @param vgap
* @return
*/
public FlowPane asFlowPane(final double hgap,final double vgap){
final FlowPane p = new FlowPane(hgap, vgap);
bindContent(p.getChildren());
return p;
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したTilePaneを生成します。
* hgap,vgapは10とします。
* @return
*/
public FlowPane asFlowPane(){
return asFlowPane(10,10);
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したVBoxを生成します
* @param spacing
* @return
*/
public VBox asVBox(final double spacing){
final VBox p = new VBox(spacing);
bindContent(p.getChildren());
return p;
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したVBoxを生成します。
* spacingは10とします。
* @return
*/
public VBox asVBox(){
return asVBox(10);
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したHBoxを生成します
* @param spacing
* @return
*/
public HBox asHBox(final double spacing){
final HBox p = new HBox(spacing);
bindContent(p.getChildren());
return p;
}
/**
* 子要素をこのインスタンスが持つToggleButtonのリストに束縛したHBoxを生成します。
* spacingは10とします
* @return
*/
public HBox asHBox(){
return asHBox(10);
}
private ToggleGroup group = new ToggleGroup();
private ObservableList<ToggleButton> buttons = FXCollections.observableArrayList();
private ObservableList<String> styleClass = FXCollections.observableArrayList();
/**
* 選択されているToggleButtonのインデックス
* @return 現在選択されているToggleButtonのインデックス。選択されていないときは-1。
*/
public final IntegerProperty selectedProperty(){
return selectedProperty;
}
public final int getSelected(){
return selectedProperty.get();
}
public final void setSelected(final int value){
selectedProperty.set(value);
}
private final IntegerProperty selectedProperty= new SimpleIntegerProperty(this, "selected", -1){
@Override
public void set(final int newValue){
if(newValue < -1 || buttons.size() <= newValue) {
return;
}
super.set(newValue);
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment