2017-09-13 34 views
0

我在编程方面有点新,对于OOP(第二个Java项目,现在完全不熟悉)并且会喜欢任何提示或帮助。如何增加ToggleGroup(例如RadioButtons)中可能的选择数量?

我目前正在为我自己的笔&纸质游戏开发角色创作程序。我正在使用JavaFX(没有FXML,因此没有SceneBuilder)用于GUI部分。我正在JDK1.8.0_131上使用Eclipse Neon。

这是我的问题:
tl; dr:如何增加ToggleGroup中可能选择的数量?
我即将创建一个供用户选择的选项列表。该名单包含30个不同的优点,他或她可以选择提高他们的品格。所选择的选项的最大值取决于字符,大约在5之间变化。我已经实现了一个pairs(我知道HashMaps)的数组,每个条目都是由优势的名称和代表其成本的整数组成他们的价值,所以在他们的成本)。
列表本身现在应该通过

ScrollPane scrollAdv = new ScrollPane(); 
VBox vBoxAdv = new VBox(); 
scrollAdv.setContent(vBoxAdv); 
Pair<String, Integer>[] listAdv = info.getAdvantages(); 
for (int i = 0; i < listAdv.length; i++) { 
    String name = listAdv[i].getKey(); // delivers the 1st entry of a pair 
    int costs = listAdv[i].getValue(); // delivers the 2nd entry of a pair 
    ToggleButton toggleButton = new ToggleButton(); 
    toggleButton.setUserData(name); 
    toggleButton.setText(name + " (" + costs + ")"); 
    vBoxAdv.getChildren().add(toggleButton); 
} 

请注意,我没有太在意的ToggleButtons实施,他们可以很容易地与单选按钮代替。如果我正确理解文档,两者的工作方式都是相同的。他们都使用ToggleGroup确保,只有一个选项被选中。
因此,尽管您现在可能已经猜到了,但我想要做的是让用户一次选择多个选项。我不想这样做,因此用户必须在另一个选项之后选择一个选项,同时重置其间的列表。

感谢您的阅读并提前感谢您的任何帮助或提示。

编辑:我总是可以添加一个计数器,只要选择了一个选项或取消选择,就可以刷新计数器,并阻止任何选择,但我认为应该有一个更好的解决方案。增加了ToggleGroup似乎正在使用的内置限制1。

+0

所以你希望用户能够选择一些切换按钮(或类似的),但达到一定的限制?因此,例如,他们可以选择30个中的0-5个(但不超过5个)。这是对问题的正确解释吗? –

+0

@James_D是的,这是完全正确的。 –

回答

1

一种方法是在达到限制时禁用其余的切换。这里有一个ToggleSet的类,它是:

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

import javafx.beans.Observable; 
import javafx.beans.binding.Bindings; 
import javafx.beans.binding.IntegerBinding; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.collections.transformation.FilteredList; 
import javafx.scene.Node ; 
import javafx.scene.control.Toggle; 

public class ToggleSet<T extends Node & Toggle> { 

    private final ObservableList<T> toggles = FXCollections.observableArrayList(t -> new Observable[] {t.selectedProperty()}); 
    private final FilteredList<T> selectedToggles = toggles.filtered(t -> ((Toggle)t).isSelected()); 
    private final IntegerProperty maximumSelectable = new SimpleIntegerProperty(0); 

    private final IntegerBinding numSelected = Bindings.size(selectedToggles); 

    public ToggleSet(int maximumSelectable) { 

     this.maximumSelectable.addListener((obs, oldMax, newMax) -> { 
      if (newMax.intValue() < numSelected.get()) { 
       List<Toggle> togglesToClear = new ArrayList<>(selectedToggles.subList(0, numSelected.get() - newMax.intValue())); 
       togglesToClear.forEach(t -> t.setSelected(false)); 
      } 
     }); 

     setMaximumSelectable(maximumSelectable); 
    } 

    public ToggleSet() { 
     this(0); 
    } 

    public ObservableList<T> getSelectedToggles() { 
     return FXCollections.unmodifiableObservableList(selectedToggles) ; 
    } 

    public IntegerProperty maximumSelectableProperty() { 
     return maximumSelectable ; 
    } 

    public final int getMaximumSelectable() { 
     return maximumSelectableProperty().get(); 
    } 

    public final void setMaximumSelectable(int maximumSelectable) { 
     maximumSelectableProperty().set(maximumSelectable); 
    } 

    public void addToggle(T toggle) { 
     if (numSelected.get() >= getMaximumSelectable()) { 
      toggle.setSelected(false); 
     } 
     toggles.add(toggle); 
     toggle.disableProperty().bind(toggle.selectedProperty().not().and(numSelected.greaterThanOrEqualTo(maximumSelectable))); 
    } 

    public void removeToggle(T toggle) { 
     toggles.remove(toggle); 
     toggle.disableProperty().unbind(); 
    } 

} 

下面是一个例子测试它:

import javafx.application.Application; 
import javafx.geometry.Insets; 
import javafx.scene.Scene; 
import javafx.scene.control.CheckBox; 
import javafx.scene.control.Label; 
import javafx.scene.control.RadioButton; 
import javafx.scene.control.Spinner; 
import javafx.scene.control.ToggleButton; 
import javafx.scene.layout.GridPane; 
import javafx.scene.layout.HBox; 
import javafx.stage.Stage; 

public class ToggleSetTest extends Application { 

    @Override 
    public void start(Stage primaryStage) { 
     ToggleSet<ToggleButton> toggleSet = new ToggleSet<>(5); 
     GridPane grid = new GridPane() ; 

     Spinner<Integer> maxSelectedSpinner = new Spinner<>(0, 20, 5); 
     maxSelectedSpinner.getValueFactory().valueProperty().bindBidirectional(toggleSet.maximumSelectableProperty().asObject()); 

     grid.add(new HBox(2, new Label("Maximum selected"), maxSelectedSpinner), 0, 0, 2, 1); 

     grid.addRow(1, new Label("Selection"), new Label("Include in set")); 

     for (int i = 1; i <= 20 ; i++) { 
      RadioButton button = new RadioButton("Button "+i); 
      CheckBox checkBox = new CheckBox(); 
      checkBox.selectedProperty().addListener((obs, wasChecked, isNowChecked) -> { 
       if (isNowChecked) { 
        toggleSet.addToggle(button); 
       } else { 
        toggleSet.removeToggle(button); 
       } 
      }); 
      checkBox.setSelected(true); 
      grid.addRow(i + 1, button, checkBox); 
     } 
     grid.setPadding(new Insets(10)); 
     grid.setHgap(5); 
     grid.setVgap(2); 
     Scene scene = new Scene(grid); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

如果你想在相同的行为ToggleGroup,其中前面的选择变得未选中,这是一个有点麻烦,但下面应该工作:

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

import javafx.beans.Observable; 
import javafx.beans.property.IntegerProperty; 
import javafx.beans.property.Property; 
import javafx.beans.property.SimpleIntegerProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.scene.Node ; 
import javafx.scene.control.Toggle; 

public class ToggleSet<T extends Node & Toggle> { 

    private final ObservableList<T> toggles = FXCollections.observableArrayList(t -> new Observable[] {t.selectedProperty()}); 
    private final ObservableList<T> selectedToggles = FXCollections.observableArrayList(); 
    private final IntegerProperty maximumSelectable = new SimpleIntegerProperty(0); 

    private final ChangeListener<Boolean> toggleListener = (obs, wasSelected, isNowSelected) -> { 
     @SuppressWarnings("unchecked") 
     T toggle = (T) ((Property<?>)obs).getBean(); 
     if (isNowSelected) { 
      selectedToggles.add(toggle); 
      ensureWithinMax(); 
     } else { 
      selectedToggles.remove(toggle); 
     } 
    }; 

    public ToggleSet(int maximumSelectable) { 

     this.maximumSelectable.addListener((obs, oldMax, newMax) -> ensureWithinMax()); 
     setMaximumSelectable(maximumSelectable); 
    } 

    private void ensureWithinMax() { 
     if (this.maximumSelectable.get() < selectedToggles.size()) { 
      List<Toggle> togglesToClear = new ArrayList<>(selectedToggles.subList(0, selectedToggles.size() - this.maximumSelectable.get())); 
      togglesToClear.forEach(t -> t.setSelected(false)); 
     } 
    } 

    public ToggleSet() { 
     this(0); 
    } 

    public ObservableList<T> getSelectedToggles() { 
     return FXCollections.unmodifiableObservableList(selectedToggles) ; 
    } 

    public IntegerProperty maximumSelectableProperty() { 
     return maximumSelectable ; 
    } 

    public final int getMaximumSelectable() { 
     return maximumSelectableProperty().get(); 
    } 

    public final void setMaximumSelectable(int maximumSelectable) { 
     maximumSelectableProperty().set(maximumSelectable); 
    } 

    public void addToggle(T toggle) { 
     if (toggle.isSelected()) { 
      selectedToggles.add(toggle); 
      ensureWithinMax(); 
     } 
     toggle.selectedProperty().addListener(toggleListener); 
     toggles.add(toggle); 
    } 

    public void removeToggle(T toggle) { 
     toggle.selectedProperty().removeListener(toggleListener); 
     toggles.remove(toggle); 
    } 

} 

(使用相同的测试代码。)

+0

哇谢谢一堆!这工作非常好,感觉平稳。我要使用它的大部分内容! –

相关问题