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; } }