2021년 11월 21일 일요일

Java FX API

1. Java FX API

package com.home.fx;

import javafx.beans.value.ChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;

import java.io.File;
import java.util.List;


public class FX {
	
	private static int fontSize = 12;
	private static int gap = 2;
	private static Insets padding = new Insets(0,0,0,0); //TRBL

	public static void setFontSize(Node node) {
		node.setStyle("-fx-font: " + fontSize + " arial;");
	}
	public static void setBackground(Node node) { node.setStyle("-fx-background-color: #D8BFD8;"); }
	public static void enable(Node node) { node.setDisable(false); }
	public static void diable(Node node) { node.setDisable(false); }
	public static void show(Node node) { node.setVisible(true); }
	public static void hide(Node node) { node.setVisible(false); }

	public static void setDropHandler(Node node, FxRunnable runnable) {
		node.setOnDragOver( event -> {
			if( event.getDragboard().hasFiles() ) {
				event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
			}
			event.consume();
		});
		node.setOnDragDropped(event -> {
			Dragboard db = event.getDragboard();
			boolean success = false;
			if( db.hasFiles() ) {
				success = true;
				List<File> files = db.getFiles();
				runnable.run(files);
			}
			event.setDropCompleted(success);
			event.consume();
		});
	}

	public static MenuBar getMenuBar() {
		MenuBar menubar = new MenuBar();
		Menu menu = new Menu("File");
		MenuItem item = new MenuItem("Exit");
		setFontSize(menubar);
		menu.setStyle("-fx-font: " + fontSize + " arial;");
		item.setStyle("-fx-font: " + fontSize + " arial;");
		item.setOnAction((e) -> System.exit(0));
		menu.getItems().add(item);
		menubar.getMenus().add(menu);
		return menubar;
	}

	public static SplitPane getHSplitPane(Double first) {
		SplitPane pane = new SplitPane();
		pane.setDividerPositions(first, 1 - first);
		pane.setOrientation(Orientation.HORIZONTAL);
		return pane;
	}
	public static SplitPane getHSplitPane() {
		return getHSplitPane(0.5);
	}
	public static SplitPane getVSplitPane(Double first) {
		SplitPane pane = new SplitPane();
		pane.setDividerPositions(first, 1 - first);
		pane.setOrientation(Orientation.VERTICAL);
		return pane;
	}
	public static SplitPane getVSplitPane() {
		return getVSplitPane(0.5);
	}
	public static void addSplitPane(SplitPane split, Node node) {
		split.getItems().add(node);
	}
	public static void addSplitPane(SplitPane split, Node node, Double size) {
		node.minWidth(size);
		node.maxWidth(size);
		split.getItems().add(node);
	}
	public static void addSplitPaneTwo(SplitPane split, Node left, Node right, Double size) {
		left.minWidth(size);
		left.maxWidth(size);
		split.getItems().addAll(left, right);
		//split.setDividerPositions(size / stage.getScene().getWidth());
	}
	public static void addSplitPaneAll(SplitPane split, Node...node) {
		for( int i = 0; i < node.length; i++ ) {
			split.getItems().add(node[i]);
		}
	}

	public static ScrollPane getScrollPane(Node node) {
		ScrollPane scroll = new ScrollPane(node);
		scroll.setVbarPolicy( ScrollPane.ScrollBarPolicy.ALWAYS );
		scroll.setHbarPolicy( ScrollPane.ScrollBarPolicy.ALWAYS );
		scroll.setPannable( true );
		scroll.setFitToWidth( true );
		scroll.setFitToHeight( true );
		return scroll;
	}

	public static Button getButton(String title, EventHandler<ActionEvent> action) {
		Button button = new Button();
		button.setText(title);
		setFontSize(button);
		button.setOnAction( action );
		return button;
	}

	public static ComboBox<String> getComboBox(Runnable runnable, String[] items) {
		ComboBox<String> combo = new ComboBox<>();
		setFontSize( combo );
		if (items != null) {
			combo.getItems().addAll(items);
			combo.getSelectionModel().select(0);
		}
		if (runnable != null) {
			combo.getSelectionModel().selectedItemProperty().addListener(
					(ChangeListener<String>) (observable, oldValue, newValue) -> runnable.run());
		}
		return combo;
	}
	public String getSelectedComboItem(ComboBox<String> combo) {
		return combo.getSelectionModel().getSelectedItem();
	}
	public int getSelectedComboIndex(ComboBox<String> combo) {
		return combo.getSelectionModel().getSelectedIndex();
	}

	public static TextArea getTextArea() {
		TextArea textArea = new TextArea();
		setFontSize(textArea);
		return textArea;
	}
	
	public static VBox getVBox() {
		VBox box = new VBox(gap); 
		box.setAlignment(Pos.CENTER);
		box.setSpacing(gap);
		box.setPadding(padding);		
		return box;
	}
	public static void addVbox(VBox box, Node node, boolean expand) {
		if( expand ) { VBox.setVgrow(node, Priority.ALWAYS);} 
		else         { VBox.setVgrow(node, Priority.NEVER); }
		box.getChildren().add(node);
	}
	public static HBox getHBox() {
		HBox box = new HBox(gap); 
		box.setAlignment(Pos.BASELINE_LEFT);
		box.setSpacing(gap);
		box.setPadding(padding);		
		return box;
	}
	public static void addHbox(HBox box, Node node, boolean expand) {
		if( expand ) { HBox.setHgrow(node, Priority.ALWAYS);} 
		else         { HBox.setHgrow(node, Priority.NEVER); }
		box.getChildren().add(node);
	}

	public static Node getToolTextArea() {
		TextArea textArea = new TextArea();
		VBox vbox = new VBox(gap); 
		HBox hbox = new HBox(gap);
		Button button = new Button("Paste Html");
		button.setOnAction((e) -> {
			if( Clipboard.getSystemClipboard().hasHtml() ) {
				textArea.clear();
				textArea.setText( Clipboard.getSystemClipboard().getHtml() );
			}
		});
		hbox.getChildren().add(button);
		textArea.setStyle("-fx-font: " + fontSize + " arial;");
		VBox.setVgrow(hbox, Priority.NEVER);
		VBox.setVgrow(textArea, Priority.ALWAYS);
		vbox.setAlignment(Pos.CENTER);
		vbox.setSpacing(gap);
		vbox.setPadding(padding);
		vbox.getChildren().add(hbox);
		vbox.getChildren().add(textArea);
		return vbox;
	}

	public static ImageView getImageView(Image image, Double width, Double height) {
		ImageView iv;
		if( image == null ) { iv = new ImageView(); }
		else { iv = new ImageView(image); }
		if( width != null ) iv.setFitWidth(width);
		if( height != null ) iv.setFitHeight(height);
		iv.setPreserveRatio(true);
		return iv;
	}
	public static ImageView getImageView() {
		return getImageView( null, null, null );
	}
	public static ImageView getImageView(Image image) {
		return getImageView( image, null, null );
	}
}

Java FX RichTextView API

1. Java FX RichTextView API

package com.home.fx;

import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.Clipboard;
import org.fxmisc.richtext.CodeArea;
import org.fxmisc.richtext.LineNumberFactory;

public class FxRichText extends CodeArea {

	//VirtualizedScrollPane scroll;
	CodeArea text;
	int fontSize = 14;

	public FxRichText(Scene scene) {
		text = this; //new CodeArea();
		text.setStyle("-fx-font: " + fontSize + " arial;");
		text.setParagraphGraphicFactory(LineNumberFactory.get(text));

		ContextMenu menu = new ContextMenu();
		addMenuItem(menu, "Clear", () -> text.clear() );
		addMenuItem(menu, "Copy", () -> text.copy() );
		addMenuItem(menu, "Paste", () -> text.paste());
		addMenuItem(menu, "Copy All", () -> { text.selectAll(); text.copy(); text.deselect(); });
		addMenuItem(menu, "Paste All", () -> { text.clear(); text.paste(); } );
		addMenuItem(menu, "Paste Html", this::pasteHtml);
		addSeparator(menu);
		addMenuItem(menu, "Wrap", this::wrapToggle);
		addMenuItem(menu, "Font(-)", this::fontDown);
		addMenuItem(menu, "Font(+)", this::fontUp);
		text.setContextMenu(menu);

		setSyntaxHighlightPUml(scene);

		/*
		scroll = new VirtualizedScrollPane(text);
		scroll.setVbarPolicy(ScrollBarPolicy.ALWAYS); //)ALWAYS;
		scroll.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
		//scroll.setPannable(true);
		//scroll.setFitToWidth(true);
		//scroll.setFitToHeight(true);
		*/
	}

	public Node getLayout() {
		return text;
	}
	
	public void setSyntaxHighlightPUml(Scene scene) {
		/*
		scene.getStylesheets().add(FxRichText.class.getResource("puml-keywords.css").toExternalForm());

		text.multiPlainChanges()
        .successionEnds(Duration.ofMillis(500))
        .subscribe(ignore -> text.setStyleSpans(0, FxRichTextPUml.computeHighlighting(text.getText())));
		*/
	}
	
	public void setText(String data) { text.clear(); text.appendText(data); }	
	public void append(String data) { text.appendText(data); }
	public void insert(int index, String data) { text.insertText(index, data); } 
	public void wrapToggle() { text.setWrapText( ! text.isWrapText() ); }
	public void showLineNumber() { text.setParagraphGraphicFactory(LineNumberFactory.get(text)); }	
	public void pasteHtml() {
		if( Clipboard.getSystemClipboard().hasHtml() ) {
			text.clear();
			text.appendText( Clipboard.getSystemClipboard().getHtml() );
		}
	}
	public void fontDown() {
		if( fontSize > 1 ) {
			fontSize--;
			//text.setStyle("-fx-font: " + fontSize + " arial;");
			text.setStyle("-fx-font-size: " + fontSize + ";");
		}
	}
	public void fontUp() {
		if( fontSize < 127 ) {
			fontSize++;
			text.setStyle("-fx-font-size: " + fontSize + ";");
		}		
	}
	public void addMenuItem(ContextMenu menu, String title, Runnable runnable) {
		MenuItem item = new MenuItem();
		item.setText(title);
		item.setOnAction(e -> runnable.run());
		menu.getItems().add(item);
	}
	public void addSeparator(ContextMenu menu) {
		menu.getItems().add(new SeparatorMenuItem());
	}	
}

Java FX ImageView API

1. Java FX ImageView API

package com.home.fx;

import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.embed.swing.SwingFXUtils;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;

import static javafx.embed.swing.SwingFXUtils.fromFXImage;

public class FxImageView {

	ImageView imageView;
	ScrollPane scrollPane;
	Label glassText;
	StackPane glassView;
	StackPane layout;
	Double zoom = 1.0;
	Image image;

	public FxImageView(int fontSize, FxRunnable keyHandle) {
		layout = new StackPane();
	    imageView = new ImageView(); //new Image(new File("D:/a.png").toURI().toString())
	    imageView.setPreserveRatio(true);
	    imageView.setPickOnBounds(true);
		layout.setOnMouseMoved(e -> {
	        if ( e.getX() < layout.getWidth() / 4 || e.getX() > layout.getWidth() * 3 / 4 ) {
	            if ( e.getX() < layout.getWidth() / 4 ) {
	                Platform.runLater(() ->glassText.setText("<"));
	                StackPane.setAlignment(glassView, Pos.BOTTOM_LEFT);
	            } else {
	                Platform.runLater(() ->glassText.setText(">"));
	                StackPane.setAlignment(glassView, Pos.BOTTOM_RIGHT);
	            }
	            glassView.setMaxWidth(layout.getWidth() / 4);
	            glassView.setMaxHeight(layout.getHeight());
	            glassView.setVisible(true);
	        } else {
	            glassView.setVisible(false);
	        }
	        e.consume();
	    });
	    
	    scrollPane = new ScrollPane();
	    scrollPane.setPannable(true);
    	if( fontSize > 0 ) {
    		scrollPane.setStyle("-fx-font-size: " + fontSize + " pt;");
    	}
	    //imageView.fitWidthProperty().bind(scrollPane.widthProperty().subtract(10d));
	    scrollPane.setContent(imageView);
	    scrollPane.vvalueProperty().addListener(new ChangeListener<Number>() {
	        public void changed(ObservableValue<? extends Number> ov,
	        Number old_val, Number new_val) {
	            if ( new_val.equals(1.0) ) {
	            	//runnable.run(KeyCode.RIGHT);
	            }
	            if ( new_val.equals(0.0) ) {
	            	//runnable.run(KeyCode.LEFT);
	            }
	        }
	    });

	    scrollPane.setOnKeyPressed(e -> {
	    	keyHandle.run(e.getCode());
	    });

	    glassText = new Label("");
	    glassText.setStyle("-fx-text-fill: goldenrod; -fx-font: italic 20 \"serif\"; -fx-padding: 0 0 20 0; -fx-text-alignment: center");
	
	    glassView = new StackPane();
	    StackPane.setAlignment(glassText, Pos.CENTER);
	    glassView.getChildren().addAll(glassText);
	    glassView.setStyle("-fx-background-color: rgba(0, 50, 100, 0.1); -fx-background-radius: 10;");
	    glassView.setLayoutX(0);
	    glassView.setLayoutY(0);
	    glassView.setPrefWidth(imageView.getFitWidth() / 4);
	    glassView.setPrefHeight(imageView.getFitHeight() / 4);
	    glassView.setVisible(false);
	    glassView.setOnMouseClicked( e-> {
	        if ( glassText.getText().equals(">") ) {
	        	keyHandle.run(KeyCode.RIGHT);
	        } else {
	        	keyHandle.run(KeyCode.LEFT);
	        }
	    });

	    glassView.focusedProperty().addListener(new ChangeListener<Boolean>() {
            @Override public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if( ! newValue.booleanValue() ) {
                    glassView.setVisible(false);
                }
            }
        });

		ContextMenu menu = new ContextMenu();
		addMenuItem(menu, "Copy", () -> {
			if( image != null ) {
				Clipboard clipboard = Clipboard.getSystemClipboard();
				ClipboardContent content = new ClipboardContent();
				content.putImage(image);
				clipboard.setContent(content);
			}
		} );
		addMenuItem(menu, "Save", () -> {
			if( image != null ) {
				try {
					FileChooser fileChooser = new FileChooser();
					FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("PNG files (*.png)", "*.png");
					fileChooser.getExtensionFilters().add(extFilter);
					File file = fileChooser.showSaveDialog(null); //stage
					ImageIO.write(fromFXImage(image, null), "png", file);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} );
		scrollPane.setContextMenu(menu);

	    StackPane.setAlignment(glassView, Pos.BOTTOM_LEFT);
	    layout.getChildren().addAll(scrollPane, glassView);
	    layout.setStyle("-fx-background-color: silver; -fx-padding: 1;");
	}	

	public StackPane getLayout() { return layout; }
	public void clearGlassView() {
		glassView.setVisible(false);
	}

	public void setImage(Image image) {
		this.image = image;
		imageView.setImage(image);
		imageView.setFitWidth( image.getWidth() * zoom );
		imageView.setFitHeight( image.getHeight() * zoom );
		scrollPane.setVvalue(0.0);
	}
	public void setImage(byte[] image) {
		setImage(new Image(new ByteArrayInputStream(image)));
	}
	public void setImage(BufferedImage image) {
		setImage(SwingFXUtils.toFXImage(image,null));
	}
	public void setContextMenu(ContextMenu menu) {
		scrollPane.setContextMenu(menu);
	}
	public void hideScrollBar() {
    	scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
    	scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
	}
	public void showScrollBar() {
    	scrollPane.setHbarPolicy(ScrollBarPolicy.AS_NEEDED);
    	scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
		setImage(this.image);
	}

	public void fitWidth() {
		imageView.fitWidthProperty().bind(scrollPane.widthProperty()); //.subtract(10d));
		imageView.fitHeightProperty().unbind();
		setImage(this.image);
	}
	public void fitHeight() {
		imageView.fitWidthProperty().unbind();
		imageView.fitHeightProperty().bind(scrollPane.heightProperty()); //.subtract(10d));
		setImage(this.image);
	}
	public void fitNone() {
		imageView.fitWidthProperty().unbind();
		imageView.fitHeightProperty().unbind();
		setImage(this.image);
	}

	public void zoomIn() {
		zoom += 0.1;
		setImage(this.image);
	}
	public void zoomOut() {
		if( zoom > 0.2 ) { zoom -= 0.1; }
		setImage(this.image);
	}

	public void addMenuItem(ContextMenu menu, String title, Runnable runnable) {
		MenuItem item = new MenuItem();
		item.setText(title);
		item.setOnAction(e -> runnable.run());
		menu.getItems().add(item);
	}
	public void addSeparator(ContextMenu menu) {
		menu.getItems().add(new SeparatorMenuItem());
	}

}