F Paper Doll拖放示例
本附录列出了PaperDoll应用程序的代码。
有关描述,请参见PaperDoll拖放应用程序。
PaperDoll.java
法律条款和版权声明
/* * 版权所有 (c) 2011, 2014, Oracle及其附属公司。 * 保留所有权利。使用受许可条款约束。 * * 此文件可在以下许可下使用和许可: * * 源代码的重新分发和使用,无论是否进行修改,只要满足以下条件: * * - 必须保留上述版权声明、此条件列表和以下免责声明。 * - 以二进制形式重新分发时,必须在文档和/或其他提供的材料中复制上述版权声明、此条件列表和以下免责声明。 * - 未经特定事先书面许可,不得使用Oracle或其贡献者的名称来认可或推广从本软件派生的产品。 * * 本软件由版权持有人和贡献者“按原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性和适用于特定用途的保证。 * 在任何情况下,版权所有人或贡献者均不对任何直接、间接、偶然、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购、使用损失、数据或利润损失、业务中断等)承担责任,无论是合同责任、严格责任还是侵权行为(包括疏忽或其他)。 * 即使已被告知可能发生此类损害的可能性。 */
代码
package paperdoll;
import paperdoll.clothes.Cloth;
import paperdoll.clothes.ClothListBuilder;
import paperdoll.body.Body;
import paperdoll.images.ImageManager;
import java.util.HashMap;
import java.util.List;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* The main application class. Most of presentation logic is here.
* Also, a container for unequipped details is created and set up here.
*
* This application uses the Public Domain Images
* from http://karenswhimsy.com/public-domain-images/
*
*/
public class PaperDoll extends Application {
public static void main(String[] args) {
launch(args);
}
/**
* All laying out goes here.
* @param primaryStage
*/
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Paper Doll");
ImageView header = new ImageView(ImageManager.getImage("ui/flowers.jpg"));
VBox title = new VBox();
title.getChildren().addAll(header);
title.setPadding(new Insets(10.0));
GridPane content = new GridPane();
content.add(Body.getBody().getNode(), 1, 1);
content.add(createItemPane(Body.getBody().getBodyPane()), 0, 1);
ColumnConstraints c1 = new ColumnConstraints();
c1.setHgrow(Priority.ALWAYS);
ColumnConstraints c2 = new ColumnConstraints();
c2.setHgrow(Priority.NEVER);
c2.setPrefWidth(Body.getBody().getBodyPane().getMinWidth() + 20);
content.getColumnConstraints().addAll(c1, c2);
items = new HashMap<>();
Body.getBody().setItemsInfo(itemPane, items);
populateClothes();
VBox root = new VBox();
root.getChildren().addAll(title, content);
primaryStage.setScene(new Scene(root, 800, 900));
primaryStage.setMinWidth(800);
primaryStage.setMinHeight(900);
primaryStage.show();
}
private FlowPane itemPane = null;
private HashMap<String, Cloth> items;
/**
* A container for unequipped items is created here.
* @param bodyPane body container is needed so that the item is removed from
* it when dropped here.
* @return
*/
private FlowPane createItemPane(final Pane bodyPane) {
if (!(itemPane == null))
return itemPane;
itemPane = new FlowPane();
itemPane.setPadding(new Insets(10.0));
itemPane.setOnDragDropped((DragEvent event) -> {
Dragboard db = event.getDragboard();
// Get the item ID here, which was stored when the drag started.
boolean success = false;
// If this is a meaningful drop...
if (db.hasString()) {
String nodeId = db.getString();
// ... search for the item on body. If it is there...
ImageView cloth = (ImageView) bodyPane.lookup("#" + nodeId);
if (cloth != null) {
// ... the item is removed from body
// and added to an unequipped container.
bodyPane.getChildren().remove(cloth);
itemPane.getChildren().add(cloth);
success = true;
}
// ...anyway, the item is not active or equipped anymore.
items.get(nodeId).takeOff();
}
event.setDropCompleted(success);
event.consume();
});
itemPane.setOnDragOver((DragEvent event) -> {
if (event.getGestureSource() != itemPane &&
event.getDragboard().hasString()) {
event.acceptTransferModes(TransferMode.MOVE);
}
event.consume();
});
return itemPane;
}
/**
* Here items are added to an unequipped items container.
*/
private void populateClothes() {
ClothListBuilder clothBuilder = new ClothListBuilder();
if (itemPane == null)
throw new IllegalStateException("Should call getItems() before populating!");
List<Cloth> clothes = clothBuilder.getClothList();
clothes.stream().map((c) -> {
itemPane.getChildren().add(c.getNode());
return c;
}).forEach((c) -> {
items.put(c.getImageViewId(), c);
});
}
}
Cloth.java
法律条款和版权声明
/* * 版权所有 (c) 2011, 2014, Oracle及其附属公司。 * 保留所有权利。使用受许可条款约束。 * * 此文件可在以下许可下使用和许可: * * 源代码的重新分发和使用,无论是否进行修改,只要满足以下条件: * * - 必须保留上述版权声明、此条件列表和以下免责声明。 * - 以二进制形式重新分发时,必须在文档和/或其他提供的材料中复制上述版权声明、此条件列表和以下免责声明。 * - 未经特定事先书面许可,不得使用Oracle或其贡献者的名称来认可或推广从本软件派生的产品。 * * 本软件由版权持有人和贡献者“按原样”提供,不提供任何明示或暗示的担保,包括但不限于适销性和适用于特定用途的担保。 * 在任何情况下,版权所有人或贡献者均不对任何直接、间接、偶发、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购、使用、数据或利润损失,或业务中断)承担任何责任,无论是合同责任、严格责任还是侵权行为(包括疏忽或其他)。 */
代码
package paperdoll.clothes;
import javafx.scene.Node;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.*;
/** * 可拖动的细节类。可拖动的细节有三种状态:预览、活动(拖动中)和装备。当前,拖动和预览图像是相同的(参见ClothListBuilder类)。 * */
public class Cloth {
private final Image previewImage;
private final Image activeImage;
private final Image equippedImage;
private final ImageView currentImage;
public void putOn() {
currentImage.setImage(equippedImage);
}
public void takeOff() {
currentImage.setImage(previewImage);
}
private void activate() {
currentImage.setImage(activeImage);
}
public String getImageViewId() {
return currentImage.getId();
}
public Node getNode() {
return currentImage;
}
public Cloth(Image[] images) {
this.previewImage = images[0];
this.activeImage = images[1];
this.equippedImage = images[2];
currentImage = new ImageView();
currentImage.setImage(previewImage);
currentImage.setId(this.getClass().getSimpleName() + System.currentTimeMillis());
currentImage.setOnDragDetected((MouseEvent event) -> {
activate();
Dragboard db = currentImage.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
// 存储节点ID以了解正在拖动的内容。
content.putString(currentImage.getId());
db.setContent(content);
event.consume();
});
}
}
ClothListBuilder.java
法律条款和版权声明
/* * 版权所有 (c) 2011, 2014, Oracle及其附属公司。 * 保留所有权利。使用受许可条款约束。 * * 此文件可在以下许可下使用和许可: * * 源代码的重新发布和使用,无论是否进行修改,只要满足以下条件: * * - 必须保留上述版权声明、此条件列表和以下免责声明。 * - 以二进制形式重新发布的代码必须复制上述版权声明、此条件列表和以下免责声明到文档和/或其他提供的材料中。 * - 未经特定事先书面许可,不得使用Oracle或其贡献者的名称来认可或推广从本软件派生的产品。 * * 本软件由版权所有者和贡献者“按原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性和适用于特定目的的保证。 * 在任何情况下,版权所有者或贡献者均不对任何直接、间接、偶然、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购、使用、数据或利润损失,或业务中断)承担任何责任,无论是合同责任、严格责任还是侵权行为(包括疏忽或其他)。 */
代码
package paperdoll.clothes;
import paperdoll.images.ImageManager;
import java.util.ArrayList;
import java.util.List;
import javafx.scene.image.Image;
/**
* 辅助类,用于生成可拖动细节的列表(细节的名称在此处硬编码)。
* 在此处设置预览、拖动和装备的图像。
* 目前,拖动和预览图像是相同的。
*
* 图像来自:http://karenswhimsy.com/public-domain-images/
*
*/
public class ClothListBuilder {
private List<Cloth> clothList;
public List<Cloth> getClothList() {
if (clothList == null) {
buildClothList();
}
return clothList;
}
private Image[] getClothImages(String clothName) {
Image []clothImages = new Image[3];
clothImages[0] = ImageManager.getImage("clothes/preview/" + clothName);
clothImages[1] = ImageManager.getImage("clothes/preview/" + clothName);
clothImages[2] = ImageManager.getImage("clothes/equipped/" + clothName);
return clothImages;
}
private void buildClothList() {
clothList = new ArrayList<>();
for (String clothName : clothNames) {
Cloth c = new Cloth(getClothImages(clothName));
clothList.add(c);
}
}
private final String []clothNames = {
"dress1.png", "dress2.png", "dress3.png", "dress4.png"
};
}
Body.java
法律条款和版权声明
/* * 版权所有 (c) 2011, 2014, Oracle及其附属公司。 * 保留所有权利。使用受许可条款约束。 * * 此文件可在以下许可下使用和许可: * * 源代码的重新发布和使用,无论是否进行修改,只要满足以下条件: * * - 必须保留上述版权声明、此条件列表和以下免责声明。 * - 以二进制形式重新发布的代码必须在文档和/或其他提供的材料中复制上述版权声明、此条件列表和以下免责声明。 * - 未经特定事先书面许可,不得使用Oracle或其贡献者的名称来认可或推广从本软件派生的产品。 * * 本软件由版权持有人和贡献者“按原样”提供,明示或暗示的任何保证,包括但不限于适销性和适用性的暗示保证,都被拒绝。 * 在任何情况下,版权持有人或贡献者均不对任何直接、间接、偶然、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购、使用损失、数据或利润损失、业务中断)承担任何责任,无论是合同责任、严格责任还是侵权行为(包括疏忽或其他)的理论,即使事先已被告知此类损害的可能性。 */
代码
package paperdoll.body;
/**
* 单例容器,用于从静态方法中访问body。
*
*/
public class Body {
private static BodyElement body;
public static BodyElement getBody() {
if (body == null)
body = new BodyElement();
return body;
}
}
BodyElement.java
法律条款和版权声明
/* * 版权所有 (c) 2011, 2014, Oracle及其附属公司。 * 保留所有权利。使用受许可条款约束。 * * 此文件可在以下许可下使用和许可: * * 源代码的重新分发和使用,无论是否进行修改,只要满足以下条件: * * - 必须保留上述版权声明、此条件列表和以下免责声明。 * - 以二进制形式重新分发时,必须在文档和/或其他提供的材料中复制上述版权声明、此条件列表和以下免责声明。 * - 未经特定事先书面许可,不得使用Oracle或其贡献者的名称来认可或推广从本软件派生的产品。 * * 本软件由版权持有人和贡献者“按原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性和适用于特定用途的保证。 * 在任何情况下,版权所有人或贡献者均不对任何直接、间接、偶然、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购、使用损失、数据或利润损失、业务中断等)承担责任,无论是合同责任、严格责任还是侵权行为(包括疏忽或其他)的理论,即使事先已被告知可能发生此类损害的可能性。 */
代码
package paperdoll.body;
import paperdoll.clothes.Cloth;
import paperdoll.images.ImageManager;
import java.util.Map;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.image.ImageView;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.Pane;
/**
* 接受拖放的身体容器。拖放到这里的可拖动细节将被装备。
*
*/
public class BodyElement {
private final Pane bodyPane;
private final ImageView bodyImage;
private Pane itemPane;
private Map<String, Cloth> items;
public void setItemsInfo(Pane p, Map<String, Cloth> m) {
itemPane = p;
items = m;
}
public Pane getBodyPane() {
return bodyPane;
}
public BodyElement() {
bodyPane = new Pane();
bodyImage = new ImageView(ImageManager.getResource("body.png"));
bodyPane.setOnDragDropped((DragEvent event) -> {
Dragboard db = event.getDragboard();
boolean success = false;
// 如果这是一个有意义的拖放...
if (db.hasString()) {
// 在这里获取一个项目ID,该ID在拖动开始时存储。
String nodeId = db.getString();
// ...在未装备的项目中搜索该项目。如果存在...
ImageView cloth = (ImageView) itemPane.lookup("#" + nodeId);
if (cloth != null) {
// ...该项目将从未装备的列表中移除
// 并附加到身体上。
itemPane.getChildren().remove(cloth);
bodyPane.getChildren().add(cloth);
cloth.relocate(0, 0);
success = true;
}
// ...无论如何,该项目现在已经装备。
items.get(nodeId).putOn();
}
event.setDropCompleted(success);
event.consume();
});
bodyPane.setOnDragOver((DragEvent event) -> {
if (event.getGestureSource() != bodyImage &&
event.getDragboard().hasString()) {
event.acceptTransferModes(TransferMode.MOVE);
}
event.consume();
});
bodyPane.getChildren().add(bodyImage);
bodyPane.setMinWidth(bodyImage.getImage().getWidth());
bodyPane.setPadding(new Insets(10.0));
}
public Node getNode() {
return bodyPane;
}
}

