Java: Lambda výrazy a GUI, radio buttony vytvořené z enum
Zadání: mějme property definovanou enumem. Implementujme v GUI panel radio buttonů, pro každou položku enumu jeden radio button. Výběrem radio buttonu provedeme výběr odpovídající položky enumu. Implementaci provedeme ve frameworku SWT.
Lambda-friendly selection listener
Chceme-li implementovat reakci na událost kliknutí myší na tlačítko (radio button je v SWT speciální případ tlačítka - viz dokumentace) pomocí lambda výrazu, narazíme na omezení. Interface SelectionListener
nelze použít jako functional interface, protože definuje metody dvě:
widgetSelected(SelectionEvent e)
- v připadě tlačítka volaná, když uživatel tlačítko stisknewidgetDefaultSelected(SelectionEvent e)
- u tlačítka nepoužívaná, používá se např. u combo boxů, když uživatel změní text a stiskne enter.
Nabízejí se dvě možnosti, jak omezení obejít. Můžeme použít netypový event - viz příklad zde. Anebo můžeme definovat upravený interface SelectionListener
tak, abychom ho mohli označit jako functional interface. Způsob implementace je poměrně těžko dohledatelný, proto ho raději uvádím také.
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
@FunctionalInterface
public interface LambdaFriendlySelectionListener extends SelectionListener {
@Override
default void widgetDefaultSelected(SelectionEvent e) {
// u tlačítka se nepoužívá, může zůstat prázdné.
}
}
Metodu widgetDefaultSelected(...)
implementujeme jako default
. Lambda výraz se pak bude odkazovat na dosud neimplementovanou metodu widgetSelected(...)
.
Panel s radio buttony
Nyní můžeme přistoupit k vlastní implementaci panelu s radio buttony. Pro účel přikladu předpokládejme, že enum MyEnum
implementuje metodu getButtonText()
vracející text pro radio button. Taktéž v příkladu nebudu řešit layout.
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
private void createRadioPanel( Composite parent ) {
for( MyEnum m : MyEnum.values() ) {
Button radio = new Button( parent, SWT.RADIO );
radio.setText( m.getButtonText() );
radio.addSelectionListener( (LambdaFriendlySelectionListener) e -> selectEnumValue( m ) );
}
}
A to je celé. Jediné, co potřebujeme, je určit, že lambda výraz implementuje typ LambdaFriendlySelectionListener
, v opačném případě bude kompilátor hlásit chybu, že SelectionListener
není functional interface. Operátor přetypování, jak jsme ho do příkladu zapsali, se neváže k parametru e
(typ SelectionEvent
je automaticky přiřazen kompilátorem), ale k celému lambda výrazu.
Pro procházení jednotlivých položek enumu je v tomto případě lepší použít klasický cyklus foreach. Implementace lambda výrazem by byla méně přehledná.
Opět jsme si ukázali, že šikovně použitá lambda výrazně usnadní programování a zpřehlední výsledný zdroják.
Tagy: Java, Programování