GoXR3Plus GoXR3Plus - 2 months ago 21
Java Question

JavaFX drag adjustable Label like Slider


Edit:Code is available on
github(https://github.com/goxr3plus/DragAdjustableLabel)

Question


I made a custom control in
javaFX
which I don't know how to name it. It actually does not exist in the
javaFX
packages but I saw it in other programs like LMMS where it's been used to control the volume.


The problem


When the mouse is reaching the top or bottom of the monitor screen nothing can be done. Have a look at the code to see what I'm talking about. How to solve the problem? Feel free to edit the title to a more appropriate ones.

Image

import java.awt.Robot;

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class FX3 extends Application {

@Override
public void start(Stage stage) throws Exception {

// Root-BorderPane
BorderPane borderPane = new BorderPane(new VolumeLabel(0, 100));
borderPane.setStyle("-fx-background-color:black;");

// Scene
stage.setScene(new Scene(borderPane, 200, 200, Color.BLACK));
stage.show();
}

public static void main(String[] args) {
launch(args);
}

// TODO SpecialLabel
class VolumeLabel extends Label {

int screenX, screenY, previousY, minimumValue, maximumValue;

IntegerProperty currentValue = new SimpleIntegerProperty(15);

/**
* Constructor
*/
public VolumeLabel(int minimumValue, int maximumValue) {

this.minimumValue = minimumValue;
this.maximumValue = maximumValue;
textProperty().bind(currentValue.asString().concat(" %"));
setStyle(
"-fx-background-color:white; -fx-text-fill:black; -fx-padding:-2 8 -2 8; -fx-background-radius: 15; -fx-font-size:20; -fx-cursor:open-hand;");

// MouseListeners
setOnMousePressed(m -> {
screenX = (int) m.getScreenX();
screenY = (int) m.getScreenY();
//setCursor(Cursor.NONE); //Uncommend this line to make the cursor invisible
});

setOnMouseDragged(m -> {
setCurrentValue(
getCurrentValue() + (m.getScreenY() == previousY ? 0 : m.getScreenY() > previousY ? -1 : 1));
previousY = (int) m.getScreenY();
});

setOnMouseReleased(m -> {
// When the mouse is released -> move it to the initial position
try {
new Robot().mouseMove(screenX, screenY);
} catch (Exception e) {
e.printStackTrace();
}
setCursor(Cursor.OPEN_HAND);
});
}

/**
* Returns the Current Value of VolumeLabel
*
* @return
*/
public int getCurrentValue() {
return currentValue.get();
}

/**
* Setting the Current Value of VolumeLabel
*
* @param value
*/
public void setCurrentValue(int value) {
//System.out.println("Value:" + value + ", CurrentValue:" + currentValue.get());
if (value >= minimumValue && value <= maximumValue)
currentValue.set(value);
}

}

}

Answer

Here is the answer(the code also in on github):

import java.awt.Robot;

import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Cursor;
import javafx.scene.control.Label;
import javafx.stage.Screen;

/**
 * A Costume Node which is working like a Slider. <br>
 * <b>!</b> When you hold the mouse on it and drag upside the value is
 * increased. <br>
 * <b>!</b> When you hold the mouse on it and drag down side the value is
 * decreased.
 * 
 * <br>
 * Usage:
 * 
 * <pre>
 * <code>
*     //initialize
*     DragAdjustableLabel dragAdjustableLabel = new DragAdjustableLabel(10, 0, 100);
*     
*     //add it for example to a BorderPane
*     primaryStage.setScene(new Scene(new BorderPane(dragAdjustableLabel)));
 * }
 *</code>
 * </pre>
 * 
 * @author GOXR3PLUS
 * @version 1.0
 */
public class DragAdjustableLabel extends Label {

    // Variables
    private int screenX;
    private int screenY;
    private int previousY;
    private int minimumValue;
    private int maximumValue;

    /**
     * The current value of the DragAdjustableLabel
     */
    private IntegerProperty currentValue;

    /**
     * Constructor
     * 
     * @param minimumValue
     *            Minimum Value that the slider can have
     * @param maximumValue
     *            Maximum Value that the slider can have
     */
    public DragAdjustableLabel(int currentValue, int minimumValue, int maximumValue) {

        this.currentValue = new SimpleIntegerProperty(currentValue);
        this.minimumValue = minimumValue;
        this.maximumValue = maximumValue;

        // Add a costume style class
        this.getStyleClass().add("drag-adjustable-label");
        setCursor(Cursor.OPEN_HAND);

        textProperty().bind(this.currentValue.asString().concat(" %"));

        // when the mouse is pressed
        setOnMousePressed(m -> {
            screenX = (int) m.getScreenX();
            screenY = (int) m.getScreenY();
            setCursor(Cursor.NONE); // comment this line to make the cursor
                                    // visible
        });

        // when the mouse is dragged
        setOnMouseDragged(m -> {

            // calculate the monitor height
            double screenHeight = Screen.getPrimary().getBounds().getHeight();

            // !if the mouse has reached the the top of the monitor
            // or
            // ! if the mouse has reached the bottom of the monitor
            if (m.getScreenY() <= 0 || m.getScreenY() + 10 >= screenHeight) {
                resetMouse();
                return;
            }

            // Calculate the current value
            setCurrentValue(
                    getCurrentValue() + (m.getScreenY() == previousY ? 0 : m.getScreenY() > previousY ? -1 : 1));
            previousY = (int) m.getScreenY();
        });

        // when the mouse is released
        setOnMouseReleased(m -> {
            resetMouse();
            setCursor(Cursor.OPEN_HAND);
        });
    }

    /**
     * Reset the mouse to the default position(which is the center of the
     * element)
     * 
     * @param x
     * @param y
     */
    private void resetMouse() {
        try {
            new Robot().mouseMove(screenX, screenY);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Setting the Current Value of VolumeLabel
     * 
     * @param value
     */
    public void setCurrentValue(int value) {

        // if the value is between the limits
        if (value >= minimumValue && value <= maximumValue)
            currentValue.set(value);
    }

    public int getCurrentValue() {
        return currentValue.get();
    }

    public IntegerProperty currentValueProperty() {
        return currentValue;
    }

}
Comments