Programovanie (2) v Jave
1-INF-166, LS 2016/17

Úvod · Pravidlá · Prednášky · Projekt · Netbeans · Odovzdávanie · Test a skúška
· Vyučujúcich môžete kontaktovať pomocou e-mailovej adresy E-prg.png (bude odpovedať ten z nás, kto má príslušnú otázku na starosti alebo kto má práve čas).
· Predvádzanie projektov bude v pondelok 5.6. od 9:00 do 12:00 a v utorok 6.6 od 12:00 do 13:30 (po skúške), oboje v miestnosti M217. Na termín sa prihláste v AIS. Ak robíte vo dvojici, prihlási sa iba jeden člen dvojice.
· Body zo záverečného testu sú na testovači. Poradie príkladov: P1: do šírky, P2: topologické, P3: výnimky, P4: iterátor, P5: testy, P6: strom. Bolo potrebné získať aspoň 20 bodov zo 40.
· Opravný test bude 19.6.2017 od 9:00 v miestnosti M-I. Na termín sa prihláste v AISe.
· Zapisovanie známok a osobné stretnutia ku skúške budú v utorok 13.6. 13:30-14:30 v M163 a v stredu 14.6. 14:00-14:30 v M163.


Cvičenia 19

Z Programovanie
Prejsť na: navigácia, hľadanie

Grafické komponenty a Eventy

Vytvorte JavaFX aplikáciu s panelom triedy Pane

  • pri kliknutí ľavým tlačítkom na panel sa na tomto mieste zobrazí nový štvorček (trieda Rectangle)
  • pri kliknutí pravým tlačítkom to bude kruh (trieda Ellipse).
  • ak užívateľ klikne na už existujúci komponent, náhodne zmení jeho farbu
  • v prípade, ak pri kliknutí myšou drží klávesové tlačítko Ctrl, komponent vymaže.
  • umožnite užívateľovi posúvať posledne vytvorený alebo označený komponent pomocou šípok na klávesnici
  • Obdobne umožnite zväčšovať komponenty pomocou kláves + a -

Viacero EventHandlerov na rovnakom prvku čakajúcich na rovnaký Event

  • Pozrite si nasledovný príklad - čo sa stane, ak klikneme na gombík btn?
btn.setOnAction((ActionEvent event) -> { System.out.println("ahoj"); }); 
btn.setOnAction((ActionEvent event) -> { System.out.println("hello"); }); 


Dizajn aplikácie

  • Urobte v hlavnom okne 10 gombíkov, z ktorých každý bude vypisovať svoje číslo. Skúste urobiť v rôznych layoutoch (napr. Border, VBox, HBox, Flow, Grid), aby ste videli, ako sa gombíky umiestňujú.
    • Vyskúšajte úlohu aj všeobecne (t.j. bez použitia 10 konkrétnych premenných typu Button).


Riešenie - Grafické komponenty a Eventy

/** Aktualny oznaceny utvar. */
static MyShape current = null;
/** Generator nahodnych cisel. */
static Random rand = new Random();
/** Panel, na ktorom sa vykresluju utvary. */
Pane pane = new Pane();

/** Zakladny handler pre kliknutie na vykresleny utvar. */
EventHandler<MouseEvent> clickHandler = new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent e) {
        MyShape shape = (MyShape) e.getSource();
        if (e.isControlDown()) {
            pane.getChildren().remove(shape);
        }
        shape.setCurrent();
        e.consume();
    }
};

/** 
 * Pomocny interface pre zjednotenie nasich utvarov pod jeden typ. 
 */
interface MyShape {

    /** 
     * Dobra vlastnost Java 8, kedy aj interface moze mat
     * predimplementovane metody. Tieto vsak nevedia priamo vyuzivat
     * premenne implementujucich tried.
     */
    default public void setCurrent() {
        this.changeColor(Color.color(
                rand.nextFloat(), rand.nextFloat(), rand.nextFloat()));
        current = this;
    }

    /** Zmeni farbu vyplne na zadanu farbu. */
    public void changeColor(Color color);

    /** 
     * Zmeni velkost o difference. 
     * Kladne hodnoty zvacsuju, zaporne zmensuju.
     */
    public void increaseSize(double difference);

    /**
     * Posunie stred utvaru zadanym rozdielom v oboch suradniciach.
     */
    public void moveBy(double dx, double dy);
}

class MySquare extends Rectangle implements MyShape {

    MySquare(double size, double x, double y) {
        super();
        setCurrent();
        this.setFill(Color.RED);
        this.setHeight(size);
        this.setWidth(size);
        setOnMouseClicked(clickHandler);
        this.setX(x - size / 2);
        this.setY(y - size / 2);
    }

    @Override
    public void changeColor(Color c) {
        setFill(c);
    }

    @Override
    public void increaseSize(double difference) {
        if (getHeight() + difference >= 0) {
            setHeight(getHeight() + difference);
            setWidth(getWidth() + difference);
            // Kedze obdlznik (Rectangle) v JavaFX je urceny svojim lavym
            // hornym rohom a velkostou, ak nechceme posunut jeho stred,
            // potrebujeme posunut jeho lavy horny roh.
            moveBy(-difference / 2, -difference / 2);
        }
    }

    @Override
    public void moveBy(double dx, double dy) {
        this.setX(getX() + dx);
        this.setY(getY() + dy);
    }
}

class MyEllipse extends Ellipse implements MyShape {

    MyEllipse(double size, double x, double y) {
        super();
        setCurrent();
        setFill(Color.RED);
        setRadiusX(size / 2);
        setRadiusY(size / 2);
        setOnMouseClicked(clickHandler);
        setCenterX(x);
        setCenterY(y);
    }

    @Override
    public void changeColor(Color c) {
        setFill(c);
    }

    @Override
    public void increaseSize(double difference) {
        if (getRadiusX() + difference / 2 >= 0) {
            setRadiusX(getRadiusX() + difference / 2);
            setRadiusY(getRadiusY() + difference / 2);
        }
    }

    @Override
    public void moveBy(double dx, double dy) {
        this.setCenterX(getCenterX() + dx);
        this.setCenterY(getCenterY() + dy);
    }
}

@Override
public void start(Stage primaryStage) {

    // Nasmu panelu povieme, co ma kedy pridavat.
    pane.setOnMouseClicked((MouseEvent event) -> {
        if (!event.isControlDown()) {
            Shape newsh;
            if (event.getButton() == MouseButton.SECONDARY) {
                newsh = new MyEllipse(10, event.getX(), event.getY());
            } else {
                newsh = new MySquare(10, event.getX(), event.getY());
            }
            pane.getChildren().add(newsh);
        }
    });

    Scene scene = new Scene(pane, 300, 250);
    primaryStage.setTitle("My Squares");
    primaryStage.setScene(scene);

    // Nakoniec spracovavanie stlaceni klavesnice prenechavame Scene.
    // Stlacenia tlacidiel + a - sa spravaju inak, ako sipky.
    // Preto pouzivame hned dva rozne handlery pre dve podobne,
    // ale nerovnake udalosti.
    scene.setOnKeyTyped((KeyEvent event) -> {
        if (current != null) {
            switch (event.getCharacter()) {
                case "+":
                    current.increaseSize(2);
                    break;
                case "-":
                    current.increaseSize(-2);
                    break;
            }
        }
    });
    scene.setOnKeyPressed((KeyEvent e) -> {
        if (current != null) {
            switch (e.getCode()) {
                case LEFT:
                    current.moveBy(-1, 0);
                    break;
                case RIGHT:
                    current.moveBy(1, 0);
                    break;
                case UP:
                    current.moveBy(0, -1);
                    break;
                case DOWN:
                    current.moveBy(0, 1);
                    break;
            }
        }
    });
    primaryStage.show();
}

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