JavaFX How to drag and drop an image - java

I am making a card game in JavaFX and what I was able to find code that will allow me to drag a piece of text. However, this doesn't show the text being dragged.
What I am currently doing is setting my scene which is the root node to be the target and setting my cards to be the source. This allows me to drag cards which are image views on my desktop but I want two things which I am struggling with.
First I want to have the image actually show up when I am dragging it and second I want to be able to place the image on my scene.
Here is the code for the card
tempImageView.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
/* drag was detected, start a drag-and-drop gesture*/
/* allow any transfer mode */
Dragboard db =
tempImageView.startDragAndDrop(TransferMode.ANY);
/* Put a string on a dragboard */
ClipboardContent content = new ClipboardContent();
content.putData(tempImageView);
db.setContent(content);
event.consume();
}
});
Here is the code for my scene
scene.setOnDragOver(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* data is dragged over the target */
/* accept it only if it is not dragged from the same node
* and if it has a string data */
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
event.consume();
}
});
Here is the tutorial I was trying to follow: https://docs.oracle.com/javafx/2/drag_drop/jfxpub-drag_drop.htm
I am new to JavaFX so any help would be awesome!

Related

JavaFX Robot.getScreenCapture causing scene to not update prior

I have an options menu from which you can save the game and it should briefly close the menu and take a screenshot of the current game.
However, the menu does not close until after calling getScreenCapture even though it runs before causing the screenshot to always be of the settings menu.
(The screenshot itself is working it's just controlling what displays at the time of the screenshot)
!! Without the screenshot line it updates the scene immediately even though the scene change line comes before.
So far I have tried Thread.sleep but no length of time allows for the scene to update
//The initial call to save:
private void saveRoom() {
program.changeState(previous);
room.save();
}
//The changing of scenes: (State extends Scene)
public void changeState(State state) {
currentState = state;
stage.setScene(currentState);
currentState.paintAll();
}
//How the game scene draws to screen:
#Override
public void paintAll() {
ArrayList<Shape> toAdd = new ArrayList<>();
for(Furniture f : furniture) {
f.paint(toAdd);
}
optionsButton.paint(toAdd);
addFurnitureButton.paint(toAdd);
root.getChildren().clear();
root.getChildren().addAll(toAdd);
}
//How the options menu draws to screen (same as game):
#Override
public void paintAll() {
ArrayList<Shape> toAdd = new ArrayList<>();
toolsButton.paint(toAdd);
saveButton.paint(toAdd);
saveAndExitButton.paint(toAdd);
exitButton.paint(toAdd);
closeButton.paint(toAdd);
root.getChildren().clear();
root.getChildren().addAll(toAdd);
}
//The capture command:
robot.getScreenCapture(null, new Rectangle2D(x,y,x1,y1));
Update: I am now using the Scene.snapshot command to take the screenshot instead and it does not cause the problem, but am still open to finding out how to go about using Robot to take a screenshot since unlike Scene.snapshot, it captures the whole screen rather than just the program which could come in handy in a future project.

Javafx- Mouse click event that undoes what the previous mouse click did

So I currently have a 3x3 gridpane of which I add a pane with a white background to each space on the grid.
What I am trying to do is have it so that if a user clicks on one of these spaces, the white pane will change to another color. Then if the user were to click on the space again, the pane would change back to white. If clicked again, then it would change to that color again, and so on.
In short, a click would cause an action, and the next click, and those after it would reverse/undo the previous action.
However, I can only get the initial click to work with this. Everything else I've thought to add to this hasn't worked.
#Override
public void handle(MouseEvent me) {
if (me.getClickCount() == 1) {
pane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));}
Any help would be really appreciated!
If it really has to be a Pane, you could try to write a custom Pane which will make it easier for you to control its behaviour:
class MyPane extends Pane{
private Background standard, other;
public MyPane(){
standard = new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY));
other = new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY));
this.setBackground(standard);
}
public void changeColor(){
if(this.getBackground().equals(standard){
this.setBackground(other);
else{
this.setBackground(standard);
}
}
public void setBackground(Background bckgrnd){
this.other = bckgrnd;
}
If you use this class instead of a standard Pane, you are able to control the color changing simply via
#Override
public void handle(MouseEvent me){
myPane.changeColor();
}
If you would use the Rectangleclass, you could use the following code:
#Override
public void handle(MouseEvent me){
if(rectangle.getFill() == standard){
rectangle.setFill(other);
}else{
rectangle.setFill(standard);
}
provided that you defined the 2 Paint variables standard and other, e.g. :
private final Paint standard = Color.WHITE;
private Paint other = Color.RED;
see Color

Pilling two obj with OnMousePressed on top of each other in javafx

Been trying around and searching but couldn't find any solution, so I finally decided to give up and ask further...
Creating a javafx app, I load tiles in a TilePane.
This tiles are clickable and lead to a details page of their respective content.
On each tile, if they do belong to a certain pack, I do display the pack name, that is also clickable and lead to a page showing that specific pack content.
So that means the container, the tile, that is a Pane is clickable and on top of it I have a Label that is claickable also. What happens is when I do click the Label, it also triggers the Pane onMousePressed()... Here is a part of the tile creation code, the part focused on the onMousePressed(). I tried to make the Pane react by double click and the Label by single, it works, but I want to Pane to open with a single click.
I would be more than thankfull for any ideas how to solve that.
public DownloadTile (Downloadable upload, MainApp mainApp) {
_mainApp = mainApp;
_upload = upload;
_tile = new Pane();
_tile.setPrefHeight(100);
_tile.setPrefWidth(296);
_tile.setStyle("-fx-background-color: #ffffff;");
_tile.setCursor(Cursor.HAND);
}
public void refresh() {
_tile.getChildren().clear();
_tile.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.isPrimaryButtonDown() /*&& event.getClickCount() == 2*/) {
_mainApp.showDownloadDialog(dt, _upload);
}
}
});
if (_upload.getPack() != null) {
Label pack = new Label();
pack.setText(_upload.getPack());
pack.getStyleClass().add("pack-link");
pack.setCursor(Cursor.HAND);
pack.relocate(10, 48);
_tile.getChildren().add(pack);
pack.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if (event.isPrimaryButtonDown()) {
_mainApp.showPackPage(_upload);
}
}
});
}
}
Your label will receive the mouseclick first (since it's on top), so after you have processed the click, you can stop it from being passed down the chain using 'consume':
pane.setOnMouseClicked(
(Event event) -> {
// process your click here
System.out.println("Panel clicked");
pane.requestFocus();
event.consume();
};

Minimize/maximize parent JFrame

Im making a quiz application. And when a team pushed their button, they aren't allowed to still see the question or see the video/audio piece. This kind of information is displayed in the quizview ( this is a jpanel ) added to a parent JFrame. What i'm trying to do is minimize the JFrame when a button is pushed from the teams. This works perfectly. If a button is pushed the administator get a pop up in his view. If the answer is incorrect the JFrame should be maximized again. So when he pushes a button if the answer is incorrect, a boolean will be set on true in the quiz model ( $maximize ). We update the views then. In the update of the view im checking if the boolean is set on true. If it is true, i call the maximize method. And maximize it again when the answer is wrong. Minimizing works perfectly, but maximizing not.
Anyone knows what's wrong?
This is my code in the view, this view is a JPanel in the bigger JFrame, where the maximizing happens :
public void update(Observable arg0, Object arg1) {
$question = (Question) arg1;
if(((QuizModel) getModel()).getMaximize()) /* Only maximize the JFrame when needed */
maximizeFrame(); /* Maximize the frame first */
repaint();
}
/**
* Maximize the parent JFrame so the teams can see the question
*/
protected void maximizeFrame() {
System.out.println("MAXIMIZE");
JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
topFrame.setState(JFrame.MAXIMIZED_BOTH);
}
The minimizing occurs when a team pushed their button, here is the code :
/**
* If a button gets pressed we call this function
* #param team the team that pressed their button
*/
protected void buttonPressed(int team) {
/* Check if a button is pressed */
if(((QuizModel) getModel()).getTeamPressed() > 0)
$isPressed = true;
else
$isPressed = false;
/* If there hasn't been pressed yet and the question is not null */
if(!$isPressed && $question != null){
minimizeFrame(); /* Minimize the frame */
/* If this question has a media path we need to pause the audio/video, we also check if the user has installed vlcplayer and selected the right path */
if($question.getMediaPath() != null && QuizSoftwareModel.$vlcPath != null)
((QuizController)getController()).pause(); /* Pause the video */
/* Give a pop up message to the admin that a team has pushed their button */
((QuizController)getController()).showScoreView(team);
}
}
/**
* Minimize the parent JFrame so the teams can't see the question anymore
*/
protected void minimizeFrame() {
JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
topFrame.setState(JFrame.ICONIFIED);
}
[EDIT] Reduced the code.
Thanks!
The solution is using topFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); instead of setState.
Setstate only sets the state of the current frame, because i needed the parent frame i needed to use setExtendedState.
Also missed some booleans to maximize/minimize when needed.

Display a GWT Image in a centered PopupPanel onLoad

Using GWT I am displaying an image thumbnail with a ClickHandler that then shows the full image (can be several MB) in a centered PopupPanel. In order to have it centered the image must be loaded before the popup is shown, otherwise the top-left corner of the image is placed in the middle of the screen (the image thinks it is 1px large). This is the code I am using to do this:
private void showImagePopup() {
final PopupPanel popupImage = new PopupPanel();
popupImage.setAutoHideEnabled(true);
popupImage.setStyleName("popupImage"); /* Make image fill 90% of screen */
final Image image = new Image();
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
popupImage.add(image);
popupImage.center();
}
});
image.setUrl(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
Image.prefetch(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
}
However, the LoadEvent event is never fired, and thus the image is never shown. How can I overcome this? I want to avoid using http://code.google.com/p/gwt-image-loader/ because I do not want to add extra libraries if I can avoid it at all. Thanks.
The onLoad() method will only fire once the image has been loaded into the DOM. Here is a quick workaround:
...
final Image image = new Image(attachmentUrl + CFeedPostAttachment.ATTACHMENT_FILE);
image.addLoadHandler(new LoadHandler() {
#Override
public void onLoad(LoadEvent event) {
// since the image has been loaded, the dimensions are known
popupImage.center();
// only now show the image
popupImage.setVisible(true);
}
});
popupImage.add(image);
// hide the image until it has been fetched
popupImage.setVisible(false);
// this causes the image to be loaded into the DOM
popupImage.show();
...
Hope that helps.

Categories