标题有点宽泛,但我不知道如何用更少的词来描述这个问题。
我正在用JavaFX和Scene Builder制作一个应用程序,这个应用程序的要点是有一个元素列表可供选择(无论你选择哪个元素,目前都不会改变任何东西,因为我一直在试图解决这个主要问题沿着其他一些问题),并通过按插入按钮添加到中间的主要区域,这些元素在添加后是可拖动的,这是添加后的外观:
顶部的标题不是那些元素将被移动的主要区域的一部分,所以我做了一个系统,它应该阻止可拖动窗格与其他区域的交叉。
我遇到的问题是,这个标题的坐标不与所示的矩形对齐,我的意思是,在上面的图像中,可拖动的窗格不能比那个更高,它停止了这样做,但它可以在标题实际所在的区域内自由移动:
下面是我使用的代码:
主类:(这个应用程序使用了一个Json API,我已经存储在我的项目,删除任何与它有关的东西,如Gson的东西进行测试)
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.input.MouseButton;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.awt.*;
import java.io.IOException;
import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.TreeMap;
public class SkriptDnD extends Application {
public static TreeMap<String, JsonObject> skriptElements = new TreeMap<>();
public static TreeMap<String, ArrayList<String>> skriptTypeElementNames;
TreeMap<String, Color> skriptTypeColors;
{
try {
skriptTypeColors = new TreeMap<>() {{
put("Event", Color.rgb(146, 44, 255));
put("Expression", Color.rgb(123, 250, 36));
put("Effect", Color.rgb(36, 136, 250));
put("Condition", Color.rgb(255, 52, 52));
put("Type", Color.rgb(255, 184, 30));
put("Function", Color.rgb(168, 168, 168));
put("Section", Color.rgb(104, 204, 192));
}};
Gson gson = new Gson();
Reader reader = Files.newBufferedReader(Paths.get("src/main/resources/me/jake/skriptdnd/skript.json"));
skriptTypeElementNames = new TreeMap<>();
JsonArray jsonArray = gson.fromJson(reader, JsonArray.class);
for (JsonElement element : jsonArray) {
JsonObject object = element.getAsJsonObject();
String name = object.get("title").getAsString();
skriptElements.put(name, object);
String doc = object.get("syntax_type").getAsString().toLowerCase();
if (!skriptTypeElementNames.containsKey(doc)) {
skriptTypeElementNames.put(doc, new ArrayList<>());
}
skriptTypeElementNames.get(doc).add(name);
}
reader.close();
} catch (Exception exception) {
try {
throw exception;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("unchecked")
@Override
public void start(Stage stage) throws IOException{
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Main.fxml"));
Scene scene = new Scene(fxmlLoader.load());
String css = getClass().getResource("SkriptDnD.css").toExternalForm();
scene.getStylesheets().add(css);
stage.setTitle("SkriptDnD");
stage.setScene(scene);
stage.setMinHeight(550);
stage.setMinWidth(800);
StackPane header = (StackPane) scene.lookup("#header");
Pane sidebar = (Pane) scene.lookup("#sidebar");
ComboBox<String> typeComboBox = (ComboBox<String>) scene.lookup("#typeComboBox");
ObservableList<String> types = typeComboBox.getItems();
types.add("All");
types.addAll(skriptTypeColors.keySet());
typeComboBox.getSelectionModel().selectFirst();
ComboBox<String> elementComboBox = (ComboBox<String>) scene.lookup("#elementComboBox");
elementComboBox.getItems().addAll(skriptElements.keySet());
elementComboBox.getSelectionModel().selectFirst();
Pane canvasPane = (Pane) scene.lookup("#canvasPane");
canvasPane.setOnMousePressed(mouseEvent2 -> {
Point location = MouseInfo.getPointerInfo().getLocation();
int mouseX = location.x;
int mouseY = location.y;
Window window = scene.getWindow();
int windowX = (int) window.getX();
int windowY = (int) window.getY();
System.out.print("\n"+new Point(mouseX-windowX,mouseY-windowY));
});
Button insertButton = (Button) scene.lookup("#insertButton");
insertButton.setOnMousePressed(mouseEvent -> {
DragPane elementPane = new DragPane(true);
elementPane.setTranslateX(300);
elementPane.setTranslateY(300);
elementPane.setPrefWidth(100);
elementPane.setPrefHeight(100);
elementPane.addIntersects(header);
System.out.print(Utils.getRectangle(header));
//elementPane.addIntersects(sidebar);
Rectangle rectangle = new Rectangle(100,100,Color.rgb(100,100,100));
rectangle.setX(0);
rectangle.setY(0);
rectangle.setArcWidth(10);
rectangle.setArcHeight(10);
elementPane.setOnMousePressed(mouseEvent12 -> {
if (mouseEvent12.getButton() == MouseButton.MIDDLE) {
canvasPane.getChildren().remove(elementPane);
}
});
elementPane.getChildren().add(rectangle);
canvasPane.getChildren().add(elementPane);
});
stage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch();
}
}
DragPane类:
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.stage.Window;
import java.awt.*;
import java.util.ArrayList;
public class DragPane extends Pane {
public Point lastValid = new Point();
public Point offset = new Point();
public ArrayList<Region> intersects = new ArrayList<>();
public DragPane(boolean draggable) {
if (draggable) {
addEventFilter(
MouseEvent.MOUSE_PRESSED,
mouseEvent -> {
Point location = MouseInfo.getPointerInfo().getLocation();
offset.setLocation(location.x, location.y);
}
);
setOnMouseDragged(mouseEvent -> {
Node source = (Node) mouseEvent.getSource();
Scene scene = source.getScene();
Window window = scene.getWindow();
int windowX = (int) window.getX();
int windowY = (int) window.getY();
int windowWidth = (int) window.getWidth();
int windowHeight = (int) window.getHeight();
Rectangle windowRectangle = new Rectangle(windowX, windowY, windowWidth, windowHeight);
Point location = MouseInfo.getPointerInfo().getLocation();
int mouseX = location.x;
int mouseY = location.y;
Point futurePoint = new Point(mouseX - offset.x, mouseY - offset.y);
if (windowRectangle.contains(location)) {
if (Utils.intersects(Utils.offset(this, futurePoint),intersects)) {
translate(futurePoint);
offset.setLocation(mouseX, mouseY);
lastValid.setLocation(futurePoint);
} else {
Point lastValidXPoint = new Point(futurePoint);
lastValidXPoint.x = lastValid.x;
Point lastValidYPoint = new Point(futurePoint);
lastValidYPoint.y = lastValid.y;
if (Utils.intersects(Utils.offset(this, lastValidXPoint),intersects)) {
translate(lastValidXPoint);
} else if (Utils.intersects(Utils.offset(this, lastValidYPoint),intersects)) {
translate(lastValidYPoint);
}
}
}
});
}
}
public void translate(Point point) {
setTranslateX(getTranslateX() + point.x);
setTranslateY(getTranslateY() + point.y);
}
public void addIntersects(Region region) {
intersects.add(region);
}
public void clearIntersects() {
intersects.clear();
}
}
实用程序类:
import javafx.scene.layout.Region;
import java.awt.*;
import java.util.ArrayList;
public class Utils {
public static Rectangle getRectangle(Region region) {
return new Rectangle((int) region.getLayoutX(), (int) region.getLayoutY(), (int) region.getWidth(), (int) region.getHeight());
}
public static Rectangle offset(Region region, Point offset) {
double x = region.getTranslateX()+offset.x;
double y = region.getTranslateY()+offset.y;
double w = region.getWidth();
double h = region.getHeight();
return new Rectangle((int) x, (int) y, (int) w, (int) h);
}
public static boolean intersects(Rectangle rectangle, ArrayList<Region> intersects) {
return intersects.stream().noneMatch((other) -> Utils.getRectangle(other).intersects(rectangle));
}
}
控制器类别:
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import java.util.Collections;
import java.util.Objects;
public class Controller {
public void typeSelect(ActionEvent event) {
Node source = (Node) event.getSource();
Scene scene = source.getScene();
ComboBox<String> typeComboBox = (ComboBox<String>) scene.lookup("#typeComboBox");
ComboBox<String> elementComboBox = (ComboBox<String>) scene.lookup("#elementComboBox");
String selected = typeComboBox.getSelectionModel().getSelectedItem().toLowerCase();
ObservableList<String> list = FXCollections.observableArrayList();
if (Objects.equals(selected, "all")) {
list.setAll(SkriptDnD.skriptElements.keySet().stream().toList());
} else {
list.setAll(SkriptDnD.skriptTypeElementNames.get(selected));
}
Collections.sort(list);
elementComboBox.getItems().setAll(list);
elementComboBox.getSelectionModel().selectFirst();
}
public void elementSelect(ActionEvent event) {
}
}
FXML文件:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Point3D?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ToggleButton?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.text.Font?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<AnchorPane fx:id="anchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="550.0" minWidth="800.0" prefHeight="550.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="me.jake.skriptdnd.Controller">
<children>
<BorderPane prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<StackPane fx:id="header" alignment="CENTER_RIGHT" prefHeight="59.0" prefWidth="800.0" BorderPane.alignment="CENTER">
<children>
<Pane prefHeight="59.0" prefWidth="538.0" style="-fx-background-color: #2c2b2b;">
<rotationAxis>
<Point3D />
</rotationAxis></Pane>
<Label fx:id="label1" text="SkriptDnD" textAlignment="CENTER" textFill="WHITE" wrapText="true" StackPane.alignment="CENTER_LEFT">
<font>
<Font name="Arial Bold" size="18.0" />
</font>
<StackPane.margin>
<Insets left="40.0" />
</StackPane.margin>
</Label>
<HBox alignment="CENTER_RIGHT" nodeOrientation="LEFT_TO_RIGHT">
<children>
<Button fx:id="insertButton" mnemonicParsing="false" text="Insert" textOverrun="CLIP">
<HBox.margin>
<Insets right="20.0" />
</HBox.margin>
<font>
<Font name="Arial Bold" size="12.0" />
</font>
</Button>
<ComboBox fx:id="typeComboBox" nodeOrientation="LEFT_TO_RIGHT" onAction="#typeSelect" prefHeight="17.0" prefWidth="150.0" promptText="Type" visibleRowCount="7" HBox.hgrow="ALWAYS">
<opaqueInsets>
<Insets />
</opaqueInsets>
<HBox.margin>
<Insets right="20.0" />
</HBox.margin>
</ComboBox>
<ComboBox fx:id="elementComboBox" onAction="#elementSelect" prefHeight="17.0" prefWidth="150.0" promptText="Element" HBox.hgrow="ALWAYS" />
</children>
<opaqueInsets>
<Insets />
</opaqueInsets>
<padding>
<Insets right="50.0" />
</padding>
</HBox>
</children>
</StackPane>
</top>
<left>
<StackPane prefHeight="491.0" prefWidth="40.0" BorderPane.alignment="CENTER">
<children>
<Pane fx:id="sidebar" prefHeight="491.0" prefWidth="34.0" style="-fx-background-color: #ebebeb; -fx-border-color: #cfcece; -fx-border-style: solid; -fx-border-width: 0 1px 0 0;">
<children>
<ToggleButton layoutX="-3.0" mnemonicParsing="false" prefHeight="38.0" prefWidth="2.0" style="-fx-background-color: #ebebeb;" />
<FontIcon iconLiteral="far-arrow-alt-circle-right" iconSize="30" layoutX="5.0" layoutY="30.0" />
</children>
</Pane>
</children>
</StackPane>
</left>
<center>
<Pane fx:id="canvasPane" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
</children>
</AnchorPane>
场景生成器层次+预览:
1条答案
按热度按时间qni6mghb1#
问题是您使用Windows来计算位置。在计算时,您需要始终使用相同的X,Y,例如,如果您希望基于场景进行计算