我是一个非常新的JavaFX,昨天开始学习它。花了一整天阅读文档,但没有学到任何东西......
这是我想要做的,创建一个创建圆的简单JavaFX应用程序。点击它的笔划变成橙色(某种颜色)。在未单击时(单击除该圆圈以外的任何其他内容),笔划将变为(某些颜色)白色。
这是我的伪代码到目前为止我所拥有的。 我想创建一个单独的类来创建一个圆圈并处理事件(重要)。
public class Something extends Application {
@Override
public void start(Stage primaryStage) {
MyCircle c1 = new MyCircle();
c1.setCircle(20, 0, 0);
TilePane root = new TilePane();
root.getChildren().add(c1.getCircle());
//Some kind of mouse event listener, not sure which one should be
c1.getCircle().addEventListener(); //pseudo code
Scene scene = new Scene(root, 400, 400);
primaryStage.setTitle("Circle");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
这个类应该创建一个圆圈并处理所有事件,例如鼠标点击,鼠标位置,点击和拖动等等。
public class MyCircle implements EventHandler{
Circle circle = new Circle();
public void setCircle(int radius, int x, int y){
circle.setRadius(radius);
position(x,y);
circle.setStrokeWidth(3);
circle.setStroke(Color.valueOf("white"));
}
public Circle getCircle(){
return circle;
}
public void position(int x, int y){
circle.setTranslateX(x);
circle.setTranslateY(y);
}
public void selected(){
circle.setStroke(Color.valueOf("orange"));
}
public void unselected() {
circle.setStroke(Color.valueOf("white"));
}
@Override
public void handle(Event event) {
if (event == MOUSE_CLICKED){ //pseudo code
selected();
}
else if(event == MOUSE_UNCLICKED){ //pseudo code
unselected();
}
}
}
由于我是JavaFX的新手,我也非常感谢解释。谢谢!
编辑:这是我的伪代码,我想将其转换为实际的工作代码。我不知道我该怎么做。任何帮助将不胜感激。
另一个编辑:除了3个标记的地方外,所有内容都是代码。请在代码中查找我的评论Psuedo Code
,我需要帮助将伪代码更改为实际代码。
答案 0 :(得分:4)
您可以使用一些内置的Java函数来帮助完成任务。
例如由CSS PsuedoClasses管理的Toggles和ToggleGroup。
没有必要这样做,没有使用这些其他JavaFX功能的解决方案就好了。使用一些标准的JavaFX函数非常简洁。
LightApp.java
Set-Cookie
LightArray.java
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class LightApp extends Application {
@Override
public void start(final Stage stage) throws Exception {
final Bulb[] bulbs = {
new Bulb(),
new Bulb(),
new Bulb()
};
Scene scene = new Scene(new LightArray(bulbs));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Bulb.java
import javafx.geometry.Insets;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.HBox;
public class LightArray extends HBox {
public LightArray(Bulb... bulbs) {
super(10, bulbs);
setPadding(new Insets(10));
ToggleGroup toggleGroup = new ToggleGroup();
for (Bulb bulb: bulbs) {
bulb.setToggleGroup(toggleGroup);
}
setOnMouseClicked(event -> {
if (event.getTarget() instanceof Bulb) {
toggleGroup.selectToggle((Bulb) event.getTarget());
} else {
toggleGroup.selectToggle(null);
}
});
getStylesheets().add(
this.getClass().getResource("bulb.css").toExternalForm()
);
}
}
bulb.css
import javafx.beans.property.*;
import javafx.css.PseudoClass;
import javafx.scene.control.*;
import javafx.scene.shape.Circle;
class Bulb extends Circle implements Toggle {
private ObjectProperty<ToggleGroup> toggleGroup = new SimpleObjectProperty<>();
Bulb() {
super(30);
getStyleClass().add("bulb");
}
@Override
public void setSelected(boolean selected) {
this.selected.set(selected);
}
@Override
public boolean isSelected() {
return selected.get();
}
@Override
public BooleanProperty selectedProperty() {
return selected;
}
public BooleanProperty selected =
new BooleanPropertyBase(false) {
@Override protected void invalidated() {
pseudoClassStateChanged(ON_PSEUDO_CLASS, get());
}
@Override public Object getBean() {
return Bulb.this;
}
@Override public String getName() {
return "on";
}
};
private static final PseudoClass
ON_PSEUDO_CLASS = PseudoClass.getPseudoClass("on");
@Override
public ToggleGroup getToggleGroup() {
return toggleGroup.get();
}
@Override
public void setToggleGroup(ToggleGroup toggleGroup) {
this.toggleGroup.set(toggleGroup);
}
@Override
public ObjectProperty<ToggleGroup> toggleGroupProperty() {
return toggleGroup;
}
}
通常用JavaFX完成的另一个常见的事情(我在这里没有完成)是制作可以通过CSS设置样式的项目(例如区域或窗格),然后将样式应用于它们。例如,它可以扩展StackPane而不是Bulb扩展Circle,然后可以通过多层背景和svg形状在css中定制灯泡形状(这是其他类似的东西,如单选按钮的实现)。
答案 1 :(得分:3)
处理节点的选择状态需要一些节点内不可用的知识。您将需要知道鼠标事件是否发生在其他地方(例如其他节点或根窗格),因此您可能必须向其传递可疑参数。
通常,将鼠标事件处理委派给MyCircle
并不是一个好主意。相反,最好在该类中指定选择行为,并将选择处理委托给具有足够知识来处理问题的单独辅助类。我创建了这个gist来展示如何完成这项任务。
public class SelectionDemo extends Application {
@Override
public void start(Stage primaryStage) {
Scene scene = new Scene(createPane(), 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private Parent createPane() {
BorderPane root = new BorderPane();
SelectionHandler selectionHandler = new SelectionHandler(root);
root.addEventHandler(MouseEvent.MOUSE_PRESSED, selectionHandler.getMousePressedEventHandler());
MyCircle c1 = new MyCircle(40, 40, 20);
MyCircle c2 = new MyCircle(40, 100, 20);
MyCircle c3 = new MyCircle(40, 160, 20);
root.getChildren().addAll(c1, c2, c3);
return root;
}
public static void main(String[] args) {
launch(args);
}
}
我借用并修改了jfxtras-labs的接口来表示可选节点。有了这个界面来区分可选择的节点和不可选的节点是很好的:
/**
* This interface is based on jfxtras-labs <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/scene/control/window/SelectableNode.java">SelectableNode</a>
*/
public interface SelectableNode {
public boolean requestSelection(boolean select);
public void notifySelection(boolean select);
}
希望可选择的类必须实现此接口并在notifySelection方法的实现中指定它们的选择行为:
public class MyCircle extends Circle implements SelectableNode {
public MyCircle(double centerX, double centerY, double radius) {
super(centerX, centerY, radius);
}
@Override
public boolean requestSelection(boolean select) {
return true;
}
@Override
public void notifySelection(boolean select) {
if(select)
this.setFill(Color.RED);
else
this.setFill(Color.BLACK);
}
}
最后选择处理程序类:
public class SelectionHandler {
private Clipboard clipboard;
private EventHandler<MouseEvent> mousePressedEventHandler;
public SelectionHandler(final Parent root) {
this.clipboard = new Clipboard();
this.mousePressedEventHandler = new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
SelectionHandler.this.doOnMousePressed(root, event);
event.consume();
}
};
}
public EventHandler<MouseEvent> getMousePressedEventHandler() {
return mousePressedEventHandler;
}
private void doOnMousePressed(Parent root, MouseEvent event) {
Node target = (Node) event.getTarget();
if(target.equals(root))
clipboard.unselectAll();
if(root.getChildrenUnmodifiable().contains(target) && target instanceof SelectableNode) {
SelectableNode selectableTarget = (SelectableNode) target;
if(!clipboard.getSelectedItems().contains(selectableTarget))
clipboard.unselectAll();
clipboard.select(selectableTarget, true);
}
}
/**
* This class is based on jfxtras-labs
* <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/scene/control/window/Clipboard.java">Clipboard</a>
* and
* <a href="https://github.com/JFXtras/jfxtras-labs/blob/8.0/src/main/java/jfxtras/labs/util/WindowUtil.java">WindowUtil</a>
*/
private class Clipboard {
private ObservableList<SelectableNode> selectedItems = FXCollections.observableArrayList();
public ObservableList<SelectableNode> getSelectedItems() {
return selectedItems;
}
public boolean select(SelectableNode n, boolean selected) {
if(n.requestSelection(selected)) {
if (selected) {
selectedItems.add(n);
} else {
selectedItems.remove(n);
}
n.notifySelection(selected);
return true;
} else {
return false;
}
}
public void unselectAll() {
List<SelectableNode> unselectList = new ArrayList<>();
unselectList.addAll(selectedItems);
for (SelectableNode sN : unselectList) {
select(sN, false);
}
}
}
}
答案 2 :(得分:1)
这就是我做到的......简单易行
主要类
public class Lab05 extends Application {
@Override
public void start(Stage primaryStage) {
double width = 400;
double height = 400;
int num_of_circles = 5;
int radius_of_circles = 20;
BorderPane root = new BorderPane();
for (int i = 0; i < num_of_circles; i++) {
MyCircle temp = createCircle(radius_of_circles, (50 * i) + 1, 100);
temp.setFrame(width, height);
root.getChildren().add(temp.getCircle());
temp.getCircle().addEventFilter(MouseEvent.ANY, temp);
}
Scene scene = new Scene(root, width, height);
primaryStage.setTitle("Lab 05");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static MyCircle createCircle(int radius, int x, int y){
MyCircle circle = new MyCircle();
circle.setCircle(radius, x, y);
return circle;
}
}
MyCircle Class
public class MyCircle implements EventHandler<MouseEvent>{
private static double frameX = 0;
private static double frameY = 0;
private final Circle circle = new Circle();
private static final List<Circle> CIRCLES = new ArrayList<>();
public void setCircle(int radius, int x, int y){
circle.setRadius(radius);
position(x,y);
circle.setStrokeWidth(3);
circle.setStroke(Color.valueOf("white"));
CIRCLES.add(circle);
}
public void setFrame(double x, double y){
frameX = x;
frameY = y;
}
public Circle getCircle(){
return circle;
}
public void position(double x, double y){
if ( x < frameX && x > 0)
circle.setCenterX(x);
if ( y < frameY && y > 0)
circle.setCenterY(y);
}
public void selected(){
CIRCLES.stream().forEach((c) -> {
c.setStroke(Color.valueOf("white"));
});
circle.setStroke(Color.valueOf("orange"));
}
public void unselected() {
circle.setStroke(Color.valueOf("white"));
}
@Override
public void handle(MouseEvent event) {
if (event.getEventType() == MouseEvent.MOUSE_PRESSED){
selected();
}
else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED){
position(event.getX(), event.getY());
}
}
}