The pattern is always the same:
- Add new ActionListener to JCheckBox X. The Listener's body does this:
- Obtain object Y reference. If reference !=null, do this:
- Call method Z on Y with argument X.isSelected()
Example code:
jChecKBoxWindowSizeLocked.addActionListener(e -> {
final WindowConfig lastWin = getLastTouchedWindowConfig();
if (lastWin != null) {
lastWin.setSizeLocked(jChecKBoxWindowSizeLocked.isSelected());
}
});
jChecKBoxRememberSize.addActionListener(e -> {
final WindowConfig lastWin = getLastTouchedWindowConfig();
if (lastWin != null) {
lastWin.setRememberSize(jChecKBoxRememberSize.isSelected());
}
});
etc.
This looks awfully redundant and as if it should be solvable with a Lambda or method, but how would I give a reference to method Z without already nailing down object Y? I tried this method, but the call I'm using is probably not right:
private void addCheckboxListener(final JCheckBox checkBox, final Consumer<Boolean> setter) {
checkBox.addActionListener(e -> {
if (setter != null) {
setter.accept(checkBox.isSelected());
}
});
}
The call is:
addCheckboxListener(cbRememberSize, getLastTouchedWindowConfig()::setRememberSize);
I am pretty sure that this gives the reference to whatever the getter returns at the time of calling the add method, not a general reference that is then resolved later. Consequently, this causes a NullPointerException in its own line (but compiles just fine):
addCheckboxListener(cbRememberLocation, ((WindowConfig) null)::setRememberLocation);
Of course I could just give the target class' setter Method as declared via reflection, but that would be complete overkill for the 10 or so JCheckBoxes this is about. Now, if it's just about 10, then I should just copy the code and not play scientist, right.
But my point/question is that there should be some kind of Lambda-ish method-reference-y way to get this done. Or does this possibility indeed not exist?
EDIT
Thanks to Holger's reply, I now successfully tried using static setters that have an additional instance parameter, so that the addCheckboxListener can just take a static method reference and therefore work just as intended. (EDIT2: Nope. Not static. Please see comments to Holger's (accepted) response. The whole rest of this "EDIT" section was written before this EDIT2.)
I'm not happy to make the setters static, but for now it seems to be the most elegant solution, and it's certainly a good knife to have in the tool shed.
A new problem/question arose from this. Before I possibly make a new post about this, I'll ask it here:
An unexplainable compile error occurs in this call:
addCheckboxListener(jCheckBoxRememberLocation, WindowConfig::setRememberLocation);
The method's head:
private void addCheckboxListener(JCheckBox checkBox, BiConsumer<WindowConfig, Boolean> setter) {
The error:
Error:(72, 49) java: incompatible types: invalid method reference
reference to setRememberLocation is ambiguous
both method setRememberLocation(WindowConfig,Boolean) in WindowConfig and method setRememberLocation(boolean) in WindowConfig match
The error only occurs when I have both the old non-static setter as well as the new static setter in the WinConfig class, plus they both need to have a different set of parameters. Is this possibly a Java bug? Here are the methods:
public void setRememberLocation(final boolean rememberLocation) {
this.rememberLocation = rememberLocation;
}
public static void setRememberLocation(final WindowConfig instance, final Boolean rememberLocation) {
instance.rememberLocation = rememberLocation;
}
The error seems wrong because only one of the two methods fits the profile.
What's REALLY odd is: If I change the non-static method's head to the very same as the static method's head, the error vanishes.
But what's REALLY super damn odd is: If I then swap the first and 2nd parameter of the non-static method, the error still does not occur. WTF!?
C:\>java -version
java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)
C:\Program Files\Java\jdk1.8.0_74\bin>javac -version
javac 1.8.0_74
winver
Windows 7 Ultimate
Version 6.1 (Build 7601: Service Pack 1)
That Java version is used by the project. It's also the only one on my system. (No, also no 32 bit version somewhere else.)