Základní komponenty JavaFX, Layouty RICHARD LIPKA 5.3. 12.3.2018
Dokončení - Obsluha ve vlastním vlákně Dlouhá obsluha (komprese, odesílání, ukládání) celkem běžná Blokuje GUI zamrzne a nereaguje na uživatele potřebuji oddělit do vlastního vlákna Rozhraní Worker<V> pro implementaci vlákna Typováno na V typ návratové hodnoty (vlákno končí vrácením výsledku) Možnost řídit běh zvenku (na rozdíl od běžných Java vláken) musí zajistit implementující třída Lze se dotazovat na stav (isrunning(), getstate(), getprogress(), getmessage()) Implementace ve třídě Task<V> Metoda call() ve které je užitečná práce Musí se chovat hezky a podporovat řízení zvenku Běží na pozadí, dokáže informovat o stavu, neblokuje vykreslovací smyčku Explicitně určena pro použití v JavaFX Jednorázová při každé obsluze je třeba vytvořit novou instanci (existuje i znovupoužitelná Service<V>, ale to přináší některé komplikace) 26.2.2018 UUR - ÚVOD DO JAVAFX 2
Dokončení - Obsluha ve vlastním vlákně příklad základní smyčky Task<Integer> task = new Task<Integer>() { protected Integer call() throws Exception { int it; for (it = 0; it < 100000; it++) { if (iscancelled()) { break; } System.out.println("it " + iterations); } return it; } }; Thread th = new Thread(task); th.start(); 26.2.2018 UUR - ÚVOD DO JAVAFX 3
Dokončení - Obsluha ve vlastním vlákně smyčka s aktualizací stavu Task<Integer> task = new Task<Integer>() { protected Integer call() throws Exception { int it; for (it = 0; it < 100000; it++) { if (iscancelled()) { updatemessage("canceled"); break; } updatemessage("iteration " + it); updateprogress(it, 100000); } return it; } }; Thread th = new Thread(task); th.start(); 26.2.2018 UUR - ÚVOD DO JAVAFX 4
Malá odbočka - cvičení Jak prohodit dvě tlačítka? Tlačítka jsou objekty chovat se k nim objektově Základní doporučení neměnit nic co se měnit opravdu nemusí ( snazší běh více vláken, jasnější chování aplikace) jak na to?
Malá odbočka - cvičení Jak prohodit dvě tlačítka? Tlačítka jsou objekty chovat se k nim objektově Základní doporučení neměnit nic co se měnit opravdu nemusí ( snazší běh více vláken, jasnější chování aplikace) jak na to? Naivní řešení: if (buttontext.compareto( Yes ) == 0) { String switchtext = yesbt.gettext(); if (buttontext.compareto( No ) == 0) { desclb.settext("as you wish, we will se on the exam.");
Malá odbočka - cvičení Jak prohodit dvě tlačítka? Tlačítka jsou objekty chovat se k nim objektově Základní doporučení neměnit nic co se měnit opravdu nemusí ( snazší běh více vláken, jasnější chování aplikace) jak na to? Lepší řešení: if (buttontext.compareto(yes_string) == 0) { String switchtext = yesbt.gettext(); if (buttontext.compareto(no_string) == 0) { desclb.settext("as you wish, we will se on the exam.");
Malá odbočka - cvičení Jak prohodit dvě tlačítka? Tlačítka jsou objekty chovat se k nim objektově Základní doporučení neměnit nic co se měnit opravdu nemusí ( snazší běh více vláken, jasnější chování aplikace) jak na to? Beze změn v tlačítkách skutečné prohození: Node bt0 = buttonpane.getchildren().remove(0); Node bt1 = buttonpane.getchildren().remove(0); buttonpane.getchildren().add(0, bt0); buttonpane.getchildren().add(0, bt1); Collections.reverse(buttonPane.getChildren());
Odbočka II - novinky 16.2. 2018 Scenebuilder jde integrovat do Eclipse Vyzkoušeno na Java 8 + Oxygen + plugin e(fx)clipse Scene-biulder-plugin na githubu Parallel Coordinates chart na Harmonic Code Blog s novými komponentami cca každý týden Zdrojáky, postup vývoje, použití K dispozici class diagram JavaFX http://www.falkhausen.de/javafx/index.html Kompletní dokumentace k API, pro Javu 8 i 9 UML-like, proklikávatelné do dokumentace
Pro zopakování Jeviště, scéna, uzly Okno aplikace reprezentuje Jeviště (Stage) V okně může být několik scén (Scene), jen jedna je viditelná Scéna je strom složený z uzlů (Node) Vnitřní uzly (panely - Pane) Listy (nemohou mít potomky) Pozor na stejné názvy v JavaFX a AWT! Neprovádět importy automaticky a bezmyšlenkovitě
Layouty Automatické pozicování prvků v panelu podle nastavených pravidel Při změně velikosti okna se automaticky přepočtou velikosti prvků pozice prvků Může a nemusí respektovat rozměry uzlů ( může je měnit ) Podobné layouty jako ve Swingu, pravidla pro skládání divů v html/css Je možné je libovolně kombinovat a složit okno z panelů s různými layouty Nejdřív kreslit na papír, rozmyslet strukturu, až pak programovat
Kontejnery (potomci Pane) Panel (Pane) je uzel určený pro vkládání dalších uzlů Veřejná metoda public ObservableList<Node> getchildren() (v Node je také, ale protected) Všechny layouty odvozeny jako potomci této třídy Layout není samostatný objekt, pro každý layout existuje odpovídající panel který jej implementuje Layout může mít různé vlastnosti ovlivňující vzhled a pozici komponenty Vkládání přes speciální metody Potomek (komponenta) může být spojen s objektem nastavujícím jeho vlastnosti Transparentní obalové / nastavovací objekty jsou dostupné jen přes metody Vkládání přes kolekci children, vlastnosti doplněny statickou metodou
Velikost uzlu - Region U uzlů je možné nastavit několik velikostí: setminsize() setmaxsize() setprefsize() Uzel si velikost určuje sám pole svého obsahu, ale voláním těchto metod je možné jeho výpočet obejít Do automatické velikosti se vejde všechen obsah komponenty Nastavení mohou být přebyta výpočtem vycházejícím z layoutů Layouty využívají obvykle prefered size Pokud uzel nemá měnit velikost, nastavit všechno stejně Pokud má uzel vyplnit dostupný prostor, nastavit rozměr na Double.MAX_VALUE Lze nastavit insets vzdálenost všech potomků od kraje region (setpadding()) Pozor, pokud mají sami další okraje, sečtou se
FlowPane Skládá prvky za sebou, tak jak jsou vloženy do jeho seznamu potomků Horizontální po řádcích Vertikální po sloupcích Umožňuje nastavit velikost mezery mezi prvky Hgap, Vgap Lze nastavit pozici prvků setalignment(pos.center) U horizontální varianty lze nastavit zarovnání řádky setrowvalignment(vpos.top)
HBox Skládání prvků do jedné řádky Žádné zalomení Pokud se nevejdou, snaží se je zmenšit až do minwidth Lze nastavit mezery mezi prvky setspacing() Potomkům lze nastavit vlastní okraje HBox.setMargin(child, Insets) Potomkům lze nastavit prioritu pro resize HBox.setHgrow (child, Priority) Always roste až do maximální šířky Never roste jen do preferované šířky
VBox V podstatě totéž jako předchozí, jen vertikální priorita se nastavuje VBox.setVgrow (Child, Priority)
BorderPane Častý základ aplikace Dělí prostor do pěti oblastí: horní a spodní pevná výška, rozšiřují se Pravý a levý pevná šířka, natahují se do výšky střed vyplňuje zbytek Vkládání setleft(), setcenter() Potomkům lze nastavit Zarovnání Okraje
AnchorPane Trochu podobný BorderPane Umožňuje kotvit prvky ke stranám panelu K jedné pozici lze kotvit více prvků Jeden prvek lze kotvit k více místům Nastavení přes AnchorPane.setTopAnchor (child, offset) Pozor, nebrání a nehlídá překrývání prvků
TilePane Pravidelná mřížka Lze nastavit Rozměry preferovaný počet řádek a sloupců Orientaci Rozestupy (Hgap, Vgap) Preferovanou velikost jednoho dílu (setpreftilewidth() ) jinak podle velikosti největšího potomka Zarovnání dílu (settilealignment() ) Jednotlivým potomkům lze nastavit Vlastní zarovnání Vlastní okraje
GridPane Nejsložitější Nepravidelná mřížka Uzly mohou zabírat několik řádek nebo sloupců Pro ladění setgridlinesvisible() Lze globálně nastavit Horizontální a vertikální mezery Vzdálenost od okraje S uzlem spojen formátovací objekt (pro nastavení statické metody) Vkládání Metody pro vkládání: add(child, column, row, colspan, rowspan) addrow(), addcolumn()
GridPane maintitle ( Welcome ) (0,0) Roztažen přes 2 sloupce, 1 řádek username (Label) (0, 1) usertextfield (TextField) (1, 1) pw (Label) (0, 2) pwbox (TextField) (1, 2)
StackPane Uzly vkládané přes sebe Obvykle pro vytvoření složitější komponenty (obrázek přes který je něco napsáno ) Potomkům lze nastavit zarovnání a okraje Snaží se prvky zvětšit na jejich maxsize
Harmonika (Accordion) a rozbalovací panely (TitledPane) Umožňuje přepínat několik panelů na jednom místě Do Accordion lze vložit libovolné množství TitledPane getpanes().addall( ) TitedPane není klasický panel (potomek Control, ne Pane) Lze nastavit jen jednoho potomka, v konstruktoru Může to být i další panel Nikdy nenastavovat výšku!
Bez layoutu - Pane Pane samotný nemá žádný layoutovací algoritmus I tak do něj lze vkládat potomky, jen je třeba je pozicovat ručně na absolutní souřadnice (snadné v Scene Builderu) Potomci mají velikost podle své preferované velikosti Všechny Node mají metody relocate(x, y) preferovaný způsob umístění setlayoutx(x) nastavení pozice setlayouty(y) settranslatex(x) nastavení posunu vůči aktuální pozici settranslatey(y) Pozor, translace a nastavené souřadnice se sčítají Souřadnice nastaveny v prostoru rodiče, ne celého okna
Scrollbary (ScrollBar, ScrollPane) Slouží k obalení komponenty scrollbary Samotný ScrollBar se obvykle nevytváří Může mít jen jednoho potomka Metoda setcontent() Umožňuje nastavit viditelnost scrollbarů (vždy, nikdy, podle potřeby) Zdroj scrollovací události setonscroll()
Ovládací prvky (potomci Control) Umožňují interakci uživatele s aplikací Reagují na vstupní události a generují vlastní události podle potřeby Dědí od třídy Parent pokud je to potřeba může mít potomky Např. hierarchická struktura menu Dědí od třídy Region Lze na ni uplatňovat CSS zabírá prostor je možné počítat pozici a velikost Má nastavitelné pozadí (Background) výplň, obrázek Má nastavitelný rámeček (Border) druh čáry, obrázek Veškerý obsah se kreslí přes ně
Tlačítka (Button) Už znáte, reaguje na stisknutí Vytváří vlastní událost na kterou lze reagovat setonaction( EventHandler<ActionEvent>) Ostatní události (kliknutí myši, dotek obrazovky) používat opatrně Může být popsáno (settext()) Může obsahovat obrázek (setgraphics( Node graphics)) setdefaultbutton() reaguje na Enter (VK_ENTER) setcancelbutton() reaguje na Esc (VK_ESC)
Práce s obrázky (ImageView) Umí načíst bmp, jpg, png a gif soubory Vytvářen z URL (cesty k obrázku) nebo z Image (třída pro reprezentaci obrázku) Při tvorbě z URL vnitřně vznikne nový Image img = new Image("file:javafx.jpg"); Cesta relativní k místu spuštění aplikace img = new Image("http://rili.cz/images/image.jpg"); Cesta absolutní, URL na webu new Image(getClass().getResourceAsStream("/resources/info.png")); Cesta relativní k aktuální třídě (binárce)!!! Nenačítat obrázek zbytečně několikrát!!!
Výběry (CheckBox, RadioButton) Výběr z malého množství možností, druhy tlačítek CheckBox Dvou nebo třístavové zaškrtávátko setallowindeterminate() Lze reagovat na změnu stavu setonaction() RadioButton Dva stavy, vybrán a nevybrán I v podobě tlačítka ToggleButton Obvykle ve skupině ToggleGroup() jen jeden smí být označen Lze reagovat na změnu stavu setonaction()
Výběry (ChoiceBox) Výběr z většího množství položek Typován na typ položky Položky uloženy v kolekci ObservableList<T>, lze získat přes getitems() Vybraný prvek lze získat přes getvalue() Nelze přidávat nové prvky Lze nastavit vlastní StringConverter<T> pro převod objektů na řetězce String tostring(t arg0)
Nastavení rozhraní StringConverter<T> ChoiceBox<Animal> cb = new ChoiceBox<Animal>(); cb.setconverter( new StringConverter<Animal>() { public String tostring(animal arg0) { return arg0.name + " " + arg0.age; } }); public Animal fromstring(string arg0) { return null; } public class Animal { String name; int age; public Animal (String name, int age) this.name = name; this.age = age; } public String tostring() { return "Animal name=" + name; } }
Výběr z mnoha prvků (ComboBox) Podobný jako ChoiceBox Pro větší množství prvků setvisiblerowcount() pro nastavení počtu řádků Automatické scrollbary Může být editovatelný seteditable() Nová hodnota se automaticky nepřidává do seznamu!, jen je vrácena přes getvalue() Je třeba nastavit StringConverter a metodu fromstring()
Výběr data (DatePicker) Komponenta pro výběr data Odstraňuje některé problémy s validací Usnadňuje výběr data Kontrolované ruční zadání textu Výběr data z kalendáře Pro získání hodnoty LocalDate getvalue() Podporuje všechny kalendáře které Java umí setchronology() Podporuje Locale nastavení
Výběr barvy (ColorPicker) Výběr barvy, z palety nebo HSB/ RGB hodnot Color getvalue() pro získání hodnoty Pamatuje si paletu barev
Malá odbočka Novinky JMetro (http://www.pixelduke.com/jmetro) Průběžně udržovaná sada vzhledů napodobující Windows Metro I slidery, toggleswitch komponenta a podobně Ukázka jak pracovat se vzhledem a se styly Lib-action Abstraktní reprezentace akcí (handler + nastavení) Mechanismy pro registraci, fluent API Spíš pro pokročilé programátory, spousta abstrakce JFreeChartFX - https://github.com/jfree/jfreechart-fx Wrapper pro JFreeChart, rozsáhlou grafovou knihovnu OrsonChartFX - https://github.com/jfree/orson-charts-fx Wrapper pro Orson Chart, knihovnu 3D grafů
Jednoduchý text (TextField, Label) Label popisek, případně s obrázkem settext() setgraphics() jako u tlačítek Můžu vložit libovolný Node, bude fungovat Metoda setlabelfor(node target) TextField základní jednořádkový neformátovaný vstup Lze nastavit preferovanou délku setprefcolumncount() Důsledně kontrolovat obsah gettext()
Formátovaný TextField Formátování založené na StringConverter <T> Libovolný návratový typ Zajistit reakci na nulový / nesprávný vstup vždy musím dostat nějaký String TextField vždy vrací jen String, formátovací objekt vrací objekt (typ T) StringConverter<String> formatter = new StringConverter<String>() { public String fromstring(string string) { if (string.length() == 8) return string; else if (string.length() == 7 && string.indexof('-') == -1) return string.substring(0, 3) + "-" + String.substring(3); else return "333-3333"; } public String tostring(string object) { if (object == null) return "777-7777"; return object; } }
Formátovaný TextField Vhodné doplnit filtr Zajistí smazání nevhodných kláves (lze zadat jen čísla, ) Vlastní operátor Aplikovaný na Change objekt popis změny řetězce ve formátovacím objektu UnaryOperator<TextFormatter.Change> filter = new UnaryOperator <TextFormatter.Change>() { public TextFormatter.Change apply(textformatter.change change) { } }; String text = change.gettext(); for (int i = 0; i < text.length(); i++) if(!character.isdigit(text.charat(i))) return null; return change; Nasazení: ownfield.settextformatter (new TextFormatter<String>(formatter, "default", filter)); 5. 3. - 12.3. 2018 UUR - LAYOUTY A ZÁKLADNÍ KOMPONENTY
Dlouhý text (TextArea) Vstup / zobrazení víceřádkového neformátovaného textu Lze měnit celý text ale ne jen jeho části Lze nastavit preferovaný počet řádek a sloupců Automatické scrollbary pokud se text nevejde Lze získat text a vybraný text gettext(), getselectedtext() Podporuje vracení změn undo(), redo() Podporuje pohyb kurzoru po slovech, po znacích, náhradu
Formátovaný text - zobrazení (TextFlow) Textový kontejner pro sazbu textu Vkládání a samostatné úpravy částí textu layout pro sázení textu a dalších objektů (do řádky) Nemá automaticky scrollbary, vyplňuje textem dostupnou plochu Jen pro vizualizaci (needitovatelný) Lze do něj vložit jakýkoliv Node
Formátovaný text úpravy (HTMLEditor) WYSIWYG editor HTML textů Vlastní ovládací prvky gethtmltext() pro získání textu
https://www.youtube.com/watch?v=g2iqie3hz34 Výběr z mnoha hodnot (Spinner) Výběr hodnot ze zadaného rozsahu, typovaný uzel Lze nastavit číselný rozsah DoubleSpinnerValueFactory<Double> svf = new SpinnerValueFactory. DoubleSpinnerValueFactory(0.0, 1.0, 0.5, 0.01); Spinner<Double> sp = new Spinner<>(); sp.setvaluefactory(svf); Lze nastavit editovatelnost: seteditable(true); Získání hodnoty: getvalue()
https://www.youtube.com/watch?v=g2iqie3hz34 Výběr z mnoha hodnot (Spinner) Lze nastvit kolekci přes kterou Spinner iteruje Spinner<String> sp = new Spinner<>(); ObservableList<String> items = FXCollections.observableArrayList ("Grace", "Matt", "Katie"); SpinnerValueFactory<String> svf = new SpinnerValueFactory. ListSpinnerValueFactory<>(items); sp.setvaluefactory(svf); Pokud je editovatelný, nové hodnoty neukládá je do kolekce nefunguje bez další obsluhy
Nastavení hodnoty posuvníkem (Slider) šoupátko pro nastavení hodnoty Diskrétní Spojité (Double) getvalue() pro získání hodnoty vždy Double Lze nastavit Základní jednotku posunu setmajortickunit() Skok při posuvu klávesnicí setblockincrement() Minimum a maximum (obvykle v konstruktoru) Viditelnost měřítka diskrétní zpracování setsnaptoticks()
Menu (Menu, MenuItem, MenuBar) Sestavování hierarchických menu Lze vložit kamkoliv, ale nedělejte to Nejlépe do kořenového prvku scény MenuBar hlavní lišta s menu Menu hlavní menu nebo submenu (do Menu se dá vložit další Menu) Metoda getitems() pro získání kolekce MenuItems MenuItem základní položka menu CheckMenuItem RadioMenuItem Rozhraní Toggle lze vkládat do skupin SeparatorMenuItem
Klávesové zkratky do menu Mnemonics Přes ALT, urychlení navigace v menu Automatické, v názvu File, E_xit, setmnemonicparsing(true) Accelerator Klávesová zkratka k akci Pozor na stejné zkratky Lepší než setonkeytyped() setaccelerator(keycombination) new KeyCombination( KeyCode.ADD, KeyCombination.CONTROL_DOWN)
Kontextové menu Funguje pro sezamy, tabulky i stromy a další prvky (včetně jednotlivých buněk) setcontextmenu(contextmenu) ContextMenu fugnuje podobně jako Menu v MenuBar Může mít potomky MenuItem, RadioMenuItem Ty se nastavují stejně jako v obyčejném menu Vykresluje se v místě kliknutí Automaticky reaguje na pravé tlačítko Po vykreslení jako normální menu (fungují Mnemonics i akcelerátory)
Nástrojová lišta (ToolBar) Panel pro tlačítka Jako jednoúrovňové menu Lze vkládat libovolné Node Lze nastavit orientaci setorientation (Orientation.VERTICAL); Musí být vložen na nějaké místo v panelu (podobně jako menu) Sám od sebe se nepřesouvá ani nevytváří své okno Pokud se do něj prvky nevejdou, vytváří rozbalovací menu
Dialogy (Alert) Podpora až od verze 8.40 Třída Dialog, od ní lze dědit vlastní dialogová okna (typována na návratovou hodnotu dialogu) Alert Základní informační dialog Několik připravených typů ERROR INFORMATION CONFIRMATION WARNING NONE Lze nastavit titulek a text (setcontenttext()) Zobrazení přes show() nebo showandwait() vrací jaké tlačítko bylo stisknuto Lze nastavit vlastní Graphics
Třída Optional<T> Obalová třída pro typ T Obsahuje Instanci typu T nebo null Lze testovat ispresent() a získat obalenou instanci get() Lze volat ifpresent(consumer) omezí se riziko NullPointerException I call it my billion-dollar mistake. It was the invention of the null reference in 1965 But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement sr Tony Hoare (jazyk Algol) 5. 3. - 12.3. 2018 UUR - LAYOUTY A ZÁKLADNÍ KOMPONENTY
Zobrazení dialogu Alert Optional<ButtonType> result = alert.showandwait(); if (result.ispresent() && result.get() == ButtonType.OK) { dosomething(); } alert.showandwait().ifpresent(response -> { if (response == ButtonType.OK) { dosomething(); } }); alert.showandwait().filter(response -> response == ButtonType.OK).ifPresent(response -> dosomething());
Dialogy (ChoiceDialog) Dialog pro výběr z několika možností Typovaný (včetně návratového typu showandwait() ) Možnosti vypsané přes tostring() Možnosti typicky zadány v konstruktoru První je defaultní volba, musí ze zopakovat, jinak nepůjde vybrat Lze je získat přes getitems() jako kolekci getselecteditem pro získání vybraného prvku
Dialogy (TextInputDialog) Dialog pro textový vstup Rovnou typován na String Ikonu lze změnit metodou setgraphics() Text v záhlaví lze změnit metodou setheadertext()
Výběr souboru (FileChooser) Dialog pro výběr souboru (cesty) Lze nastavit filtry pro zobrazené soubory getextensionfilters().add() ExtensionFilter( Name, *.jpg, *.png ) Lze nastavit výchozí adresář a jméno souboru Pro zobrazení showopendialog(), showsavedialog() Vrací File nebo null showopenmultipledialog() Vrací List<File> nebo null
Děkuji za pozornost OTÁZKY? NÁZORY, PŘIPOMÍNKY? PŘÍŠTĚ: SEZNAM, TABULKA, STROM