我的 VBOX 有一些问题,我寻找其他可以帮助我的问题,但遗憾的是没有任何效果。我有一个带有一堆滑块和按钮的 VBox,发生的事情是我可以随意调整它。所以我可以把它做得小到它里面的按钮会消失,或者我可以把它做得大到它会覆盖我程序的其他部分。我尝试了 vbox.setMaxSize 和 vbox.setMinxSize,但没有发生任何事情。我还应该对其中的按钮和滑块做些什么吗?我虽然因为按钮和滑块是 Vbox childrem,所以我在 Vbox 上所做的更改也适用于它们。我将发布控制器类,然后是 FXML 文件,如果需要其他类,请随意告诉我。非常感谢。
控制器
package fotofinish;
import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Slider;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;
//TODO: Find a better way to have image be refreshed
public class FXMLDocumentController implements Initializable {
private static final Logger logger = Logger.getLogger(fotofinish.FXMLDocumentController.class.getName());
Stage stage;
private FotoFinishModel model = new FotoFinishModel();
@FXML
private Slider brightnessSlider;
@FXML
private Slider contrastSlider;
@FXML
private ToggleGroup brushTypeRadioGroup;
@FXML
private RadioButton brushTypeCircleRadioButton;
@FXML
private RadioButton brushTypeSpraypaintRadioButton;
@FXML
private RadioButton brushTypeSquareRadioButton;
@FXML
private ColorPicker brushColorPicker;
@FXML
private NumberFieldFX brushSizeNumberField;
@FXML
private ImageView imageViewer;
@FXML
private ScrollPane imageScrollPane;
@FXML
private VBox vbox;
@Override
public void initialize(URL url, ResourceBundle rb) {
//TODO: WHAT IS BLOCK INCREMENT?
this.brightnessSlider.valueProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
if(model.changeBrightness(newValue.doubleValue())) {
this.refreshImageViewer();
}
});
//TODO: convert to dragged call
this.contrastSlider.valueProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
if (model.changeContrast(newValue.doubleValue())) {
this.refreshImageViewer();
}
});
}
@FXML
private void filterGrayscale(ActionEvent ignored) {
model.applyGrayscaleFilter();
this.refreshImageViewer();
this.resetSliders();
}
@FXML
private void filterSepia(ActionEvent ignored) {
model.applySepiaFilter();
this.refreshImageViewer();
this.resetSliders();
}
@FXML
private void filterInstant(ActionEvent ignored) {
model.applyInstantFilter();
this.refreshImageViewer();
this.resetSliders();
}
@FXML
private void filterCustom(ActionEvent ignored) {
//TODO: code to create custom filter popup and get arguments for custom filter
logger.log(Level.INFO, "TODO: custom filter popup launched");
model.applyCustomFilter();
this.refreshImageViewer();
this.resetSliders();
}
@FXML
private void filterNone(ActionEvent ignored) {
model.resetImageToOriginal();
this.refreshImageViewer();
this.resetSliders();
}
@FXML
private void brushTypeCircle(ActionEvent ignored) {
model.setBrushTypeCircle();
}
@FXML
private void brushTypeSquare(ActionEvent ignored) {
model.setBrushTypeSquare();
}
@FXML
private void brushTypeSpraypaint(ActionEvent ignored) {
model.setBrushTypeSpraypaint();
}
@FXML
private void helpDoc(ActionEvent ignored) {
logger.log(Level.INFO, "TODO: help document launched");
}
@FXML
private void aboutDialog(ActionEvent ignored) {
logger.log(Level.INFO, "TODO: about dialog created");
}
@FXML
private void brushColor(ActionEvent ignored) {
model.changeBrushColor(this.brushColorPicker.getValue());
}
@FXML
private void brushSize(ActionEvent ignored) {
model.changeBrushSize(Integer.parseInt(this.brushSizeNumberField.getText()));
}
//TODO: make title setting more intelligent
@FXML
private void open(ActionEvent ignored) {
logger.log(Level.INFO, "open file chooser launched");
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open Image");
fileChooser.getExtensionFilters().add(new ExtensionFilter("Image Files", "*.png")); //TODO: add other types
File selectedFile = fileChooser.showOpenDialog(null); //TODO: needs value in order to block main window
if (selectedFile != null) {
logger.log(Level.INFO, "file {0} choosen in open file chooser", selectedFile);
model.loadImage(selectedFile);
this.refreshImageViewer();
this.stage.setTitle("Foto Finish - " + selectedFile);
} else {
logger.log(Level.INFO, "no file selected in open file chooser");
}
}
@FXML
private void galleryButterfly(ActionEvent ignored) {
model.loadGalleryButterflyImage();
this.refreshImageViewer();
}
@FXML
private void galleryTeddyBear(ActionEvent ignored) {
model.loadGalleryTeddyBearImage();
this.refreshImageViewer();
}
@FXML
private void galleryPrincess(ActionEvent ignored) {
model.loadGalleryPrincessImage();
this.refreshImageViewer();
}
@FXML
private void galleryFirefighter(ActionEvent ignored) {
model.loadGalleryFirefighterImage();
this.refreshImageViewer();
}
@FXML
private void save(ActionEvent ignored) {
model.saveImage();
}
@FXML
private void saveAs(ActionEvent ignored) {
logger.log(Level.INFO, "save as file chooser launched");
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Save Image");
fileChooser.getExtensionFilters().add(new ExtensionFilter("Image Files", "*.png")); //TODO: add other types
File selectedFile = fileChooser.showSaveDialog(null); //TODO: needs value in order to block main window
if (selectedFile != null) {
logger.log(Level.INFO, "file {0} choosen in save as file chooser", selectedFile);
model.saveImageAs(selectedFile);
} else {
logger.log(Level.INFO, "no file selected in save as file chooser");
}
}
@FXML
private void quit(ActionEvent ignored) {
logger.log(Level.INFO, "quitting");
Platform.exit(); //TODO: make this detect unsaved changes
}
@FXML
private void newFile(ActionEvent ignored) {
logger.log(Level.INFO, "TODO: new file created");
}
private void refreshImageViewer() {
this.imageViewer.setImage(model.getImage());
logger.log(Level.INFO, "image refreshed");
}
//TODO: make this connect better with FXML default value
private void resetSliders() {
this.brightnessSlider.setValue(0);
this.contrastSlider.setValue(0);
logger.log(Level.INFO, "brightness and contrast sliders reset");
}
public void setStage(Stage stageFromMain) {
this.stage = stageFromMain;
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.input.*?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="500.0" minWidth="600.0" prefHeight="700.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fotofinish.FXMLDocumentController">
<top>
<MenuBar prefHeight="0.0" prefWidth="1034.0" BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem fx:id="menubarFileNew" mnemonicParsing="false" onAction="#newFile" text="New">
<accelerator>
<KeyCodeCombination alt="UP" code="N" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem fx:id="menubarFileOpen" mnemonicParsing="false" onAction="#open" text="Open">
<accelerator>
<KeyCodeCombination alt="UP" code="O" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator>
</MenuItem>
<Menu mnemonicParsing="false" text="Open from Gallery">
<items>
<MenuItem fx:id="menubarFileGalleryButterfly" mnemonicParsing="false" onAction="#galleryButterfly" text="Butterfly" />
<MenuItem fx:id="menubarFileGalleryTeddyBear" mnemonicParsing="false" onAction="#galleryTeddyBear" text="Teddy Bear" />
<MenuItem fx:id="menubarFileGalleryPrincess" mnemonicParsing="false" onAction="#galleryPrincess" text="Princess" />
<MenuItem fx:id="menubarFileGalleryFirefighter" mnemonicParsing="false" onAction="#galleryFirefighter" text="Firefighter" />
</items>
</Menu>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem fx:id="menubarFileSave" mnemonicParsing="false" onAction="#save" text="Save">
<accelerator>
<KeyCodeCombination alt="UP" code="S" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator>
</MenuItem>
<MenuItem fx:id="menubarFileSaveAs" mnemonicParsing="false" onAction="#saveAs" text="Save As">
<accelerator>
<KeyCodeCombination alt="UP" code="S" control="DOWN" meta="UP" shift="DOWN" shortcut="UP" />
</accelerator>
</MenuItem>
<SeparatorMenuItem mnemonicParsing="false" />
<MenuItem fx:id="menubarFileQuit" mnemonicParsing="false" onAction="#quit" text="Quit">
<accelerator>
<KeyCodeCombination alt="UP" code="C" control="DOWN" meta="UP" shift="UP" shortcut="UP" />
</accelerator></MenuItem>
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem fx:id="menubarHelpFotoFinishHelpMenuItem" mnemonicParsing="false" onAction="#helpDoc" text="Foto Finish Help">
<accelerator>
<KeyCodeCombination alt="UP" code="F1" control="UP" meta="UP" shift="UP" shortcut="UP" />
</accelerator></MenuItem>
<MenuItem fx:id="menubarHelpAboutMenuItem" mnemonicParsing="false" onAction="#aboutDialog" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<SplitPane dividerPositions="0.14941569282136896" minHeight="-Infinity" minWidth="-Infinity" prefHeight="160.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<VBox fx:id="vbox" alignment="TOP_CENTER" layoutX="-11.0" layoutY="25.0" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="100.0" prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="10.0" AnchorPane.leftAnchor="10.0" AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="10.0">
<children>
<Label fx:id="sliderLabel" alignment="TOP_LEFT" text="Sliders">
<padding>
<Insets left="10.0" />
</padding>
</Label>
<GridPane alignment="CENTER">
<columnConstraints>
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" maxWidth="104.0" minWidth="10.0" prefWidth="84.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 minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button fx:id="filterGrayscaleButton" contentDisplay="TOP" mnemonicParsing="false" onAction="#filterGrayscale" prefHeight="25.0" prefWidth="84.0" text="Grayscale" textAlignment="CENTER" GridPane.rowIndex="1">
<opaqueInsets>
<Insets top="50.0" />
</opaqueInsets>
</Button>
<Button fx:id="filterSepiaButton" mnemonicParsing="false" onAction="#filterSepia" prefHeight="25.0" prefWidth="83.0" text="Sepia" GridPane.rowIndex="2" />
<Button fx:id="filterInstantButton" mnemonicParsing="false" onAction="#filterInstant" prefHeight="25.0" prefWidth="83.0" text="Instant" GridPane.rowIndex="3" />
<Button fx:id="filterCustomButton" mnemonicParsing="false" onAction="#filterCustom" prefHeight="25.0" prefWidth="82.0" text="Custom" GridPane.rowIndex="4" />
<Button fx:id="filterNoneButton" mnemonicParsing="false" onAction="#filterNone" prefHeight="25.0" prefWidth="82.0" text="None" GridPane.rowIndex="5" />
</children>
<padding>
<Insets left="10.0" />
</padding>
</GridPane>
<GridPane prefHeight="271.0" prefWidth="176.0">
<columnConstraints>
<ColumnConstraints halignment="CENTER" hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="88.0" minHeight="10.0" prefHeight="35.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="290.0" minHeight="26.0" prefHeight="59.0" vgrow="SOMETIMES" />
<RowConstraints maxHeight="233.0" minHeight="6.0" prefHeight="40.0" />
<RowConstraints maxHeight="127.0" minHeight="28.0" prefHeight="56.0" />
<RowConstraints maxHeight="148.0" minHeight="23.0" prefHeight="34.0" />
<RowConstraints maxHeight="124.0" minHeight="41.0" prefHeight="51.0" />
</rowConstraints>
<children>
<Label fx:id="brightnessLabel" text="Brightness" />
<Label fx:id="contrastLabel" text="Contrast" GridPane.rowIndex="2" />
<Slider fx:id="brightnessSlider" max="1.0" min="-1.0" minorTickCount="10" orientation="HORIZONTAL" showTickLabels="true" showTickMarks="true" snapToTicks="true" GridPane.rowIndex="1" />
<Slider fx:id="contrastSlider" max="1.0" min="-1.0" minorTickCount="10" orientation="HORIZONTAL" showTickLabels="true" showTickMarks="true" snapToTicks="true" GridPane.rowIndex="3" />
<Label text="Saturation" GridPane.rowIndex="4" />
<Slider max="1.0" min="-1.0" minorTickCount="10" showTickLabels="true" showTickMarks="true" snapToTicks="true" GridPane.rowIndex="5" />
</children>
<padding>
<Insets left="10.0" right="10.0" />
</padding>
</GridPane>
<Label fx:id="drawingLabel" text="Drawing" />
<ColorPicker fx:id="brushColorPicker" onAction="#brushColor" />
<Label fx:id="brushTypeLabel" text="Brush Type" />
<RadioButton fx:id="brushTypeCircleRadioButton" mnemonicParsing="false" onAction="#brushTypeCircle" selected="true" text="Circle">
<toggleGroup>
<ToggleGroup fx:id="brushTypeRadioGroup" />
</toggleGroup>
</RadioButton>
<RadioButton fx:id="brushTypeSquareRadioButton" mnemonicParsing="false" onAction="#brushTypeSquare" text="Square" toggleGroup="$brushTypeRadioGroup" />
<RadioButton fx:id="brushTypeSpraypaintRadioButton" mnemonicParsing="false" onAction="#brushTypeSpraypaint" text="Spraypaint" toggleGroup="$brushTypeRadioGroup" />
<Label fx:id="brushSizeLabel" text="Brush Size" />
<fotofinish.NumberFieldFX fx:id="brushSizeTextField" onAction="#brushSize" text="10" />
<Label fx:id="filtersLabel" text="Filters" />
</children>
</VBox>
</children>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="369.0" prefWidth="465.0">
<children>
<ScrollPane layoutX="145.0" layoutY="111.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<content>
<ImageView fx:id="imageViewer" fitHeight="577.0" fitWidth="1010.0" pickOnBounds="true" preserveRatio="true" />
</content>
</ScrollPane>
</children>
</AnchorPane>
</items>
</SplitPane>
</center>
</BorderPane>