Упражнение #2

В това упражнение ще се фокусираме върху изграждането на визуалната структура на JavaFX приложенията, използвайки Контейнери за изглед (Layout Controls) и FXML.

1. FXML – Декларативен UI дизайн

FXML е XML базиран език, който служи за дефиниране на потребителския интерфейс в JavaFX. Той позволява ясно разделение между визуалното представяне и програмната логика.

1.1. Структура на FXML файла

Всеки FXML файл следва строго определена структура, която се състои от три основни части:

  1. XML хедър: Първият ред винаги е стандартният XML дефиниционен ред:

<?xml version="1.0" encoding="UTF-8"?>

  1. Инструкции за импортиране (<?import ...?>):

В FXML не можем да използваме графични елементи, без да сме ги импортирали. Те съответстват директно на import операторите в Java.

Пример: За да използваме Button, трябва да добавим <?import javafx.scene.control.Button?>. Могат да се използват и маски: <?import javafx.scene.layout.*?>.

  1. Коренов елемент (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>
    

Table of contents


This site uses Just the Docs, a documentation theme for Jekyll.