Русский
Русский
English
Статистика
Реклама

Javafx

Радио с записью станций на языке Java

19.03.2021 14:20:53 | Автор: admin

Привет всем! Как я уже говорил в своем первом посте, я не программист, а скорее любитель. Пробовал писать свои поделки на разных языках, но начинал я с Java. Больше всего из семейства Java мне понравилась платформа JavaFX. Точнее сказать, связка JavaFX + FXML, где в контроллере расписываем логику, а графический интерфейс описываем в отдельном fxml-файле. Радио как раз написано с помощью этой связки.

Для воспроизведения применяется библиотека JLayer. Встроенный класс MediaPlayer почему-то отказался у меня работать. Запись и воспроизведение сделаны в отдельных потоках. Ради эксперимента пробовал запустить воспроизведение в основном потоке приложения. Получил намертво зависший интерфейс. То же самое получил и при попытке записи в основном потоке.

Полностью код приложения доступен в репозитории GitHub. Приложение было создано с помощью среды разработки NetBeans 8.2 и конструктора Scene Builder от компании Gluon. В этом посте я не ставил целью полностью рассмотреть код приложения, а лишь остановился на некоторых, самых интересных, на мой взгляд, моментах.

Внешний вид

Вот так программа выглядит:

В меню Station находятся пункты для создания, удаления и изменения станции. В меню Record можно найти пункты для начала и остановки записи, а также для изменения директории записи. В меню Reference имеется пункт для выхода из программы и пункт О Программе, показывающий некоторую информацию о приложении.

Содержимое файла разметки интерфейса. Все очень лаконично и понятно. Какие-то пояснения, я думаю, излишни.

<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.control.Button?><?import javafx.scene.control.Label?><?import javafx.scene.control.ListView?><?import javafx.scene.control.Menu?><?import javafx.scene.control.MenuBar?><?import javafx.scene.control.MenuItem?><?import javafx.scene.layout.AnchorPane?><?import javafx.scene.text.Font?><AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="300.0" prefWidth="535.0" xmlns="http://personeltest.ru/away/javafx.com/javafx/8.0.171" xmlns:fx="http://personeltest.ru/away/javafx.com/fxml/1" fx:controller="radioplayer.PlayerController">   <ListView fx:id="stationsListView" focusTraversable="false" layoutX="14.0" layoutY="36.0" prefHeight="246.0" prefWidth="200.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.topAnchor="36.0" />   <Button fx:id="playButton" focusTraversable="false" layoutX="240.0" layoutY="177.0" mnemonicParsing="false" onAction="#playAction" prefHeight="103.0" prefWidth="130.0" text="PLAY" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="165.0">      <font>         <Font name="System Bold" size="22.0" />      </font></Button>   <Button fx:id="stopButton" focusTraversable="false" layoutX="391.0" layoutY="177.0" mnemonicParsing="false" onAction="#stopAction" prefHeight="103.0" prefWidth="130.0" text="STOP" AnchorPane.bottomAnchor="14.0" AnchorPane.rightAnchor="14.0">      <font>         <Font name="System Bold" size="22.0" />      </font></Button>   <Label fx:id="nameStation" layoutX="240.0" layoutY="46.0" prefHeight="113.0" prefWidth="279.0" wrapText="true" AnchorPane.bottomAnchor="141.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="36.0">      <font>         <Font name="System Bold Italic" size="24.0" />      </font></Label>   <MenuBar prefHeight="29.0" prefWidth="535.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">     <menus>       <Menu mnemonicParsing="false" text="Station">         <items>           <MenuItem mnemonicParsing="false" onAction="#addAction" text="Add" />           <MenuItem mnemonicParsing="false" onAction="#editAction" text="Edit" />           <MenuItem mnemonicParsing="false" onAction="#deleteAction" text="Delete" />         </items>       </Menu>       <Menu mnemonicParsing="false" text="Record">         <items>           <MenuItem fx:id="recordItem" mnemonicParsing="false" onAction="#recordAction" text="To begin" />           <MenuItem fx:id="stopRecordItem" mnemonicParsing="false" onAction="#stopRecordAction" text="Stop" />           <MenuItem mnemonicParsing="false" onAction="#directoryRecordAction" text="Records Directory" />         </items>       </Menu>       <Menu mnemonicParsing="false" text="Reference">         <items>           <MenuItem mnemonicParsing="false" onAction="#appInfoAction" text="About the program" />           <MenuItem mnemonicParsing="false" onAction="#exitAction" text="Exit" />         </items>       </Menu>     </menus>   </MenuBar></AnchorPane>

Файл стилей (toast это всплывающие сообщения. О них позже):

.root{    -fx-background-color: grey;}.button{    -fx-background-radius: 40;    -fx-border-radius: 40;    -fx-text-fill: white;}.button:hover{    -fx-background-color: derive(-fx-base, 18%);    -fx-border-style: solid;    -fx-border-width: 1;    -fx-border-color: derive(-fx-base, -15%);    -fx-cursor: hand;}.button:pressed{    -fx-text-fill: black;}.list-view, .list-view .viewport, .list-view .content{    -fx-background-color: gainsboro;}.list-view:hover{    -fx-cursor: hand;}.toast{    -fx-background-radius: 30;    -fx-border-radius: 30;    -fx-background-color: black;    -fx-padding: 20;}#nameStation{    -fx-text-fill: white;}#playButton{    -fx-background-color: blue;}#stopButton{    -fx-background-color: red;}

Воспроизведение и запись

Воспроизведение происходит с помощью этого кода:

taskPlayer = new Task() {            @Override            public Void call() {                try {                    radioUrl = new URL(urlString);                    InputStream in = radioUrl.openStream();                    InputStream is = new BufferedInputStream(in);                    player = new Player(is);                    player.play();                } catch (FileNotFoundException e) {                    e.getMessage();                } catch (IOException | JavaLayerException e) {                    e.getMessage();                }                return null;            }        };        new Thread(taskPlayer).start();

В отличие от воспроизведения, при записи никаких сторонних библиотек не используется. Как уже говорилось, для воспроизведения применяется библиотека JLayer. Запись происходит так:

taskRecord=new Task() {            @Override            public Void call() throws FileNotFoundException, IOException{                    output = new FileOutputStream(reader(file.getAbsolutePath())+                            separator+nameStation.getText()+"-"+new Date().toString().replace(":","-")+".mp3");                    InputStream in = radioUrl.openStream();                    InputStream is = new BufferedInputStream(in);                    byte data[] = new byte[1024];                    int count;                    while ((count = is.read(data)) != -1) {                        output.write(data, 0, count);                    }                output.flush();                return null;            }        };        new Thread(taskRecord).start();

Станции

Станции хранятся в виде текстовых файлов, где имя файла представляет собой название станции, а содержимое это ее URL. Вот метод, который создает станции при первом запуске:

private void createDefaultStations(){         String[] stationNames = {"NonStopPlay","Classical Music","Fip Radio","Jazz Legends","Joy Radio","Live-icy","Music Radio","Radio Electron","Dubstep","Trancemission"};         String[] stationUrls = {"http://stream.nonstopplay.co.uk/nsp-128k-mp3","http://stream.srg-ssr.ch/m/rsc_de/mp3_128","http://direct.fipradio.fr/live/fip-midfi.mp3","http://jazz128legends.streamr.ru/","http://airtime.joyradio.cc:8000/airtime_192.mp3","http://live-icy.gss.dr.dk:8000/A/A05H.mp3","http://ice-the.musicradio.com/CapitalXTRANationalMP3","http://radio-electron.ru:8000/128","http://air.radiorecord.ru:8102/dub_320","http://air.radiorecord.ru:8102/tm_320"};         for(int i=0;i<10;i++){             writer(path+separator+stationNames[i], stationUrls[i]);         }    }

Вызов этого метода происходит из другого метода dirCreator, который создает директорию RadioStations, где хранятся файлы станций. Вот этот метод:

private void dirCreator(final String fPath) {        final File file = new File(fPath);        if (!file.exists()) {            file.mkdir();            if(file.exists()){                alertWindow("The <RadioStations> directory has been created.\nYour radio stations will be here:\n"+fPath);                createDefaultStations();            }else{                alertWindow("Error!\nThe <RadioStations> directory will not be created.\n" +                        "Try creating the specified directory manually in the following path:\n"+fPath+"\nThe program will be closed.");                System.exit(0);            }        }    }

Разрешения на чтение и запись

Следующие методы проверяют разрешения на чтение и запись. Если разрешение отсутствует, то пытаются установить его:

private boolean permissionRead(File file){        if(!file.canRead()){            file.setReadable(true);            return !file.canRead();        }        return false;    }    private boolean permissionWrite(File file){        if(!file.canWrite()){            file.setWritable(true);            return !file.canWrite();        }        return false;    }

Применяются эти методы в инициализаторе для проверки разрешений для папки RadioStations:

@Override    public void initialize(URL url, ResourceBundle rb) {        parentPath = System.getProperty("user.home");        path=parentPath+separator+"RadioStations";        this.dirCreator(this.path);        File f=new File(path);        if(permissionRead(f)||permissionWrite(f)){            if(permissionRead(f)&&permissionWrite(f)){                alertWindow("Failed to get permission to read and write files to the <RadioStations> directory.\nTry to give permission manually.");            }else if(permissionRead(f)){                alertWindow("Failed to get permission to read files in directory <RadioStations>.\nTry to give permission manually.");            }else{                alertWindow("Failed to get permission to write files to <RadioStations> directory.\nTry to give permission manually.");            }            System.exit(0);        }        showStationsList();        stopButton.setDisable(true);        recordItem.setDisable(true);        stopRecordItem.setDisable(true);    }   

Диалоги

Для построения диалогов я не использовал визуальный конструктор, а писал все вручную. Например, вот диалог, который появляется перед записью. Программа спрашивает куда сохранять запись:

final Alert alert = new Alert(Alert.AlertType.CONFIRMATION);        alert.setResizable(true);        alert.getDialogPane().setPrefSize(500,200);        alert.setTitle("Saving Recordings");        alert.setHeaderText("");        alert.setContentText("The default path for your recordings is:\n"+f.getAbsolutePath()+"\nChange?");                ButtonType buttonTypeEdit = new ButtonType("Edit", ButtonBar.ButtonData.OK_DONE);        ButtonType buttonTypeDefault = new ButtonType("Default", ButtonBar.ButtonData.FINISH);        ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);                alert.getButtonTypes().setAll(buttonTypeEdit, buttonTypeDefault, buttonTypeCancel);                final Optional<ButtonType> resultAlert = alert.showAndWait();

Вот окно диалога:

Конечно, программа каждый раз не будет доставать пользователя такими вопросами. Перед первой записью она покажет это окно и если пользователь выберет Edit, то откроется окно выбора папки, а если выберет Default, то диалог просто закроется и запись будет вестись в папку по умолчанию. Cancel отменяет запись.

Вот еще пример диалога. Это диалог добавления станции:

Dialog dialog = new Dialog<>();        dialog.setTitle("Station Creation");        dialog.setHeaderText("Enter the name and url of the radio station");        ButtonType createButtonType = new ButtonType("Create", ButtonBar.ButtonData.OK_DONE);        ButtonType cancelButtonType  = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);        dialog.getDialogPane().getButtonTypes().addAll(createButtonType,cancelButtonType);        GridPane grid = new GridPane();        grid.setHgap(10);        grid.setVgap(10);        grid.setPadding(new Insets(20, 150, 10, 10));        TextField stationName = new TextField();        TextField url = new TextField();        grid.add(new Label("Title:"), 0, 0);        grid.add(stationName, 1, 0);        grid.add(new Label("Url:"), 0, 1);        grid.add(url, 1, 1);        dialog.getDialogPane().setContent(grid);        Optional<ButtonType> result = dialog.showAndWait();

Здесь все просто. Получаем окно с двумя текстовыми полями. Вот такое:

Окно диалога для изменения станций такое же, только поля заполнены данными изменяемой станции.

Заставка

Перед запуском приложения сначала появляется заставка. Для этого в проект был добавлен специальный класс. В настройках запуска проекта его нужно указать как стартовый.

package radioplayer;import javafx.application.Application;import java.awt.*;import javafx.stage.Stage;/** * * @author alex */public class Splash extends Application{        public static void main(final String[] args) {        SplashScreen splash = SplashScreen.getSplashScreen();        try {            Thread.sleep(3000L);        }        catch (InterruptedException ex) {            ex.getMessage();        }        if (splash != null) {            splash.close();            Application.launch(RadioPlayer.class, args);        }    }    @Override    public void start(Stage primaryStage) throws Exception {        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.    }}

Сама заставка:

Там же в настройках нужно указать следующие параметры для виртуальной машины:

-splash:src/images/splash.png

В манифест приложения следует добавить:

SplashScreen-Image: images/splash.png

Всплывающие сообщения, как в Android

В приложении имеются всплывающие сообщения, которые выглядят как подобные сообщения в Android OS. Вот пример сообщения:

За их появления отвечает отдельный класс:

package radioplayer;import javafx.animation.KeyFrame;import javafx.animation.KeyValue;import javafx.animation.Timeline;import javafx.scene.Scene;import javafx.scene.layout.StackPane;import javafx.scene.paint.Color;import javafx.scene.text.Font;import javafx.scene.text.Text;import javafx.stage.Stage;import javafx.stage.StageStyle;import javafx.util.Duration;/** * * @author alex */public class Toast {    void setMessage(final String toastMsg){        Stage toastStage=new Stage();        toastStage.setResizable(false);        toastStage.initStyle(StageStyle.TRANSPARENT);        Text t = new Text(toastMsg);        t.setFont(Font.font("Verdana",20));        t.setFill(Color.WHITE);        StackPane root = new StackPane(t);        root.getStyleClass().add("toast");        root.setOpacity(0);        Scene scene = new Scene(root);        scene.getStylesheets().add((getClass().getResource("style.css")).toExternalForm());        scene.setFill(null);        toastStage.setScene(scene);        toastStage.show();        Timeline tl1 = new Timeline();        KeyFrame fadeInKey1 = new KeyFrame(Duration.millis(500),new KeyValue (toastStage.getScene().getRoot().opacityProperty(), 1));        tl1.getKeyFrames().add(fadeInKey1);        tl1.setOnFinished((ae) ->                new Thread(() -> {                    try {                        Thread.sleep(3000);                    } catch (InterruptedException e) {                        e.getMessage();                    }                    Timeline tl2 = new Timeline();                    KeyFrame fadeOutKey1 = new KeyFrame(Duration.millis(500), new KeyValue(toastStage.getScene().getRoot().opacityProperty(), 0));                    tl2.getKeyFrames().add(fadeOutKey1);                    tl2.setOnFinished((aeb) -> toastStage.close());                    tl2.play();                }).start());        tl1.play();    }}

Сборка

Если создавать исполняемый архив, просто нажав в NetBeans кнопку очистки и сборки проекта, мы получим архив, который не будет содержать в себе классы библиотеки JLayer. В манифесте этого архива будет прописан путь до библиотеки. Программа будет работать, только если библиотека будет расположена по этому пути.

Чтобы классы библиотеки JLayer запаковать в исполняемый архив, нужно в файле build.xml дописать следующее:

<target name="package-for-store" depends="jar">    <property name="store.jar.name" value="Radio"/>    <property name="store.dir" value="store"/>    <property name="store.jar" value="${store.dir}/${store.jar.name}.jar"/>    <echo message="Packaging ${application.title} into a single JAR at ${store.jar}"/>    <delete dir="${store.dir}"/>    <mkdir dir="${store.dir}"/>    <jar destfile="${store.dir}/temp_final.jar" filesetmanifest="skip">        <zipgroupfileset dir="dist" includes="*.jar"/>        <zipgroupfileset dir="dist/lib" includes="*.jar"/>        <manifest>            <attribute name="Main-Class" value="radioplayer.Splash"/>            <attribute name="SplashScreen-Image" value="images/splash.png"/>        </manifest>    </jar>    <zip destfile="${store.jar}">        <zipfileset src="${store.dir}/temp_final.jar"        excludes="META-INF/*.SF, META-INF/*.DSA, META-INF/*.RSA"/>    </zip>    <delete file="${store.dir}/temp_final.jar"/></target>

Для сборки в меню нужно выбрать выполнить цель, а в подменю найти package-for-store. В папке store появится готовый архив.

Дополнительная ссылка на SourceForge. До встречи в следующих постах!

Подробнее..

Из песочницы Написание десктопного приложения с помощью JavaFX

09.09.2020 16:16:51 | Автор: admin
Решил я написать исполняемый jar файл с удобным интерфейсом для расчета своих повседневных задач по работе. Начал с самых простых.

image

Нужно определить критические напряжения на сдвиг исходя из типа закрепления и отношения сторон прямоугольной пластины.

Начнем с настройка интерфейса, а в помощь возьмем Scene Builder


Создадим рабочую область с размером 900х600.

image

Создадим несколько контейнеров c размерами и отступами(я сначала разметку делал просто на листочке, но листочек уже потерялся).

image

Далее пройдемся по внутренним элементам контейнеров


  1. Кнопка Button
    Присвоим уникальное имя нашей кнопки и название метода в котором потом будем реализовывать наш код

    image
  2. Поле TextField
    Присвоим уникальное имя нашему текстовому полю. Поле понадобиться для ввода/вывода числовых значения. Так же добавим дополнительное имя полю, которое при вводе символом будет пропадать

    image

    image
  3. Поле Label
    Поле Label я использовал для обозначения ячеек.
  4. Поле Image
    Тут указываем имя существующей картинки находящийся в проекте

    image
  5. Поле CheckBox
    Тут указываем уникальное имя. Это необходимо для определения типа закрепления

    image

Конечный код файла sample.fxml

Листинг sample.fxml
<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.control.Button?><?import javafx.scene.control.CheckBox?><?import javafx.scene.control.Label?><?import javafx.scene.control.TextField?><?import javafx.scene.image.Image?><?import javafx.scene.image.ImageView?><?import javafx.scene.layout.GridPane?><?import javafx.scene.layout.Pane?><?import javafx.scene.layout.VBox?><Pane prefHeight="600.0" prefWidth="900.0" xmlns="http://personeltest.ru/away/javafx.com/javafx/8.0.112" xmlns:fx="http://personeltest.ru/away/javafx.com/fxml/1" fx:controller="sample.Controller">   <children>      <Button fx:id="button" layoutX="40.0" layoutY="200.0" mnemonicParsing="false" onAction="#showDateTime" prefHeight="71.0" prefWidth="528.0" text="=" />      <VBox layoutX="312.0" layoutY="20.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="280.0" GridPane.columnIndex="1">         <children>            <TextField fx:id="myTextField1" promptText="Значение а" />            <TextField fx:id="myTextField2" promptText="значение b (наименьшая сторона)" />            <TextField fx:id="myTextField3" promptText="Толщина" />            <TextField fx:id="myTextField4" prefHeight="25.0" prefWidth="280.0" promptText="Модуль упругости Е" />            <TextField fx:id="myTextField6" prefHeight="25.0" prefWidth="280.0" promptText="Действующие напряжения" />         </children>      </VBox>      <VBox layoutX="611.0" prefHeight="562.0" prefWidth="271.0" GridPane.columnIndex="21">         <children>            <ImageView fx:id="image" fitHeight="116.0" fitWidth="174.0" pickOnBounds="true" preserveRatio="true">               <image>                  <Image url="@Zadelka1.PNG" />               </image></ImageView>            <CheckBox fx:id="checkbox1" mnemonicParsing="false" text="Все края защемлены" />            <ImageView fitHeight="122.0" fitWidth="237.0" layoutX="30.0" pickOnBounds="true" preserveRatio="true">               <image>                  <Image url="@Zadelka2.PNG" />               </image></ImageView>            <CheckBox fx:id="checkbox2" mnemonicParsing="false" text="Шарнир по верхним  и нижним кромкам" />            <ImageView fitHeight="127.0" fitWidth="272.0" pickOnBounds="true" preserveRatio="true">               <image>                  <Image url="@Zadelka3.PNG" />               </image></ImageView>            <CheckBox fx:id="checkbox3" mnemonicParsing="false" text="Шарнир по бокам" />            <ImageView fitHeight="129.0" fitWidth="392.0" pickOnBounds="true" preserveRatio="true">               <image>                  <Image url="@Zadelka4.PNG" />               </image></ImageView>            <CheckBox fx:id="checkbox4" mnemonicParsing="false" text="Шарнир кругом" />         </children>      </VBox>            <VBox layoutX="20.0" layoutY="20.0" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="262.0">         <children>            <Label prefHeight="25.0" prefWidth="185.0" text="Значение a" />            <Label prefHeight="25.0" prefWidth="262.0" text="Значение b (наименьшая сторона)" />            <Label prefHeight="25.0" prefWidth="188.0" text="Толщина" />            <Label prefHeight="25.0" prefWidth="186.0" text="Модуль упругости E" />            <Label prefHeight="25.0" prefWidth="188.0" text="Действующие напряжения" />         </children>      </VBox>      <VBox layoutX="312.0" layoutY="311.0" prefHeight="200.0" prefWidth="280.0">         <children>            <TextField fx:id="myTextField5" prefHeight="25.0" prefWidth="280.0" promptText="Касательное напряжения(кр)" />            <TextField fx:id="myTextField7" prefHeight="25.0" prefWidth="280.0" promptText="Запас прочности" />         </children>      </VBox>      <VBox layoutX="20.0" layoutY="310.0" prefHeight="200.0" prefWidth="262.0">         <children>            <Label prefHeight="25.0" prefWidth="260.0" text="Критическое касательное напряжения" />            <Label prefHeight="25.0" prefWidth="187.0" text="Запас прочности" />         </children>      </VBox>   </children>  </Pane>


Создание главного метода класса Main


Класс Main
package sample;import javafx.application.Application;import javafx.fxml.FXMLLoader;import javafx.scene.Parent;import javafx.scene.Scene;import javafx.stage.Stage;public class Main extends Application  {    @Override    public void start(Stage primaryStage) {        try {//Ссылка на sample.fxml(наш интерфейс).Название программы и создание нашей главной сцен            Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));            primaryStage.setTitle("Чистый сдвиг");            primaryStage.setScene(new Scene(root));            primaryStage.show();        } catch(Exception e) {            e.printStackTrace();        }    }    public static void main(String[] args)  {        launch(args);    }}


Создания класса Controller.Самое важное помечено комментариями


Класс Controller
ackage sample;import javafx.fxml.FXML;import javafx.fxml.Initializable;import javafx.scene.control.Button;import javafx.scene.control.CheckBox;import javafx.scene.control.TextField;import javafx.stage.Stage;import java.net.URL;import java.util.ResourceBundle;import static java.lang.Double.NaN;import static java.lang.Double.parseDouble;import static java.lang.String.valueOf;public class Controller extends TextField implements Initializable  {//Создание переменных разлчиных типов связанных с интерфейсом    @FXML    private TextField myTextField4;    @FXML    private TextField myTextField1;    @FXML    private TextField myTextField2;    @FXML    private TextField myTextField3;    @FXML    private TextField myTextField5;    @FXML    private TextField myTextField6;    @FXML    private TextField myTextField7;    @FXML    private CheckBox checkbox1;    @FXML    private CheckBox checkbox2;    @FXML    private CheckBox checkbox3;    @FXML    private CheckBox checkbox4;    private double k;    private double krit;    private double zapas;    @Override    public void initialize(URL location, ResourceBundle resources) {                //Применения фильтра для ввода параметров        myTextField1.setTextFormatter(new AlphaNumericTextFormatter());        myTextField2.setTextFormatter(new AlphaNumericTextFormatter());        myTextField3.setTextFormatter(new AlphaNumericTextFormatter());        myTextField4.setTextFormatter(new AlphaNumericTextFormatter());        //myTextField6.setTextFormatter(new AlphaNumericTextFormatter());    }    public void showDateTime() throws Exception {//Перевод строки в число        Double a = parseDouble(myTextField1.getText());        Double b = parseDouble(myTextField2.getText());        Double t = parseDouble(myTextField3.getText());        Double e = parseDouble(myTextField4.getText());        Double c = b / a;//Условия выбора CheckBox и отношения стороны        if (checkbox1.isSelected()) {            if (c <= 0.1) {                k = 8;            } else if ((c > 0.1) && (c <= 0.15)) {                k = 8.5;            } else if ((c > 0.15) && (c <= 0.2)) {                k = 8.8;            } else if ((c > 0.2) && (c <= 0.25)) {                k = 9;            } else if ((c > 0.25) && (c <= 0.30)) {                k = 9.2;            } else if ((c > 0.3) && (c <= 0.35)) {                k = 9.5;            } else if ((c > 0.35) && (c <= 0.40)) {                k = 9.8;            } else if ((c > 0.40) && (c <= 0.45)) {                k = 10.3;            } else if ((c > 0.45) && (c <= 0.50)) {                k = 10.5;            } else if ((c > 0.5) && (c <= 0.55)) {                k = 10.8;            } else if ((c > 0.55) && (c <= 0.6)) {                k = 11;            } else if ((c > 0.6) && (c <= 0.65)) {                k = 11.5;            } else if ((c > 0.65) && (c <= 0.7)) {                k = 11.8;            } else if ((c > 0.7) && (c <= 0.75)) {                k = 12;            } else if ((c > 0.75) && (c <= 0.8)) {                k = 12.5;            } else if ((c > 0.8) && (c <= 0.85)) {                k = 12.8;            } else if ((c > 0.85) && (c <= 0.9)) {                k = 13;            } else if ((c > 0.9) && (c <= 0.95)) {                k = 13.5;            } else if ((c > 0.95) && (c <= 1)) {                k = 14;            }            krit = (k * e) / (Math.pow((b / t), 2));            String d = valueOf(krit);            //перевод числа в строку            myTextField5.setText(d);            }            else if (checkbox2.isSelected()) {                if (c <= 0.1) {                    k = 8;                } else if ((c > 0.1) && (c <= 0.15)) {                    k = 8.2;                } else if ((c > 0.15) && (c <= 0.2)) {                    k = 8.4;                } else if ((c > 0.2) && (c <= 0.25)) {                    k = 8.5;                } else if ((c > 0.25) && (c <= 0.30)) {                    k = 8.6;                } else if ((c > 0.3) && (c <= 0.35)) {                    k = 8.7;                } else if ((c > 0.35) && (c <= 0.40)) {                    k = 8.9;                } else if ((c > 0.40) && (c <= 0.45)) {                    k = 9;                } else if ((c > 0.45) && (c <= 0.50)) {                    k = 9.2;                } else if ((c > 0.5) && (c <= 0.55)) {                    k = 9.4;                } else if ((c > 0.55) && (c <= 0.6)) {                    k = 9.5;                } else if ((c > 0.6) && (c <= 0.65)) {                    k = 9.7;                } else if ((c > 0.65) && (c <= 0.7)) {                    k = 10;                } else if ((c > 0.7) && (c <= 0.75)) {                    k = 10;                } else if ((c > 0.75) && (c <= 0.8)) {                    k = 10.2;                } else if ((c > 0.8) && (c <= 0.85)) {                    k = 10.5;                } else if ((c > 0.85) && (c <= 0.9)) {                    k = 10.6;                } else if ((c > 0.9) && (c <= 0.95)) {                    k = 11;                } else if ((c > 0.95) && (c <= 1)) {                    k = 11;                }            krit = (k * e) / (Math.pow((b / t), 2));            String d = valueOf(krit);            myTextField5.setText(d);            }        else if (checkbox3.isSelected()) {            if (c <= 0.1) {                k = 4.9;            } else if ((c > 0.1) && (c <= 0.15)) {                k = 5.1;            } else if ((c > 0.15) && (c <= 0.2)) {                k = 5.2;            } else if ((c > 0.2) && (c <= 0.25)) {                k = 5.5;            } else if ((c > 0.25) && (c <= 0.30)) {                k = 5.8;            } else if ((c > 0.3) && (c <= 0.35)) {                k = 6;            } else if ((c > 0.35) && (c <= 0.40)) {                k = 6.2;            } else if ((c > 0.40) && (c <= 0.45)) {                k = 6.5;            } else if ((c > 0.45) && (c <= 0.50)) {                k = 6.9;            } else if ((c > 0.5) && (c <= 0.55)) {                k = 7;            } else if ((c > 0.55) && (c <= 0.6)) {                k = 7.5;            } else if ((c > 0.6) && (c <= 0.65)) {                k = 8;            } else if ((c > 0.65) && (c <= 0.7)) {                k = 8.2;            } else if ((c > 0.7) && (c <= 0.75)) {                k = 8.5;            } else if ((c > 0.75) && (c <= 0.8)) {                k = 9.1;            } else if ((c > 0.8) && (c <= 0.85)) {                k = 9.5;            } else if ((c > 0.85) && (c <= 0.9)) {                k = 10;            } else if ((c > 0.9) && (c <= 0.95)) {                k = 10.5;            } else if ((c > 0.95) && (c <= 1)) {                k = 11;            }            krit = (k * e) / (Math.pow((b / t), 2));            String d = valueOf(krit);            myTextField5.setText(d);        }        else if (checkbox4.isSelected()) {            if (c <= 0.1) {                k = 4.8;            } else if ((c > 0.1) && (c <= 0.15)) {                k = 5;            } else if ((c > 0.15) && (c <= 0.2)) {                k = 5;            } else if ((c > 0.2) && (c <= 0.25)) {                k = 5.1;            } else if ((c > 0.25) && (c <= 0.30)) {                k = 5.2;            } else if ((c > 0.3) && (c <= 0.35)) {                k = 5.4;            } else if ((c > 0.35) && (c <= 0.40)) {                k = 5.5;            } else if ((c > 0.40) && (c <= 0.45)) {                k = 5.6;            } else if ((c > 0.45) && (c <= 0.50)) {                k = 5.9;            } else if ((c > 0.5) && (c <= 0.55)) {                k = 6;            } else if ((c > 0.55) && (c <= 0.6)) {                k = 6.2;            } else if ((c > 0.6) && (c <= 0.65)) {                k = 6.5;            } else if ((c > 0.65) && (c <= 0.7)) {                k = 6.7;            } else if ((c > 0.7) && (c <= 0.75)) {                k = 7;            } else if ((c > 0.75) && (c <= 0.8)) {                k = 7.1;            } else if ((c > 0.8) && (c <= 0.85)) {                k = 7.4;            } else if ((c > 0.85) && (c <= 0.9)) {                k = 7.8;            } else if ((c > 0.9) && (c <= 0.95)) {                k = 8;            } else if ((c > 0.95) && (c <= 1)) {                k = 8.3;            }            krit = (k * e) / (Math.pow((b / t), 2));            String d = valueOf(krit);            myTextField5.setText(d);        }        Double f = parseDouble(myTextField6.getText());            zapas = krit/f;            String g = valueOf(zapas);            myTextField7.setText(g);        }        }


Создание двух классов для применения фильтра ввода данных (Исключение букв, а так же возможность ограничения количества вводы/выводы). Решения не мое, а нашел я его на stackoverflow.Из всех предложенных оно мне показалось самым простым и понятным.

Класс AlphaNumericTextFormatter

Класс AlphaNumericTextFormatter
public class AlphaNumericTextFormatter extends TextFormatter<String> {    /** The Constant ALPHA_NUMERIC_ONLY. */    //private static final String ALPHA_NUMERIC_ONLY = "^[a-zA-Z0-9]*$";    /** MAKE NUMERIC ONLY **/    private static final String DIGITS_ONLY = "^[0-9.]*$";    /**     * Instantiates a new alpha numeric text formatter.     */    public AlphaNumericTextFormatter() {        super(applyFilter(null));    }    /**     * Instantiates a new alpha numeric text formatter.     *     * @param maxLength     *            the max length     */    public AlphaNumericTextFormatter(int maxLength) {        super(applyFilter(new MaxLengthTextFormatter(maxLength).getFilter()));    }    /**     * Apply filter.     *     * @param filter     *            the filter     * @return the unary operator     */    private static UnaryOperator<Change> applyFilter(UnaryOperator<Change> filter) {        return change -> {            if (change.getControlNewText() != null && change.getControlNewText().matches(DIGITS_ONLY)) {                if (filter != null) {                    filter.apply(change);                }                return change;            }            return null;        };    }}


Класс MaxLengthTextFormatter

Листинг кода
package sample;import java.util.function.UnaryOperator;import javafx.scene.control.TextFormatter;import javafx.scene.control.TextFormatter.Change;public class MaxLengthTextFormatter extends TextFormatter<String> {    private int maxLength;    public MaxLengthTextFormatter(final int maxLength) {        super(new UnaryOperator<Change>() {            public Change apply(Change change) {                if (change.isDeleted()) {                    if (change.getControlNewText().length() > maxLength) {                        change.setText(change.getText().substring(0, maxLength));                    }                } else if (change.getControlText().length() + change.getText().length() >= maxLength) {                    int maxPos = maxLength - change.getControlText().length();                    change.setText(change.getText().substring(0, maxPos));                }                return change;            }        });        this.maxLength = maxLength;    }    public int getMaxLength() {        return this.maxLength;    }}


Ну и в конце создания jar файла


image

image

На этом все. Теперь готов файл который будет запускаться на любом компьютере с установленной java.
Подробнее..
Категории: Java , Javafx

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru