How to enable a JButton on a condition? - java

I'm trying to create a JButton that enables when certain conditions are met. The program sets setEnabled(false) as initial value, but after an update, it should be setEnabled(true).
I tried several things. Here some code:
public class SwimAction extends AbstractAction {
private final PoolModel poolModel;
private final Swimmer swimmer;
public SwimAction(PoolModel poolModel, Swimmer swimmer) {
super("GO!");
this.poolModel = poolModel;
this.swimmer = swimmer;
// default
setEnabled(false);
}
I tried the following:
// Replaced the setEnabled(false) by setEnabled(checkGo())
public boolean checkGo(){
return(pool.isNotOccupied());
}
// Overwrite setEnabled
#Overwrite
public void setEnabled(boolean bool){
boolean oldBool = this.enabled;
if (oldBool != bool && pool.isNotOccupied()) {
this.enabled = bool;
this.firePropertyChange("enabled", oldBool, bool);
}
}
However, none of them worked. Anyone knows how to enable the button when a certain condition (pool.isNotOccupied()) is met?

Seems like you need to listener for a change in the state of the pool object's occupied property, and the best way to do this is to give it a listener of some sort. This could be as simple as a ChangeListener or perhaps better, a PropertyChangeListener. The details of the best solution would likely depend much on the structure of your program, of the rest of the code that we can't see, but, if PoolModel is what you're listening to, what if you gave it...
public class PoolModel {
public static final String OCCUPIED = "occupied";
private PropertyChangeSupport propChangeSupport = new PropertyChangeSupport(this);
private boolean occupied;
public void addPropertyChangeListener(PropertyChangeListener l) {
propChangeSupport.addPropertyChangeListener(l);
}
// also have a remove listener
public boolean isOccupied() {
return occupied;
}
public void setOccupied(boolean occupied) {
boolean oldValue = this.occupied;
boolean newValue = occupied;
this.occupied = occupied;
propChangeSupport.firePropertyChange(OCCUPIED, oldValue, newValue);
}
// ......
And then in the code that uses it:
poolModel.addPropertyChangeListener(pcEvent -> {
if (pcEvent.getPropertyName().equals(OCCUPIED)) {
setEnabled((boolean) pcEvent.getNewValue());
}
});

Related

JavaFX: Custom Equals Method Causes No Refresh in TableView

Here's the situation: I have an ObservableSet (because the ID field for my data must be unique) that has a listener. That listener updates an ObservableList. That ObservableList is, in turn, listened to by a TableView. (According to the comments, this is all necessary because ObservableSet can't be used to back a TableView in JavaFX.)
What we're finding, however, is that doing multiple add operations to the Set don't trigger the refresh of the TableView.
This works fine for:
Initial list population
Duplicate set entries (the listener isn't triggered, that's the intended behavior)
However, editing the value, the TableView will only trigger if there's a single add statement (in the example below, commenting out markStructure.add(new MarkStructureItem(2, 15)); makes it work fine, but then you only have a single value). If there's more than one, the TableView doesn't refresh.
This can be worked around by adding a manual refresh at the end of the Listener class (tblTable.refresh()). This is actually how it's functioned up until now, but development now requires the removal of that.
Any idea what's going on? Why is the listener on the TableView not getting triggered for subsequent adds? The data IS being put into the Set and List, that much has been determined; it's just not triggering a refresh.
Code example (not production, but a POC I put together to test and get answers):
public class TestController implements Initializable {
ObservableSet<MarkStructureItem> markStructure = FXCollections.observableSet();
ObservableList<MarkStructureItem> listMarkStructure = FXCollections.observableArrayList();
#FXML
private Pane root;
#FXML
private TableView<MarkStructureItem> tblTable;
#FXML
private TableColumn<MarkStructureItem, Integer> col1;
#FXML
private TableColumn<MarkStructureItem, Integer> col2;
#FXML
private Button btnButton;
private void resetAll() {
markStructure.clear();
markStructure.add(new MarkStructureItem(1, 25));
markStructure.add(new MarkStructureItem(2, 15));
}
#FXML
private void handleButtonAction(ActionEvent event) throws IOException {
Object source = event.getSource();
Button btnSource = (Button) source;
Stage stage = (Stage) root.getScene().getWindow();
switch (btnSource.getId()) {
case "btnButton": {
resetAll();
break;
}
}
}
class MarksUpdater<MarkStructureItem extends configurationeditor.MarkStructureItem> implements SetChangeListener {
#Override
public void onChanged(Change change) {
if (change.wasRemoved()) {
listMarkStructure.remove(change.getElementRemoved());
} else if (change.wasAdded()) {
MarkStructureItem newMarks = (MarkStructureItem) change.getElementAdded();
listMarkStructure.add(newMarks);
}
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
markStructure.addListener(new MarksUpdater<MarkStructureItem>());
col1.setCellValueFactory(
new PropertyValueFactory<MarkStructureItem, Integer>("id")
);
col2.setCellValueFactory(
new PropertyValueFactory<MarkStructureItem, Integer>("marks")
);
col2.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
col2.setOnEditCommit(
new EventHandler<CellEditEvent<MarkStructureItem, Integer>>() {
#Override
public void handle(CellEditEvent<MarkStructureItem, Integer> t) {
((MarkStructureItem) t.getTableView().getItems().get(
t.getTablePosition().getRow())
).setMarks(t.getNewValue());
}
}
);
tblTable.setItems(listMarkStructure);
resetAll();
}
}
markStructure class:
public class MarkStructureItem {
final SimpleIntegerProperty marks;
final SimpleIntegerProperty id;
#Override
public int hashCode() {
return this.getId().hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj.getClass() == this.getClass()) {
MarkStructureItem thisObj = (MarkStructureItem) obj;
return thisObj.getId() == this.getId();
}
return false;
}
public MarkStructureItem(Integer finishPosition, Integer marks) {
this.marks = new SimpleIntegerProperty(marks);
this.id = new SimpleIntegerProperty(finishPosition);
}
public Integer getId() {
return id.get();
}
public void setMarks(Integer value) {
marks.set(value);
}
public Integer getMarks() {
return marks.get();
}
public void setId(Integer value) {
id.set(value);
}
}
Issue 1:
Your equals implementation is not null-safe and you're comparing the Integers using reference equality (==) instead of equals. This will probably work as long as you're inside the range of cached values and use autoboxing, but cease to work outside that range (this range is only guarantied to be -128 to 127, see Integer.valueOf(int)).
Since you're using the Object in a Set, I recommend making the id unmodifiable anyways. Otherwise you need to remove the value from the set before modifying it and adding it back to the Set (the hash code changes), which would mess up the order in the list unless you temporarily prevent the SetChangeListener from updating the list.
Also using a primitive type will prevent issues with ==.
Issue 2:
For any changes in the marks property to be visible in the TableView, you need to provide a marksProperty() method returning the property itself. This is necessary for the TableView to listen to changes of the property.
public class MarkStructureItem {
final SimpleIntegerProperty marks;
final int id;
#Override
public int hashCode() {
return id;
}
#Override
public boolean equals(Object obj) {
return obj != null
&& obj.getClass() == this.getClass()
&& this.id == ((MarkStructureItem) obj).id; // primitive type can be compared using ==
// && this.getId().equals(((MarkStructureItem) obj).getId()); // alternative for non-primitive types
}
public MarkStructureItem(int finishPosition, Integer marks) {
this.marks = new SimpleIntegerProperty(marks);
this.id = finishPosition;
}
public int getId() {
return id;
}
public IntegerProperty marksProperty() {
return marks;
}

How Customize Component Label in ZK

Haii all i need help, i want to custom Label component in zk and i nedd to add a property wich is mandatory property when i set mandatory="true" the asterix symbol will be appear and if i set mandatory="false" the asterix symbol disappear,and i am trying like this :
private Label label;
private Label sign;
private String lblValue;
private String REQUIRED_SIGN = " *";
private boolean mandatory;
public SignLabelCustom()
{
label = new Label();
label.setSclass("form-label");
appendChild(label);
sign = new Label();
if(mandatory=true){
sign.setValue(REQUIRED_SIGN);
sign.setStyle("color: red");
appendChild(sign);
}
else{
sign.setValue("");
sign.setStyle("color: red");
removeChild(sign);
}
}
public String getValue() {
return lblValue;
}
public boolean isMandatory() {
return mandatory;
}
public void setMandatory(boolean mandatory) {
this.mandatory = mandatory;
}
public void setValue(String lblValue) {
label.setValue(lblValue);
this.lblValue = lblValue;
}
but the condition does'nt working, how to solve it?
What you probably want is called an HtmlMacroComponent, which combines a label and a textbox...
You start with a zul file:
<zk>
<label id="mcLabel"/><textbox id="mcTextbox"/>
</zk>
...and create a component for it...
public class MyTextbox extends HtmlMacroComponent {
#Wire("#mcTextbox")
private Textbox textbox;
#Wire("#mcLabel")
private Label label;
private String caption;
private boolean mandatory;
public MyTextbox() {
compose(); // this wires the whole thing
}
public void setMandatory(final boolean value) {
mandatory = value;
updateCaption();
}
public boolean isMandatory() {
return mandatory;
}
public void setCaption(final String value) {
caption = value;
updateCaption();
}
public String getCaption() {
return caption;
}
protected void updateCaption() {
label.setValue(mandatory ? caption + "*" : caption);
}
public String getValue() {
return textbox.getValue();
}
public void setValue(final String value) {
textbox.setValue(value);
}
}
...and now you can use it, for example by defining it on the top of your zul file... (adjust package and .zul name as required):
<?component name="mytextbox" macroURI="/zk/textbox.zul" class="com.example.MyTextbox"?>
...so you can simply use it...
<mytextbox id="name" value="Frank N. Furter" caption="Your name" mandatory="true"/>
Later you can define a language addon for it...
my-language-addon
xul/html
mytextbox
com.example.MyTextbox
/zk/textbox.zul
...so that you don't need to put the definition on top of every .zul file where you use it anymore. See the documentation for more on this.
Of course, you also could only create a new label, etc. but I found it's a good think to create MacroComponents for those jobs that combine various components, since this way, for example, you could also automatically add validation, etc.

GWT Editors - how to add N sub-editors of the same type based on a Collection

I have an object, Supply, that can either be an ElecSupply or GasSupply (see related question).
Regardless of which subclass is being edited, they all have a list of BillingPeriods.
I now need to instantiate N number of BillingPeriodEditors based on the contents of that list, and am pretty baffled as to how I should do it.
I am using GWTP. Here is the code of the SupplyEditor I have just got working:
public class SupplyEditor extends Composite implements ValueAwareEditor<Supply>
{
private static SupplyEditorUiBinder uiBinder = GWT.create(SupplyEditorUiBinder.class);
interface SupplyEditorUiBinder extends UiBinder<Widget, SupplyEditor>
{
}
#Ignore
final ElecSupplyEditor elecSupplyEditor = new ElecSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor> elecSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor>(
elecSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof ElecSupply);
if(!(value instanceof ElecSupply))
{
showGasFields();
}
else
{
showElecFields();
}
}
};
#Ignore
final GasSupplyEditor gasSupplyEditor = new GasSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor> gasSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor>(
gasSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof GasSupply);
if(!(value instanceof GasSupply))
{
showElecFields();
}
else
{
showGasFields();
}
}
};
#UiField
Panel elecPanel, gasPanel, unitSection;
public SupplyEditor()
{
initWidget(uiBinder.createAndBindUi(this));
gasPanel.add(gasSupplyEditor);
elecPanel.add(elecSupplyEditor);
}
// functions to show and hide depending on which type...
#Override
public void setValue(Supply value)
{
if(value instanceof ElecSupply)
{
showElecFields();
}
else if(value instanceof GasSupply)
{
showGasFields();
}
else
{
showNeither();
}
}
}
Now, as the list of BillingPeriods is a part of any Supply, I presume the logic for this should be in the SupplyEditor.
I got some really good help on the thread How to access PresenterWidget fields when added dynamically, but that was before I had implemented the Editor Framework at all, so I think the logic is in the wrong places.
Any help greatly appreciated. I can post more code (Presenter and View) but I didn't want to make it too hard to read and all they do is get the Supply from the datastore and call edit() on the View.
I have had a look at some examples of ListEditor but I don't really get it!
You need a ListEditor
It depends of how you want to present them in your actual view, but the same idea apply:
public class BillingPeriodListEditor implements isEditor<ListEditor<BillingPeriod,BillingPeriodEditor>>, HasRequestContext{
private class BillingPeriodEditorSource extends EditorSource<BillingPeriodEditor>{
#Override
public EmailsItemEditor create(final int index) {
// called each time u add or retrive new object on the list
// of the #ManyToOne or #ManyToMany
}
#Override
public void dispose(EmailsItemEditor subEditor) {
// called each time you remove the object from the list
}
#Override
public void setIndex(EmailsItemEditor editor, int index) {
// i would suggest track the index of the subeditor.
}
}
private ListEditor<BillingPeriod, BillingPeriodEditor> listEditor = ListEditor.of(new BillingPeriodEditorSource ());
// on add new one ...
// apply or request factory
// you must implement the HasRequestContext to
// call the create.(Proxy.class)
public void createNewBillingPeriod(){
// create a new one then add to the list
listEditor.getList().add(...)
}
}
public class BillingPeriodEditor implements Editor<BillingPeriod>{
// edit you BillingPeriod object
}
Then in you actual editor edit as is in the path Example getBillingPeriods();
BillingPeriodListEditor billingPeriods = new BillingPeriodListEditor ();
// latter on the clickhandler
billingPeriods.createNewBillingPeriod()
You are done now.

JSlider with 2 data sources event handling

I have a JSlider component on my frame which is being constantly updated by an external component (a media player which sets a new value from time to time). I want the slider to handle the stateChanged event only when I manipulate the slider and not my external component.
Is there any way to achieve this?
I'd implement my own BoundedRangeModel, this way you can add additional flags that indicates whether it should accept updates or not
UPDATE with EXAMPLE
The basic idea would be to implement your own model, that way you can control when the value is actually changed
public class MyBoundedRangeModel extends DefaultBoundedRangeModel {
private boolean updatesAllowed;
public void setUpdatesAllowed(boolean updatesAllowed) {
this.updatesAllowed = updatesAllowed;
}
public boolean isUpdatesAllowed() {
return updatesAllowed;
}
#Override
public void setMinimum(int n) {
setUpdatesAllowed(true);
super.setMinimum(n);
setUpdatesAllowed(false);
}
#Override
public void setMaximum(int n) {
setUpdatesAllowed(true);
super.setMaximum(n);
setUpdatesAllowed(false);
}
#Override
public void setExtent(int n) {
setUpdatesAllowed(true);
super.setExtent(n);
setUpdatesAllowed(false);
}
#Override
public void setValue(int n) {
super.setValue(n);
}
#Override
public void setValueIsAdjusting(boolean b) {
setUpdatesAllowed(true);
super.setValueIsAdjusting(b);
setUpdatesAllowed(false);
}
#Override
public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean adjusting) {
if (isUpdatesAllowed()) {
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
}
}
}
This would allow you to control the change of the "value" property. The problem you have here is that ALL the set methods go through the setRangeProperties method, so you need to decide what should be allowed to effect it. In my example, the only method that does not control it is the setValue method.
In your code you would need to call it something like...
MyBoundedRangeModel boundedRangeModel = new MyBoundedRangeModel();
slider.setModel(boundedRangeModel);
...
boundedRangeModel.setUpdatesAllowed(true);
slider.setValue(value);
boundedRangeModel.setUpdatesAllowed(false);
Your only other choice is to extend the JSlider itself and override the setValue method directly in a similar way

JComboxBox setSelectedItem

I am facing problem to set a perticulat value of a custom JComboBox. If I call setSelectedItem() from the initialize() method of the following class it is not selecting the particular value.
The extended JComboBox class is:
public class ThemeComboBox extends JComboBox {
private static final long serialVersionUID = 50L;
public ThemeComboBox(DefaultComboBoxModel model) {
super(model);
initialize();
LibraryLogger.initMessage(getClass().getSimpleName());
}
public void initialize() {
ThemeComboBoxModel model = (ThemeComboBoxModel) getModel();
for(ThemeModel themeModel : model.getThemeModels()) {
if(themeModel.getThemeClass().equals(ConfigurationManager.getInstance().getUiManager().getUiProperties().getTheme())) {
setSelectedItem(themeModel);
System.out.println("=========");
break;
}
}
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
ThemeComboBox themeComboBox = (ThemeComboBox) actionEvent.getSource();
System.out.println(themeComboBox.getSelectedItem());
}
});
}
}
While if I override the getSelectedItem() of custom DefaultComboBoxModel then it is selecting that value but on choosing other value the selection remain same or it remain unchange.
The model class is:
public class ThemeComboBoxModel extends DefaultComboBoxModel {
private static final long serialVersionUID = 51L;
private Vector<ThemeModel> themeModels;
public ThemeComboBoxModel(Vector<ThemeModel> models) {
super(models);
}
public Vector<ThemeModel> getThemeModels() {
return themeModels;
}
public void setThemeModels(Vector<ThemeModel> themeModels) {
this.themeModels = themeModels;
}
/*#Override
public Object getSelectedItem() {
for(ThemeModel themeModel : themeModels) {
if(themeModel.getThemeClass().equals(ConfigurationManager.getInstance().getUiManager().getUiProperties().getTheme())) {
return themeModel;
}
}
return null;
}*/
}
I am unable to understand what I am doing wrong. Any information will be very helpful to me.
Thanks in advance.
1) I hope that main method is initialized from invokeLater
2) Swing is single threaded, where output to the GUI is done quite in one moment
3) there isn't any guarantee that all events have got any order, basically isn't possible ordering events for Swing GUI, same/especially on GUI startup
4) show GUI (setVisible(true);), then last codeline will be JComboBox#setSelectedItem(int or Object), wrapped inside invokeLater
5) add Listeners only if needed, remove useless Listeners

Categories