Упражнение #2
В това упражнение ще се фокусираме върху изграждането на визуалната структура на JavaFX приложенията, използвайки Контейнери за изглед (Layout Controls) и FXML.
1. FXML – Декларативен UI дизайн
FXML е XML базиран език, който служи за дефиниране на потребителския интерфейс в JavaFX. Той позволява ясно разделение между визуалното представяне и програмната логика.
1.1. Структура на FXML файла
Всеки FXML файл следва строго определена структура, която се състои от три основни части:
- XML хедър: Първият ред винаги е стандартният XML дефиниционен ред:
<?xml version="1.0" encoding="UTF-8"?>
- Инструкции за импортиране (
<?import ...?>):
В FXML не можем да използваме графични елементи, без да сме ги импортирали. Те съответстват директно на import операторите в Java.
Пример: За да използваме Button, трябва да добавим <?import javafx.scene.control.Button?>. Могат да се използват и маски: <?import javafx.scene.layout.*?>.
- Коренов елемент (Root Element):
Всеки файл трябва да има точно един коренов елемент (обикновено контейнер за изглед като AnchorPane или VBox). Той дефинира началото на йерархията и съдържа дефиницията на пространството от имена (xmlns:fx="http://javafx.com/fxml/1").
1.2. Йерархия на графичните елементи: Контейнери и Дъщерни елементи
В JavaFX всичко се организира в дървовидна структура (Scene Graph). Елементите се делят на две основни категории според ролята им в йерархията:
-
Контейнерни елементи (Parent/Containers):
Това са елементи, които могат да съдържат други елементи в себе си. В JavaFX това са наследниците на класа Parent (от пакета javafx.scene.layout). Контейнерни елементи притежават свойството children (списък от деца). В FXML дъщерните елементи се записват директно между отварящия и затварящия таг на контейнера.
- Примери:
HBox,VBox,GridPane,StackPane.
- Примери:
-
Дъщерни/Листни елементи (Children/Leaf Nodes):
Това са крайните елементи, които обикновено не съдържат други обекти. Това са базовите контроли за интерфейса. Те се разполагат вътре в контейнерите и техните свойства (позиция, размер) често се управляват от логиката на родителския контейнер.
- Примери:
Button,Label,TextField.
- Примери:
Правило за влагане: Контейнерите могат да съдържат както контроли (Button), така и други контейнери (HBox вътре в VBox). Това позволява изграждането на сложни и адаптивни интерфейси чрез вложени структури.
1.3. Връзка между елементите в FXML и Java (fx:id)
За да можем да достъпим графичен елемент, се, използваме атрибута fx:id, който е дефиниран в пространството от имена xmlns:fx="http://javafx.com/fxml/1"
Пример в FXML: <ToggleGroup fx:id="group"/>
2. Контейнери за изглед (Layout Controls):
Контейнерите за изглед са специални контейнери, които управляват позиционирането и оразмеряването на своите деца (други контроли или Контейнери за изглед). Използването им е от ключово значение за създаването на адаптивни и добре изглеждащи потребителски интерфейси.
HBox(Хоризонтална кутия): Подрежда децата си едно до друго хоризонтално.- Свойства:
spacing- разстояние между децата,alignment- подравняване на децата в кутията, стойността на това свойство е enum Pos.HGrow- разтягане по хоризонтала за отделно дете,prefHeight- препорачителна височина на контейнера.
- Пример:
-
Без атрибути:
<HBox> ... </HBox> -
С атрибути:
<HBox spacing="15" alignment="CENTER" prefHeight="50.0"> ... </HBox>
-
- Свойства:
VBox(Вертикална кутия): Подрежда децата си едно под друго вертикално.- Свойства:
spacing- разстояние между децата,alignment- подравняване на децата в кутията, стойността на това свойство е enum Pos.VGrow- разтягане по вертикала за отделно дете,prefWidth- препорачителна дължина на контейнера.
- Пример:
-
Без атрибути:
<VBox> ... </VBox> -
С атрибути:
<VBox spacing="10" alignment="TOP_LEFT" prefWidth="200.0"> ... </VBox>
-
- Свойства:
BorderPane(Контейнер с граници): Разполага децата си в пет региона:TOP(горе),BOTTOM(долу),LEFT(ляво),RIGHT(дясно),CENTER(център).- Много полезен за основни оформления на приложения (напр. меню горе, статус бар долу, навигация отляво/отдясно, основно съдържание в центъра).
- Пример:
-
Без атрибути:
<BorderPane> ... </BorderPane> -
С атрибути:
<BorderPane prefWidth="800" prefHeight="600"> <top> <!-- Дефинира елемента в горната зона --> </top> </BorderPane>
-
- Пример:
- Много полезен за основни оформления на приложения (напр. меню горе, статус бар долу, навигация отляво/отдясно, основно съдържание в центъра).
GridPane(Мрежов контейнер): Организира децата си в гъвкава мрежа от редове и колони, която се определя от броя и подредбата на вложените елементите.- Полезен за форми, таблици или други структурирани оформления. Децата се добавят към конкретна колона и ред.
- Свойства:
hgap- хоризонтално разтояние между колонитеvgap- вертикално разтояние между колоните
- Пример:
-
Без атрибути:
<GridPane> ... </GridPane> -
С атрибути:
<GridPane hgap="10" vgap="10" alignment="CENTER"> <!-- Дефинира разстояние между колоните (hgap) и редовете (vgap) --> </GridPane>
-
FlowPane(Поточен контейнер): Разполага децата си последователно, подобно на поток от текст. Когато не остава място в текущия ред/колона, преминава към следващия.- Може да бъде хоризонтален или вертикален.
- Свойства:
orientation- определя посоката, в която се подреждат елементите първоначално.- Възможни стойности: HORIZONTAL (по подразбиране) и VERTICAL
prefWrapLength- определя кога FlowPane трябва да “пренесе” елементите, като дефинира максимална ширина или височина в която могат да се разположат.
- Пример:
-
Без атрибути:
<FlowPane> ... </FlowPane> -
С атрибути:
<FlowPane orientation="VERTICAL" hgap="5" vgap="5" prefWrapLength="200"> ... </FlowPane>
-
StackPane(Наслагващ контейнер): Наслагва децата си едно върху друго в центъра, подобно на стек от карти.- Полезен за показване на алтернативни изгледи или наслагване на елементи (напр. индикатор за зареждане върху друго съдържание).
- Пример:
-
Без атрибути:
<StackPane> ... </StackPane> -
С атрибути:
<StackPane prefWidth="400" prefHeight="300"> ... </StackPane>
-
AnchorPane(Закотвящ контейнер): Позволява закачане (anchoring) на децата си към една или повече страни на контейнера.- Дава много прецизен контрол върху позиционирането, но може да е по-труден за поддържане при промяна на размера. Позициите се задават чрез свойствата
topAnchor,bottomAnchor,leftAnchor,rightAnchor. - Пример:
-
Без атрибути:
<AnchorPane> ... </AnchorPane> -
С атрибути:
<AnchorPane> <Button text="Stay in corner" AnchorPane.topAnchor="10.0" AnchorPane.rightAnchor="10.0" /> </AnchorPane>
-
- Дава много прецизен контрол върху позиционирането, но може да е по-труден за поддържане при промяна на размера. Позициите се задават чрез свойствата
3. Базови контроли (UI Controls):
3.1 Текстови контроли
Те служат за визуализация или въвеждане на текстова информация.
Label(Етикет): Неинтерактивен текст, използван за описание на други елементи.- Свойства:
text- съдържание,wrapText- пренасяне на нов ред,alignment- подравняване на текста.textFill- цвят за запълване,
- Вложени свойства:
font- определя шрифта на текста в компонентa. Инициялизира се с елементаFont. Който има свойства:name- име на шрифта,size- размер на шрифра.
- Пример:
- С атрибути:
<Label text="Welcome to the system" alignment="CENTER" textFill="#333333"> <font><Font name="Arial Bold" size="14.0"/></font> </Label>
- С атрибути:
- Свойства:
TextField(Текстово поле): Едноредово поле за въвеждане на свободен текст.- Свойства:
promptText- текст-подсказка,text- въведеният текст,editable- дали е редактируемо.
- Пример:
- Без атрибути:
<TextField /> - С атрибути:
<TextField promptText="example@email.com" prefWidth="250.0" />
- Без атрибути:
- Свойства:
PasswordField(Поле за парола): СпециализиранTextField, който маскира въведените символи (обикновено с точки).- Пример:
- С атрибути:
<PasswordField promptText="Enter password" />
- С атрибути:
- Пример:
TextArea(Текстова област): Многоредово поле за въвеждане на дълги текстове.- Свойства:
prefRowCount- брой видими редове),wrapText- автоматично пренасяне.
- Пример:
- С атрибути:
<TextArea promptText="Type your comments here..." wrapText="true" prefHeight="100.0" />
- С атрибути:
- Свойства:
3.2 Бутони и контроли за избор:
Тези елементи задействат логика или позволяват на потребителя да направи избор.
Button(Бутон): Стандартен бутон за натискане.- Свойства:
defaultButton- активира се приEnter,cancelButton- активира се приEscape,maxWidth- за разтягане.
- Пример:
- С атрибути:
<Button text="Save" defaultButton="true" />
- С атрибути:
- Свойства:
CheckBox(Флагче за избор): Двупозиционен (или трипозиционен) избор. Позволява избор на множество опции едновременно.- Свойства:
selected- дали е избран,allowIndeterminate- позволява трето състояние.
- Пример:
- С атрибути:
<CheckBox text="I agree to terms" selected="false" />
- С атрибути:
- Свойства:
RadioButton(Радио бутон): Избор на само една опция от дадена група.- Свойства:
toggleGroup(всички бутони в една логическа група трябва да сочат към еднаToggleGroup).
- Пример:
- С дефиниция на група:
<VBox> <RadioButton text="Option A" selected="true"> <toggleGroup> <ToggleGroup fx:id="radioGroup"/> </toggleGroup> </RadioButton> <RadioButton text="Option B" toggleGroup="$radioGroup"/> </VBox>
- С дефиниция на група:
- Свойства:
ToggleButton(Превключващ бутон): Бутон, който остава в състояние “натиснат” (selected), докато не бъде натиснат отново.- Пример:
- С атрибути:
<ToggleButton text="ON / OFF" selected="true" />
- С атрибути:
- Пример:
4. FXML атрибути и компоненти
Тук ще намерите описание и конкретни примери за най-често използваните атрибути, за да разберете къде и как да ги прилагате.
4.1. Основни атрибути за оразмеряване и идентификация
Тези атрибути са валидни за почти всички елементи.
fx:id:- За какво е: Връзка с Java контролера.
- Пример:
<Button fx:id="submitBtn" text="Вход" />
prefHeight/prefWidth:- За какво е: Задава желания размер на елемента.
- Пример:
<VBox prefWidth="300.0" prefHeight="200.0"> ... </VBox>
minHeight/minWidth:- За какво е: Гарантира, че елементът няма да се свие твърде много.
- Пример:
<!-- Страничното меню не може да бъде по-тясно от 150px --> <VBox minWidth="150.0"> ... </VBox>
maxHeight/maxWidth:- За какво е: Ограничава размера. Специалната стойност “Infinity” кара елемента да се разтегне до края.
- Пример:
<!-- Бутон, който се разпъва по цялата ширина на родителя си --> <Button text="Login" maxWidth="Infinity" />
4.2. Атрибути, специфични за Контейнери (Layout Parents)
Тези атрибути се слагат на самия контейнер.
alignment:- За какво е: Подравнява съдържанието вътре в контейнера (напр. центрира бутоните).
- Пример:
<!-- Всички елементи вътре ще са в центъра --> <VBox alignment="CENTER" spacing="10"> ... </VBox>
spacing:- За какво е: Задава разстояние (в пиксели) между елементите. Валидно за HBox и VBox.
- Пример:
<HBox spacing="15.0"> <Button text="OK"/> <Button text="Cancel"/> </HBox>
hgap/vgap:- За какво е: Задава разстояние между редовете и колоните в мрежа (GridPane) или поток (FlowPane).
- Пример:
<GridPane hgap="10.0" vgap="10.0"> ... </GridPane>
orientation:- За какво е: Определя дали елементите се редят хоризонтално или вертикално.
- Пример:
<FlowPane orientation="VERTICAL" prefWrapLength="200"> ... </FlowPane>
4.3. Статични ограничения (Static Constraints)
Тези атрибути са най-особени. Те се слагат на ДЕТЕТО, но се четат от РОДИТЕЛЯ.
BorderPane.alignment:- За какво е: Казва на BorderPane къде да сложи това дете в неговата зона.
- Пример:
<top> <Label text="Header" BorderPane.alignment="CENTER" /> </top>
GridPane.columnIndex/GridPane.rowIndex:- За какво е: Позиционира елемента в конкретна клетка на таблицата.
- Пример:
<GridPane> <!-- Етикет в колона 0, ред 0 --> <Label text="Name:" GridPane.columnIndex="0" GridPane.rowIndex="0"/> <!-- Поле в колона 1, ред 0 --> <TextField GridPane.columnIndex="1" GridPane.rowIndex="0"/> </GridPane>
GridPane.columnSpan/GridPane.rowSpan:- За какво е: Елементът заема мястото на няколко клетки.
- Пример:
<!-- Бутонът е широк колкото 2 колони --> <Button text="Submit" maxWidth="Infinity" GridPane.columnSpan="2" GridPane.rowIndex="3"/>
VBox.vgrow/HBox.hgrow:- За какво е: Казва на детето да заеме всичкото свободно място. Много важно за responsive дизайн.
- Пример:
<VBox> <Label text="Menu Top" /> <!-- Този празен регион ще избута "Menu Bottom" най-долу --> <Region VBox.vgrow="ALWAYS" /> <Button text="Menu Bottom" /> </VBox>
AnchorPane.topAnchor…:- За какво е: Закотвя елемента на разстояние от ръба.
- Пример:
<AnchorPane> <!-- Бутон, винаги стоящ долу вдясно на 10px от ръба --> <Button text="Save" AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0" /> </AnchorPane>
4.4. Свойства на Контролите
Тези атрибути променят поведението на самата контрола.
text:- Пример:
<Label text="Здравей свят" />
- Пример:
promptText(Placeholder):- Пример:
<TextField promptText="Въведете имейл..." />
- Пример:
wrapText(Пренасяне):- Пример:
<TextArea wrapText="true" />
- Пример:
defaultButton(Реагира на Enter):- Пример:
<Button text="Login" defaultButton="true" />
- Пример:
4.5. Вложени тагове за свойства (Property Tags)
Използват се за сложни стойности, които не са просто текст или число.
1. Таг <padding> (Вътрешен отстъп)
Добавя разстояние вътре в елемента.
- Пример:
<GridPane hgap="10" vgap="10"> <padding> <!-- 20px отстъп от всички страни на формата --> <Insets top="20.0" right="20.0" bottom="20.0" left="20.0"/> </padding> <Label text="Form Title" /> </GridPane>
2. Таг <font> (Шрифт)
Променя шрифта на текста.
- Пример:
<Label text="Main Title"> <font> <!-- Голям удебелен шрифт --> <Font name="System Bold" size="24.0"/> </font> </Label>
3. Таг <background> (Фон)
Задава цвят на фона без CSS.
- Пример:
<HBox> <background> <Background> <fills> <!-- Задава сив фон --> <BackgroundFill> <fill> <Color red="0.9" green="0.9" blue="0.9"/> </fill> </BackgroundFill> </fills> </Background> </background> <Label text="Toolbar" /> </HBox>
4. Таг <margin> (Външен отстъп)
Добавя разстояние извън елемента. Това е статично свойство и се дефинира вътре в детето, но името на тага зависи от родителя (напр. HBox.margin).
- Пример:
<HBox> <Button text="Button 1" /> <Button text="Button 2"> <!-- Отдалечава Button 2 с 10px от левия му съсед --> <HBox.margin> <Insets left="10.0" /> </HBox.margin> </Button> </HBox>