Seminár z programovania v sieťach

Téma 1: Java FX »


zdroj: Java FX 8 tutorial
  • prvá verzia v roku 1997
  • na vývoj internetových aplikácií
  • pre interaktívne webstránky ktoré potrebujú komunikovať s užívateľom
  • aplikácie sa formou pluginu spúšťajú v prehliadači, no je možné ich aj stiahnuť a využívať ako desktopovú aplikáciu
  • náhrada za Swing pre tvorbu GUI rozhraní
  • najnovšia verzia Java FX 8

  • 1) Čo potrebujeme
  • Najnovšia verzia Java JDK 8 (obsahuje Java FX 8) download
  • Najnovší Eclipse Mars download
  • Scene Builder 8.0 (designový nástroj na tvorbu GUI) download
  • 2) Konfigurácia Eclipse
  • Help → Install new software...
    name: e(fx)clipse
    location: http://download.eclipse.org/efxclipse/updates-released/2.0.0/site
    zaškrtnúť e(fx)clipse - install, doinštalovať a reštartovať

  • Ďalej potrebujeme povedať Eclipsu aby používal JDK 8 a kde nájde Scene Builder
  • Window → Preferences → Java → Installed JREs
    Tu nastavíme aby sa defaultne používalo jre1.8.0_60 (teda nastavíme k nemu cestu a ostatné odstránime)
  • Window → Preferences → Java → Compiler
    Tu nastavíme verziu compilera na 1.8
  • Window → Preferences → JavaFX
    Nastavíme si cestu k Scene Builder-u
  • 3) Vytvorenie projektu a tvorba používateľského prostredia
  • File → New → Other → JavaFX Project
  • Pridáme do projektu nový fxml dokument s názvom PersonLayout
  • Otvoríme ho v SceneBuilder-i
  • Vytvoríme si jednoduché GUI pre aplikáciu na ukladanie údajov o osobách
  • Vytvoríme ešte jeden fxml súbor s názvom MenuLayout pre menu, ktorému ale ako root element nastavíme BorderPane
  • Cez menu projektu → New → Other → JavaFX → Classes vytvoríme triedu JavaFX Main Class s názvom MainApp a nakopírujeme si tam tento zdrojový kód: MainApp.txt
  • 4) Naplnenie tabuľky údajmi
  • Vytvoríme si triedu Person ktorá bude zastupovať údaje pre jednu osobu. Person.txt
  • Pridáme si do triedy MainApp súčasti potrebné na to, aby si aplikácia mala kam údaje načítať
    medzi inštančné premenné pridáme private ObservableList personData = FXCollections.observableArrayList();
    medzi metódy pridáme konštruktor a novú metódu zdroj tu
  • Na prepojenie aplikácie s tabuľkou v fxml súbore potrebujeme controller. Vytvoríme si teda triedu PersonLayoutController zdroj tu
  • Aplikáciu musíme nastaviť tak aby vedela ktorý controller má použiť. Pridáme teda do metódy showPersonOverview v triede MainApp tieto riadky:
    PersonOverviewController controller = loader.getController();
    controller.setMainApp(this);
  • Znovu si otvoríme PersonLayout.fxml v Scene Builder-i a aj tu nastavíme správny controller
  • Okrem toho v časti code priradíme id tabuľke, jej stĺpcom a labelom
  • 5) Interakcia s užívateľom
  • Pri kliknutí na položku tabuľky chceme zobraziť údaje vybranej osoby, pridáme teda do triedy PersonLayoutController nasledovnú metódu:

    private void showPersonDetails(Person person) {
        if (person != null) {
            // Fill the labels with info from the person object.
            firstNameLabel.setText(person.getFirstName());
            lastNameLabel.setText(person.getLastName());
            streetLabel.setText(person.getStreet());
            postalCodeLabel.setText(Integer.toString(person.getPostalCode()));
            cityLabel.setText(person.getCity());
    		birthdayLabel.setText(DateUtil.format(person.getBirthday()));
        } else {
            // Person is null, remove all the text.
            firstNameLabel.setText("");
            lastNameLabel.setText("");
            streetLabel.setText("");
            postalCodeLabel.setText("");
            cityLabel.setText("");
            birthdayLabel.setText("");
        }
    }
    
  • V triede osoba používame dátový typ LocalDate ktorý potrebujeme preformátovať na String, vytvoríme si na to pomocnú triedu DateUtil zdroj tu
  • Následne v controlleri aktualizujeme metódu initialize pridaním listenera, ktorý bude detekovať kliknutie do tabuľky:

    private void initialize() {
    		// Initialize the person table with the two columns.
    		firstNameColumn.setCellValueFactory(cellData -> cellData.getValue()
    		.firstNameProperty());
    		lastNameColumn.setCellValueFactory(cellData -> cellData.getValue()
    		.lastNameProperty());
    
    		showPersonDetails(null);
    
    		// Listen for selection changes and show the person details when
    		// changed.
    		personTable.getSelectionModel().selectedItemProperty()
    				.addListener((observable, oldValue, newValue) -> 
    				showPersonDetails(newValue));
    	}
    
  • V controlleri vytvoríme udalosť pre tlačidlo Delete, ktorá vymaže označený záznam, v prípade stlačenia pri prázdnej tabuľke resp. bez označenia záznamu vypíše upozornenie:

    @FXML
    private void handleDeletePerson() {
        int selectedIndex = personTable.getSelectionModel().getSelectedIndex();
        if (selectedIndex >= 0) {
            personTable.getItems().remove(selectedIndex);
        } else {
            // Nothing selected.
            Alert alert = new Alert(AlertType.WARNING);
            alert.initOwner(mainApp.getPrimaryStage());
            alert.setTitle("No Selection");
            alert.setHeaderText("No Person Selected");
            alert.setContentText("Please select a person in the table.");
    
            alert.showAndWait();
        }
    }
    
  • Cez SceneBuilder (v záložke Code) nastavíme tlačidlu spustenie tejto akcie
  • Vytvoríme ďalší fxml dokument s názvom PersonEditLayout do ktorého pridáme GridPane, Labely a TextFieldy a Buttony takto:
  • Pre tento dokument vytvoríme controller PersonEditLayoutController.java obsahujúci obslužné metódy pre tlačidlá ok a cancel, navyše obsahuje aj overenie správnosti vstupu zdroj tu
  • Prejdeme do SceneBuildera a tam PersonEditLayout-u nastavíme tento nový controller, tlačidlám OK a cancel priradíme vytvorené udalosti a TextFieldom priradíme id-čka
  • Do MainApp pridáme metódu ktorá zabezpečí otvorenie editovacieho okienka:

        public boolean showPersonEditDialog(Person person) {
            try {
                // Load the fxml file and create a new stage for the popup dialog.
                FXMLLoader loader = new FXMLLoader();
                loader.setLocation(MainApp.class.getResource("PersonEditLayout.fxml"));
                AnchorPane page = (AnchorPane) loader.load();
    
                // Create the dialog Stage.
                Stage dialogStage = new Stage();
                dialogStage.setTitle("Edit Person");
                dialogStage.initModality(Modality.WINDOW_MODAL);
                dialogStage.initOwner(primaryStage);
                Scene scene = new Scene(page);
                dialogStage.setScene(scene);
    
                // Set the person into the controller.
                PersonEditLayoutController controller = loader.getController();
                controller.setDialogStage(dialogStage);
                controller.setPerson(person);
    
                // Show the dialog and wait until the user closes it
                dialogStage.showAndWait();
    
                return controller.isOkClicked();
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
        }
    
  • Nakoniec ešte do PersonEditController-a pridáme metódy na obsluhu tlačidiel, ktoré potom cez SceneBuilder týmto tlačidlám priradíme:

    @FXML
    private void handleNewPerson() {
        Person tempPerson = new Person();
        boolean okClicked = mainApp.showPersonEditDialog(tempPerson);
        if (okClicked) {
            mainApp.getPersonData().add(tempPerson);
        }
    }
    
    @FXML
    private void handleEditPerson() {
        Person selectedPerson = personTable.getSelectionModel().getSelectedItem();
        if (selectedPerson != null) {
            boolean okClicked = mainApp.showPersonEditDialog(selectedPerson);
            if (okClicked) {
                showPersonDetails(selectedPerson);
            }
    
        } else {
            // Nothing selected.
            Alert alert = new Alert(AlertType.WARNING);
            alert.initOwner(mainApp.getPrimaryStage());
            alert.setTitle("No Selection");
            alert.setHeaderText("No Person Selected");
            alert.setContentText("Please select a person in the table.");
    
            alert.showAndWait();
        }
    }
    
  • 6) Export do spustiteľného .jar súboru
  • Nájdeme v hierarchii súbor build.fxbuild a otvoríme ho
  • Vyplníme údaje označené hviezdičkou (Autor, názov - AddressApp, verzia - 1.0, spúšťacia trieda - MainApp, formát - exe) a klikneme na ant build only
  • Pridáme do projektu priečinok "build" a do neho ďalšie priečinky "package" a "dist"
  • Do priečinka "dist" pridáme priečinok "resources" a do neho nakopírujeme všetky naše zdrojové súbory (.java aj .fxml)
  • Do priečinka "package" pridáme priečinok "windows" a do neho stiahneme tieto obrázky pre ikony ico a bmp
  • Prejdeme do súboru build.xml kde potrebujeme pridať:
    pri id="fxant" pridáme ako 3.riadok medzi tag filelist tento riadok <file name="${basedir}"/>
    pri id="appRes" pridáme ako 3.riadok <fx:fileset dir="dist" includes="resources/**"/>
    pri id="fxApplication" pridáme ako 3.riadok version="1.0"
  • Teraz spustíme build.xml ako Ant build, čo by malo vygenerovať spustiteľné jar-ko v priečinku build/dist

  • Téma 2: SVG »


    zdroje:
    http://rvlasveld.github.io/blog/2013/07/02/creating-interactive-graphs-with-svg-part-1/
    SVG (scalable vector graphics)
  • ide o značkovací jazyk a formát súboru, ktorý popisuje dvojrozmernú vektorovú grafiku pomocou XML
  • všetky SVG kresby možno animovať (JavaScript, ECMAScript)
  • vhodný pre jednoduchú grafiku napr. stromy, grafy, atď...
  • SVG grafika neobsahuje obrazové dáta pixel po pixeli, ale len zoznam svojich súčastí - grafických objektov

  • Výhody
  • kresby možno jednoducho vytvoriť a upravovať (hoci aj textovým editorom)
  • ľahká prenositeľnosť
  • veľkosť výsledného súboru (možno využiť komprimovanie na formát .svgz)
  • ak obrázok obsahuje text, je možné ho vyhľadávať

  • Vkladanie na stránku
  • tag <embed>
  • tag <object>
  • tag <iframe>
  • tag <svg> - narozdiel od ostatných spôsobov, v tomto sa vkladá SVG priamo do HTML kódu

  • Základné útvary v SVG a ich použitie
  • Obdĺžnik <rect>
  • Kružnica <circle>
  • Elipsa <ellipse>
  • Čiara <line>
  • Polyline <polyline>
  • Path <path>
  • Mnohouholník <polygon>
  • Text <text>

  • Kontajner na zoskupovanie útvarov
    <g>
    .
    .
    .
    </g> 
    

    Základné atribúty útvarov
  • zapisujú sa ako parametre k tagom napr.
    <circle stroke="red" />
  • základné atribúty: farba pera (stroke), farba výplne (fill) a hrúbka pera (stroke-width)
  • obdĺžnik
     <rect x="80" y="60" width="250" height="250" rx="20"/> 
    
    - x, y -> súradnica ľavého horného okraja obdĺžnika
    - rx, ry -> zaokrúhlenie rohov obdĺžnika v x-ovej a y-ovej osi
    - width, height -> rozmery obdĺžnika
  • čiara
     <line x1="0" y1="0" x2="200" y2="200" /> 
    
    - x1, y1 -> súradnica začiatočného vrchola
    - x2, y2 -> súradnica koncového vrchola
  • path
     <path d="M150 0 L75 200 L225 200 Z" /> 
    
    - d -> dáta o ceste, aká sa má nakresliť
    - M x, y-> presunúť kresliace pero na súradnicu (move to)
    - L x, y-> nakresliť čiaru k danej súradnici (line to)
    - Z -> uzavrieť cestu

  • Príklad
    <?xml version="1.0"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
     "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    
    <svg xmlns="http://www.w3.org/2000/svg"
     width="467" height="462">
     <rect x="80" y="60" width="250" height="250" rx="20"
     style="fill:#ff0000; stroke:#000000;stroke-width:2px;" />
     
     <rect x="140" y="120" width="250" height="250" rx="40"
     style="fill:#0000ff; stroke:#000000; stroke-width:2px;
     fill-opacity:0.7;" />
    </svg>
    

    Grafy v SVG
    Chceme za pomoci html, svg a css vytvoriť graf podobný tomuto: graf, ktorý bude zobrazovať hodnoty RTT z pingu na vybraný server (napr. google.sk).
    "Súčiastky" nášho grafu budú
    - mriežka prerušovaných čiar, pomáhajúcich interpretovať hodnoty dátových bodov
    - dátové body, každý pozostávajúci z času odoslania príkazu ping a získanej hodnoty RTT
    - textové popisky určujúce rozsah a hodnoty grafu
    - oblasť pod dátovými bodmi

    Mriežka
    - vytvoríme si súbor graf.html kód tu, do ktorého vložíme element svg v ktorom vytvoríme pomocou útvaru line mriežku
    - okrem toho si vytvoríme súbor graf.css, kde budeme definovať vzhľad komponentov (ide to aj priamo v kóde ale nakoľko máme veľa komponentov, bude to pohodlnejšie), tam si nateraz nakopírujeme kód ktorý nastaví pozadie komponentu a vzhľad mriežky:
    svg {
        background-color: #000000;
      }
    
    svg.graph {
      height: 500px;
      width: 800px;
    }
    
    svg.graph .grid {
      stroke: yellow;
      stroke-dasharray: 1 2;
      stroke-width: 1;
    }
    svg.graph .grid.double {
      stroke-opacity: 0.4;
    }
    
    - potom nastavíme v html súbore v časti head, aby bolo toto css použité
    <link rel="stylesheet" href="graph.css" type="text/css" media="screen" />
    

    Dátové body
    - nateraz si do html súboru nakopírujeme napevno zopár dátových bodov:
    <g class="first_set points" data-setname="Our first data set">
      <circle cx="113" cy="374" data-value="5" r="5"></circle>
      <circle cx="259" cy="316" data-value="20" r="5"></circle>
      <circle cx="405" cy="350" data-value="10" r="5"></circle>
      <circle cx="551" cy="273" data-value="30" r="5"></circle>
      <circle cx="697" cy="150" data-value="62" r="5"></circle>
    </g>
    
    - okrem toho si v css zadefinujeme vzhľad dátových bodov:
    svg.graph .points {
      stroke: white;
      stroke-width: 3;
    }
    svg.graph .first_set {
      fill: #0000ff;
    }
    

    Labely
    - určíme si rozsah nášho grafu a jeho hodnôt a podľa nich zadáme nasledovné labely:
    <g class="labels x-labels">
      <text x="113" y="430">10:00</text>
      <text x="259" y="430">10:05</text>
      <text x="405" y="430">10:10</text>
      <text x="551" y="430">10:15</text>
      <text x="697" y="430">10:20</text>
    </g>
    
    <g class="labels y-labels">
      <text x="80" y="45">90</text>
      <text x="80" y="103">75</text>
      <text x="80" y="161">60</text>
      <text x="80" y="219">45</text>
      <text x="80" y="277">30</text>
      <text x="80" y="335">15</text>
      <text x="80" y="393">0</text>
      <text x="110" y="15">RTT čas v MS</text>
    </g>
    
    - v css dodefinujeme vzhľad labelov:
    svg.graph .labels {
      stroke: white;
      font-family: Arial;
      font-size: 14px;
      kerning: 1;
    }
    
    svg.graph .labels.x-labels {
      text-anchor: middle;
    }
    
    svg.graph .labels.y-labels {
      text-anchor: end;
    }
    

    Oblasť pod dátovými bodmi
    - s využitím útvaru path pospájame dátové body a vytvoríme z nich a rohov grafu polygón:
    <g class="surfaces">
      <path class="first_set" d="M113,390 L113,374 L259,316 L405,350 L551,273 L697,150 L697,390 Z"></path>
    </g>
    
    - do css pridáme kód pre vzhľad tejto časti:
    svg.graph .surfaces {
      fill-opacity: 0.5;
    }
    

    Teraz máme graf hotový, je ale čisto statický. Teraz by sme ho chceli "oživiť" tak, že budeme mať možnosť do neho vložiť novú hodnotu a graf sa sám aktualizuje (resp. vypadne z neho najstaršia hodnota a ostatné sa posunú).
    Najprv si teda vytvoríme komponenty, cez ktoré budeme vkladať nové hodnoty:
    <br/>
    Čas odoslania pingu:<br/>
    <input id="cas" type="time" name="date">
    <br>
    RTT čas:<br/>
    <input id="hodnota" type="number" name="time" min="0" max="90">
    <br/>
    <input id="button1" type="button" value="Pridať novú hodnotu" onclick="addNew()" />
    

    Nakoniec ešte pridáme skript, ktorý zariadi pridanie novej hodnoty do grafu:
    <script>
        function addNew() {
    		document.getElementById("lbl1").textContent=document.getElementById("lbl2")
    		.textContent;
    		document.getElementById("point1").setAttribute("cy",document.getElementById("point2")
    		.getAttribute("cy"));
    		document.getElementById("lbl2").textContent=document.getElementById("lbl3")
    		.textContent;
    		document.getElementById("point2").setAttribute("cy",document.getElementById("point3")
    		.getAttribute("cy"));
    		document.getElementById("lbl3").textContent=document.getElementById("lbl4")
    		.textContent;
    		document.getElementById("point3").setAttribute("cy",document.getElementById("point4")
    		.getAttribute("cy"));
    		document.getElementById("lbl4").textContent=document.getElementById("lbl5")
    		.textContent;
    		document.getElementById("point4").setAttribute("cy",document.getElementById("point5")
    		.getAttribute("cy"));
    		document.getElementById("lbl5").textContent=document.getElementById("cas").value;
    		var v = "390.0";
    		var v2 = "3.88";
    		var hodnota= ""+document.getElementById("hodnota").value;
    		document.getElementById("point5").setAttribute("cy",v-(hodnota*v2));
    		document.getElementById("line").setAttribute("d","M113,390 "+"L"
    		+document.getElementById("point1").getAttribute("cx")+","
    		+document.getElementById("point1").getAttribute("cy")
    		+" L"+document.getElementById("point2").getAttribute("cx")+","
    		+document.getElementById("point2").getAttribute("cy")+" L"
    		+document.getElementById("point3").getAttribute("cx")+","
    		+document.getElementById("point3").getAttribute("cy")
    		+" L+"+document.getElementById("point4").getAttribute("cx")+","
    		+document.getElementById("point4").getAttribute("cy")+" L"
    		+document.getElementById("point5").getAttribute("cx")+","
    		+document.getElementById("point5").getAttribute("cy")+" L697,390 Z");
        }
    </script>
    
    Theme Sponsored by: Roller Blinds, Cyprus Holidays, Walk in Baths