init commit
This commit is contained in:
commit
1427029da0
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
build/
|
||||
*.class
|
||||
10
Main.java
Normal file
10
Main.java
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
import src.Application;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args)
|
||||
{
|
||||
Application app = new Application();
|
||||
app.run();
|
||||
}
|
||||
}
|
||||
210
run.sh
Executable file
210
run.sh
Executable file
@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
APP_NAME="calci"
|
||||
BUILD_DIR="build"
|
||||
MAIN_CLASS="Main"
|
||||
USE_UI=0
|
||||
IGNORE_PATTERNS=()
|
||||
|
||||
########################################
|
||||
# USER-FACING (CLI surface)
|
||||
########################################
|
||||
|
||||
print_help() {
|
||||
cat <<EOF
|
||||
$APP_NAME runner
|
||||
|
||||
Usage: ./run.sh [options]
|
||||
|
||||
Options:
|
||||
--main <Class> Set the main class to run (default: Main)
|
||||
--ui Enable JavaFX modules (tries to auto-detect JAVAFX_HOME)
|
||||
--ignore a|b|c Ignore files/dirs (split by |) when copying resources
|
||||
--help Show this help message
|
||||
EOF
|
||||
}
|
||||
|
||||
########################################
|
||||
# BACKEND (work logic)
|
||||
########################################
|
||||
|
||||
compile_sources() {
|
||||
echo "🛠️ Compiling sources..."
|
||||
if [ $USE_UI -eq 1 ]; then
|
||||
detect_javafx
|
||||
javac --module-path "$JAVAFX_HOME/lib" \
|
||||
--add-modules javafx.controls,javafx.fxml,javafx.swing \
|
||||
-d "$BUILD_DIR" $(find src -name "*.java")
|
||||
else
|
||||
javac -d "$BUILD_DIR" $(find src -name "*.java")
|
||||
fi
|
||||
}
|
||||
|
||||
copy_resources() {
|
||||
echo "📦 Copying resources..."
|
||||
|
||||
# Build rsync exclude flags
|
||||
local excludes=( "--exclude=*.java" )
|
||||
for pat in "${IGNORE_PATTERNS[@]}"; do
|
||||
excludes+=( "--exclude=$pat" )
|
||||
done
|
||||
|
||||
rsync -a "${excludes[@]}" ./ "$BUILD_DIR"/
|
||||
}
|
||||
|
||||
run_app() {
|
||||
echo "🚀 Running $MAIN_CLASS..."
|
||||
if [ $USE_UI -eq 1 ]; then
|
||||
java --module-path "$JAVAFX_HOME/lib" \
|
||||
--add-modules javafx.controls,javafx.fxml,javafx.swing \
|
||||
-cp "$BUILD_DIR" "$MAIN_CLASS"
|
||||
else
|
||||
java -cp "$BUILD_DIR" "$MAIN_CLASS"
|
||||
fi
|
||||
}
|
||||
|
||||
detect_javafx() {
|
||||
if [ -n "$JAVAFX_HOME" ]; then
|
||||
return
|
||||
fi
|
||||
echo "🔍 Trying to auto-detect JavaFX SDK..."
|
||||
for path in \
|
||||
"/usr/share/openjfx" \
|
||||
"/usr/share/java/openjfx" \
|
||||
"/usr/lib/jvm/javafx-sdk-21" \
|
||||
"/usr/lib/jvm/javafx-sdk-17" \
|
||||
"$HOME/javafx-sdk-21" \
|
||||
"$HOME/javafx-sdk-17"; do
|
||||
if [ -d "$path/lib" ]; then
|
||||
JAVAFX_HOME="$path"
|
||||
echo "✅ Found JavaFX SDK at $JAVAFX_HOME"
|
||||
return
|
||||
fi
|
||||
done
|
||||
ask_user_install_javafx
|
||||
if [ ! -d "$JAVAFX_HOME/lib" ]; then
|
||||
echo "Warning: Installed JavaFX but still cannot find lib/. Please set JAVAFX_HOME manually."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
########################################
|
||||
# HELPERS (system checks, installs)
|
||||
########################################
|
||||
|
||||
ask_install() {
|
||||
local tool=$1
|
||||
if ! command -v "$tool" >/dev/null 2>&1; then
|
||||
echo "Error: $tool is not installed."
|
||||
read -rp "Do you want to install $tool now? (y/n) " choice
|
||||
case "$choice" in
|
||||
y|Y)
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
sudo apt-get update && sudo apt-get install -y default-jdk
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
sudo dnf install -y java-17-openjdk-devel
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
sudo pacman -S --noconfirm jdk-openjdk
|
||||
else
|
||||
echo "Package manager not supported, please install $tool manually."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
try_install_javafx() {
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
sudo apt-get update && sudo apt-get install -y openjfx
|
||||
JAVAFX_HOME="/usr/share/openjfx"
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
sudo dnf install -y openjfx
|
||||
JAVAFX_HOME="/usr/share/openjfx"
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
sudo pacman -S --noconfirm javafx21-openjdk
|
||||
JAVAFX_HOME="/usr/lib/jvm/javafx-sdk-21"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
ask_user_install_javafx() {
|
||||
echo "❌ Could not find JavaFX SDK."
|
||||
read -rp "Do you want to install JavaFX now? (y/n) " choice
|
||||
case "$choice" in
|
||||
y|Y)
|
||||
try_install_javafx || ask_user_custom_command
|
||||
;;
|
||||
*)
|
||||
echo "Please install JavaFX manually and set JAVAFX_HOME."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
ask_user_custom_command() {
|
||||
echo "⚠️ No supported package manager detected."
|
||||
read -rp "Do you want to enter a custom install command? (y/n) " custom
|
||||
case "$custom" in
|
||||
y|Y)
|
||||
read -rp "Enter install command: " cmd
|
||||
if [ -n "$cmd" ]; then
|
||||
echo "Running: $cmd"
|
||||
if ! eval "$cmd"; then
|
||||
echo "❌ Installation command failed."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "No command entered. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Please download JavaFX manually:"
|
||||
echo "👉 https://gluonhq.com/products/javafx/"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
########################################
|
||||
# ENTRYPOINT
|
||||
########################################
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--main)
|
||||
MAIN_CLASS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--ui)
|
||||
USE_UI=1
|
||||
shift
|
||||
;;
|
||||
--ignore)
|
||||
IFS='|' read -ra IGNORE_PATTERNS <<< "$2"
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
print_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
ask_install javac
|
||||
ask_install java
|
||||
mkdir -p "$BUILD_DIR"
|
||||
|
||||
compile_sources
|
||||
copy_resources
|
||||
run_app
|
||||
3
sources.txt
Normal file
3
sources.txt
Normal file
@ -0,0 +1,3 @@
|
||||
src/Base.java
|
||||
src/Application.java
|
||||
Main.java
|
||||
25
src/Application.java
Normal file
25
src/Application.java
Normal file
@ -0,0 +1,25 @@
|
||||
package src;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
|
||||
public class Application extends Base {
|
||||
public Application() {
|
||||
super("Hello FXML", 675, 600);
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void sayHello() {
|
||||
System.out.println("Hello from FXML!");
|
||||
}
|
||||
|
||||
protected void on_button_click(String label) {
|
||||
System.out.println("Button clicked: " + label);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initUi() {
|
||||
loadUi("./hello.fxml");
|
||||
}
|
||||
}
|
||||
|
||||
82
src/Base.java
Normal file
82
src/Base.java
Normal file
@ -0,0 +1,82 @@
|
||||
package src;
|
||||
|
||||
import javafx.embed.swing.JFXPanel;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
public abstract class Base {
|
||||
private final JFrame frame;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final String title;
|
||||
|
||||
public Base(String title, int width, int height) {
|
||||
this.title = title;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
frame = new JFrame(title);
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.setSize(width, height);
|
||||
frame.setResizable(false);
|
||||
JFXPanel fxPanel = new JFXPanel();
|
||||
frame.add(fxPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
initUi();
|
||||
SwingUtilities.invokeLater(() -> frame.setVisible(true));
|
||||
}
|
||||
|
||||
public abstract void initUi();
|
||||
|
||||
protected abstract void on_button_click(String label);
|
||||
|
||||
@FXML
|
||||
protected void button_click(MouseEvent e) {
|
||||
if (e.getSource() instanceof Button btn) {
|
||||
on_button_click(btn.getText());
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadUi(String fxmlPath) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
String resolvedPath;
|
||||
if (fxmlPath.startsWith("./")) {
|
||||
resolvedPath = "/src/views" + fxmlPath.substring(1);
|
||||
} else {
|
||||
resolvedPath = fxmlPath.startsWith("/") ? fxmlPath : "/" + fxmlPath;
|
||||
}
|
||||
|
||||
JFXPanel fxPanel = (JFXPanel) frame.getContentPane().getComponent(0);
|
||||
|
||||
URL url = getClass().getResource(resolvedPath);
|
||||
if (url == null) {
|
||||
throw new IllegalStateException("FXML not found: " + resolvedPath);
|
||||
}
|
||||
|
||||
FXMLLoader loader = new FXMLLoader(url);
|
||||
loader.setController(this);
|
||||
Parent root = loader.load();
|
||||
|
||||
javafx.application.Platform.runLater(() -> {
|
||||
Scene scene = new Scene(root, width, height);
|
||||
fxPanel.setScene(scene);
|
||||
});
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
60
src/views/hello.fxml
Executable file
60
src/views/hello.fxml
Executable file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TitledPane?>
|
||||
<?import javafx.scene.layout.ColumnConstraints?>
|
||||
<?import javafx.scene.layout.GridPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.RowConstraints?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<TitledPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="675.0" xmlns="http://javafx.com/javafx/24.0.1" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<content>
|
||||
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="450.0" prefWidth="600.0">
|
||||
<children>
|
||||
<Label fx:id="label" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="80.0" prefWidth="584.0" text="Label" />
|
||||
<HBox prefHeight="450.0" prefWidth="675.0">
|
||||
<children>
|
||||
<GridPane maxWidth="1.7976931348623157E308" prefHeight="282.0" prefWidth="595.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="Button" GridPane.rowIndex="1" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="8" GridPane.columnIndex="1" GridPane.rowIndex="1" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="9" GridPane.columnIndex="2" GridPane.rowIndex="1" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" prefHeight="0.0" prefWidth="100.0" text="+" GridPane.columnIndex="3" GridPane.rowIndex="1" GridPane.rowSpan="2" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="4" GridPane.rowIndex="2" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="5" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="7" GridPane.rowIndex="1" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="6" GridPane.columnIndex="2" GridPane.rowIndex="2" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="1" GridPane.rowIndex="3" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="2" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="3" GridPane.columnIndex="2" GridPane.rowIndex="3" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="=" GridPane.columnIndex="3" GridPane.rowIndex="3" GridPane.rowSpan="2" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="0" GridPane.rowIndex="4" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="." GridPane.columnIndex="1" GridPane.rowIndex="4" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="+/-" GridPane.columnIndex="2" GridPane.rowIndex="4" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="CLR" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="/" GridPane.columnIndex="1" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="*" GridPane.columnIndex="2" />
|
||||
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="-" GridPane.columnIndex="3" />
|
||||
</children>
|
||||
</GridPane>
|
||||
</children>
|
||||
</HBox>
|
||||
</children>
|
||||
</VBox>
|
||||
</content>
|
||||
</TitledPane>
|
||||
Loading…
x
Reference in New Issue
Block a user