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 stiskne
  • widgetDefaultSelected(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í

Tento web bude tebe a tvůj počítač krmit piškotkami, jelikož a protože je to slušný web a jako takový ví, že je potřeba návštěvu řádně pohostit, aby se u nás cítila dobře. Užíváním tohoto webu potvrzuješ, že netrpíš mentální anorexií, nedržíš žádnou obskurní dietu a že můžeš piškotki do sebe cpát kdykoli a v jakémkoli množství. Více informací...