Key Input using GtkD - events

I'm a beginner of both gtk and GtkD.
Now, I'm trying to get input from keyboard with reference to this .
But, It seems that three years have made some changes in Toolkits.
I wrote code below. However, I got strange values of ev in callback function.
I could not see any prospect of resolution with going alone.
So, could you show me where to modify?
I appreciate you in advance, and also your patient with my poor English.
I'm using gtkD-2.1.1 and gtk+3.2.3.
this is the full code:
import std.stdio;
import gtkc.gdktypes;
import gtk.MainWindow;
import gtk.Widget;
import gdk.Event;
import gtk.Main;
class Window : MainWindow{
immutable width = 200;
immutable height = 200;
this(){
super("input test");
setDefaultSize(width,height);
setEvents(EventMask.KEY_PRESS_MASK); // Actually I don't know how this works
auto callback_func = cast(bool delegate(Event,Widget))&get_key; // I doubt this cast
this.addOnKeyPress(callback_func);
showAll();
}
bool get_key(GdkEventKey* ev, Widget widget){
writefln("sender %s", widget);
writefln("type %x",ev.type);
writefln("window* %x",ev.window);
writefln("send_event %x",ev.sendEvent);
writefln("time %x",ev.time);
writefln("state %x",ev.state);
writefln("keyval %x",ev.keyval);
writefln("length %x",ev.length);
writefln("gchar* %x",ev.string);
writefln("hardware_keycode %x",ev.hardwareKeycode);
writefln("group %x",ev.group);
writefln("is_modifier %x\n",ev.bitfield0);
return true;
}
}
void main(string[] args){
Main.init(args);
auto win = new Window();
Main.run();
}

Yes, that cast is wrong. I guess that Signature with GdkEventKey* is outdated. Change your get_key to take an Event and you should get proper results:
...
auto call = &get_key;
...
bool get_key(Event e, Widget widget){
GdkEventKey* ev = e.key();
...
I have never done anything with GtkD, and this is just the result of some glances over the docs. So, it's probably not best practice, but it should get you back on the road.

Related

How to handle tap events for an interactive watch faces with androidx.wear?

What is the correct way of handling tap events with the new androidx.wear.watchface libraries? I was doing this with the now deprecated android.support:wearable libraries without any problem with Java (using onTapCommand). Now, everything seems to be quite different, especially since the documentation and examples seem to be available only in Kotlin. Also, I can't find any example which properly shows how the functions are used.
The documentation mentions setTapListener, TapListener. And then there are the functions onTap, onTapEvent and onTapCommand. This seems very confusing.
Could somebody put here a small example? Or point me to a working example on the internet?
Any help much appreciated!
Implementing this seemed to work for me
https://developer.android.com/reference/androidx/wear/watchface/WatchFace.TapListener
My code:
class WatchFaceRenderer(...): Renderer.CanvasRenderer(...), WatchFace.TapListener {
override fun onTapEvent(tapType: Int, tapEvent: TapEvent, complicationSlot: ComplicationSlot?) {
if (tapType == TapType.UP)
// do something
invalidate()
}
}
class Service : WatchFaceService() {
override suspend fun createWatchFace(
surfaceHolder: SurfaceHolder,
watchState: WatchState,
complicationSlotsManager: ComplicationSlotsManager,
currentUserStyleRepository: CurrentUserStyleRepository
): WatchFace {
val renderer = WatchFaceRenderer(
context = applicationContext,
surfaceHolder = surfaceHolder,
watchState = watchState,
currentUserStyleRepository = currentUserStyleRepository,
canvasType = CanvasType.SOFTWARE,
)
return WatchFace(WatchFaceType.ANALOG, renderer).setTapListener(renderer)
}
}

How can I make changes in the GUI with background work in JavaFX?

From all the searching and reading it’s clear that I need to call Platform.runLater() to change the GUI. It also appears I need to use the Runnable interface. Perhaps I should also use Tasks?
But I can’t figure out how exactly I should use them. Plus, I’m not sure which class I should put them in. I’m super new to JavaFX.
My trial JavaFX project has only a Label and a TextField. Label contains a question and the TextField is for answering. Simple enough.
I ran into the problem here:
The answer checking method is in a separate class. I can’t figure out how I can access the components of the GUI/FXML and change them. The methods in the other classes are static while the components of the GUI/FXML are non-static.
Since my actual project would have many quizzes, I'm keen on using separate classes for checking answers.
Only 3 small classes are relevant here:
The “Launcher” class which contains the main method.
The “ViewController” class for the FXML file as well as some methods.
The “Ans” class which has a method to check the answer input.
In which class should I put the Platform.runLater()? And how would the code be?
I’ll just share the code of the “Ans” and the “ViewController” classes.
Ans (The background works are supposed to happen in this file. In the comments, I've mentioned what I want to do but unable to do. For example, I want to set the Label text from there but I can't. Since I have no idea how to do it I've just put a System.out.Println there. In the comments next to it, I've mentioned what I actually want to do.)
package com.dan.ans;
import com.dan.qn.Qn;
import com.dan.view.ViewController;
public class Ans {
public static void checkAns() {
// Checks if the ans is correct.
if (ViewController.getTextFieldInput().equalsIgnoreCase(Qn.getAns())) {
System.out.println("Correct!"); // Here I want the label to say 'Correct!' rather than it be print out in the console.
Qn.setQuestion(); // This gets the next question from the database. But again, I don't know how to make the changes show on the screen. (In the actual code I'd have a separate Label for each of these things)
} else { // Runs if it's not correct.
System.out.println("Incorrect!"); // Here I want the label to say 'Incorrect' rather than it be print out in the console.
}
}
}
ViewController
package com.dan.view;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import com.dan.ans.Ans;
import com.dan.qn.Qn;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
public class ViewController implements Initializable {
private static String textFieldInput; // I don't know how to access the typed info in the textField from another class. So I store it here and get it from it.
// This is the getter I use for it. (See above)
public static String getTextFieldInput() {
return textFieldInput;
}
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
Qn.setQuestion(); // This method is in the Qn class. It retrieves data from the db file and keeps them in variables.
label.setText(Qn.getQn()); // This sets the label's text using the retrieved data. So you see the first question when the program opens.
}
// Event Listener on TextField[#textField].onAction
public void enter(ActionEvent event) throws IOException {
textFieldInput = textField.getText(); // Stores the typed info in the variable to be accessed from elsewhere.
Ans.checkAns(); // Runs the checkAns to check if the typed answer is correct or not.
}
}
The “Launcher” method just looks like any method with a main class. So I haven’t shared its code here.
Could someone please show me how I can update the components in the GUI from other classes such as “Ans”? I’m pretty sure I should use Platform.runLater() and Runnable. Also may be Tasks. I’ve seen several examples but it’s not clear how I can use it this context.
Thanks a lot in advance! :)
It's not really particularly clear what the issue is here. The natural (to me, anyway) approach would simply be to make the checkAnswer(...) method a method that simply "does what it says on the box", i.e. that takes an answer as a parameter, checks it, and returns a value to the caller indicating if it is correct.
That way you can also avoid all the ugly static hacks.
public class Ans {
public boolean checkAns(String answer) {
// not really sure what Qn is here, but you can also clean this up and
// get rid of the static methods
if (answer.equalsIgnoreCase(Qn.getAns()) {
// not sure if this really belongs here?
Qn.setQuestion(); // really takes no parameters? Sets it to what, then?
return true ;
} else {
return false ;
}
}
}
And then in your controller, you can just do
public class ViewController implements Initializable {
private Ans ans ;
#FXML
private Label label;
#FXML
private TextField textField;
#Override
public void initialize(URL location, ResourceBundle resources) {
ans = new Ans();
// ...
}
// ...
public void enter(ActionEvent event) {
if (ans.checkAns(textField.getText())) {
// update UI to show answer was correct, etc
} else {
// update UI to show answer was incorrect...
}
}
// ...
}
Note how this allows you to maintain proper separation of concerns: the Ans class doesn't need to know anything at all about the UI (which it should not know about at all), and all the UI-specific code is encapsulated in the controller class where it belongs.
It's not really clear why you are asking about Platform.runLater(...) and using Task, since none of the code you posted appears to involve any background threads (i.e. none of this code seems to take an appreciable amount of time to run). If, for example, the checkAns(...) method was doing some remote lookup and did take time to run, you would execute it in a Task and update the UI from the task's onSucceeded handler. See, e.g. Using threads to make database requests. Your question really seems to be more about basic OO design and how to define the relationships between different objects, though; I don't think you are actually asking about threading at all.

event.preventDefault is unclear for me even if I understand stopImmediatePropagation and stopPropagation

event.preventDefault seems to be hard to understand to me.(this is the dark side of AS3). :)
stopImmediatePropagation - stopPropagation methods are pretty easy to understand.
Here's a test I made (which need just a copy/paste on the timeline) this may avoid You to spend too much time.
I just do not understand in which case preventDefault may be useful...
If you have some suggestions or links, please could You give me some feedback?
Here is the code :
// This example is coded on the Timeline.
// The Stage must fit 550 * 400 pixels (default size).
import flash.display.DisplayObjectContainer;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
// function to create a MovieClip and return it to a variable.
function createMC(target:DisplayObjectContainer):MovieClip{
var mc:MovieClip = new MovieClip();
target.addChild(mc);
return mc;
}
// function that draws a Rectangle in the MovieClip of your choice.
function dRect(target:MovieClip,x:uint,y:uint,width:uint,height:uint,color:uint,alpha:Number):void{
var g:Graphics = target.graphics;
g.lineStyle(1,0x000000);
g.beginFill(color,alpha);
g.drawRect(x-width/2,y-height/2,width,height);
g.endFill();
}
// event function that trace the properties of the Event.
function traceTarget(me:MouseEvent):void{
trace(" *** event.phase = " + me.eventPhase + ", event.bubbles = " + me.bubbles);
trace("me.target.name = " + me.target.name);
trace("me.currentTarget.name(the listening object) = " + me.currentTarget.name);
/*
Use preventDefault and the events for m1 AND this will be triggered.
MOUSE_DOWN,setText will be called 2 times 1 time for this, the second time for m1!
MOUSE_DOWN,traceTarget will be called 2 times 1 time for this, the second time for m1!
*/
//me.preventDefault();
/*
Use stopPropagation to avoid that the same function is not called if an event occurs.
MOUSE_DOWN,setText will be called !
*/
me.stopPropagation();
/*
Use stopImmediatePropagation to avoid all the functions that another listener may trigger.
MOUSE_DOWN,setText WILL NEVER BE CALLED because traceTarget has been called!
stopImmediatePropagation will only allow the first listener (traceTarget).
*/
//me.stopImmediatePropagation();
trace(me.toString());
// trace the Event that is triggered.
}
function setText(me:MouseEvent):void{
tf_1.text = "me.target.name = " + me.target.name;
tf_1.setTextFormat(tf);
countText++;
trace("setText("+ me.target + ") has been called " + countText + " time(s)");
countText = 0;
}
/*
A counter to see how many times an Event method is triggered
*/
var countText:uint = 0;
/*
Declare a TextField
*/
var tf_1:TextField = new TextField();
this.addChild(tf_1);
tf_1.width = 300;
tf_1.height = 20;
tf_1.x = this.stage.stageWidth - this.stage.stageWidth/2 - tf_1.width/2;
tf_1.y = 30;
var tf:TextFormat = new TextFormat(null,16,0xff0000,true,null,null,null,null,TextFormatAlign.CENTER)
tf_1.text = "Click on a Square/Rectangle";
tf_1.setTextFormat(tf);
/*
Declare 4 MovieClips
3 MovieClips inside each other
- m1 on "this" (root1 in this case).
- m2 inside m1
- m3 inside m2
1 MovieClip on "this" (root1 in this case).
*/
var m1:MovieClip
var m2:MovieClip
var m3:MovieClip
var otherClip:MovieClip
// Create the MovieClips
m1 = createMC(this);
m2 = createMC(m1);
m3 = createMC(m2);
otherClip = createMC(this);
// set the names for the MovieClip's
m1.name = "movieClip_1";
m2.name = "movieClip_2";
m3.name = "movieClip_3";
otherClip.name = "otherClip";
// Draw Rectangles in the MovieClip's
dRect(m1,275,200,100,100,0xff0000,1);
dRect(m2,275,200,50,50,0x00ff00,1);
dRect(m3,275,200,25,25,0x0000ff,1);
dRect(otherClip,100,200,50,50,0xff9900,1);
// Add a listener on m1 MovieClip.
m1.addEventListener(MouseEvent.MOUSE_DOWN,traceTarget,false);
m1.addEventListener(MouseEvent.MOUSE_DOWN,setText,false);
// Add a listener on root (root1 in this case).
this.addEventListener(MouseEvent.MOUSE_DOWN,traceTarget,false);
this.addEventListener(MouseEvent.MOUSE_DOWN,setText,false);
If You could help me to understand the preventDefault method, I should be really happy.
Best regards. Nicolas.
From the documentation of preventDefault()
Many events have associated behaviors that are carried out by default. For example, if a user types a character into a text field, the default behavior is that the character is displayed in the text field. Because the TextEvent.TEXT_INPUT event's default behavior can be canceled, you can use the preventDefault() method to prevent the character from appearing.
Here's an example for that:
package
{
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.display.Sprite;
import flash.events.TextEvent;
public class Main extends Sprite
{
public function Main()
{
var tf:TextField = new TextField();
tf.type = TextFieldType.INPUT;
tf.border = true;
addChild(tf);
tf.addEventListener(TextEvent.TEXT_INPUT, onInput);
}
private function onInput(te:TextEvent):void
{
te.preventDefault();
}
}
}
The TextField is there, but you cannot type into it. If you comment out the line that adds the listener, the default behaviour is not prevent and you can type.
stopImmediatePropagation(), stopPropagation() and eventPhase are all concerned with the event flow: the three phases of capturing, target and bubbling. As such, they can be used to influence if an Event "reaches" an object that added a listener for it. If you want to think about the listeners that you add for an event as custom behaviour, you might call the three above "preventCustom()".
The documentation of the two methods explicitely mentions this:
Note: This method does not cancel the behavior associated with this event; see preventDefault() for that functionality.
preventDefault() deals with the default behaviour associated with the event and has nothing to do with the event flow.
As an example, you might be thinking that you could achieve the same thing as the above example by adding a listener for the capturing phase at stage and then stopping the propagation, like so:
package
{
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.display.Sprite;
import flash.events.TextEvent;
public class Main extends Sprite
{
public function Main()
{
var tf:TextField = new TextField();
tf.type = TextFieldType.INPUT;
tf.border = true;
addChild(tf);
stage.addEventListener(TextEvent.TEXT_INPUT, onInput, true); // new: added to stage and for capturing phase
}
private function onInput(te:TextEvent):void
{
te.stopImmediatePropagation(); // new: stopping propagation
}
}
}
If you execute this code, you will be able to type into the TextField just fine. Again, you're just messing with the event flow here, not the default behaviour. All you do is prevent subsequent listeners to be getting the Event, for example, if you add a listener to the TextField itself as shown below, it will never be executed, because you stop the event flow before it is reached.
package
{
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.display.Sprite;
import flash.events.TextEvent;
public class Main extends Sprite
{
public function Main()
{
var tf:TextField = new TextField();
tf.type = TextFieldType.INPUT;
tf.border = true;
addChild(tf);
tf.addEventListener(TextEvent.TEXT_INPUT, onTfInput);
stage.addEventListener(TextEvent.TEXT_INPUT, onInput, true);
}
private function onTfInput(te:TextEvent):void
{
// never executed
}
private function onInput(te:TextEvent):void
{
te.stopImmediatePropagation();
}
}
}
tl, dr;
If you find a bomb with a self timer ticking, stopImmediatePropagation() will stop other people getting notice about that and might prevent a panic, but only preventDefault() will save your life. If cancelable is false, you better run.
From the as3 docs: preventDefault() "cancels the events behaviour if that behaviour can be cancelled".
One example i can give you is the android back button. If you press the back button, it will minimize your AIR app by default. But if you listen for it and call preventDefault(). It will stop that default behavior so you can navigate to, your last open page instead.
Another example would be the home button on android, you can call preventDefault() but this action cannot he cancelled, so it will be ignored.
A mouse event like your example however, im not in a position to test what exactly that does

Haxe application exits when deployed to windows

I am making a game engine in haxe/openfl. so far it's just supposed to display the image that belongs to the thing object. what I have built so far runs perfectly on when deployed as a flash application, but closes instantly when I deploy it as a windows application. It just creates a blank screen in html5. I have not tested other targets. I am using HIDE, and every time it crashes, HIDE brings up the message: "File c:\Users\Adu\Documents\HaxeProjects\Downloaded\Export\windows\cpp\bin\Downloaded.exe was changed. Reload?" and gives me the options yes or no. My answer doesn't seem to change the situation. when I manually go into the export directory and run the application, it gives the error: "Error Custom([file_write,stderr]). Here is my code:
Main:
package;
import openfl.display.Graphics;
import openfl.Assets;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.Lib;
import openfl.text.TextField;
import openfl.text.TextFormat;
import openfl.ui.Keyboard;
import openfl.events.*;
class Main
{
static var obj(default,default):ObjectManager; //contains the list that all gameobjects add themselves to
static var stage = Lib.current.stage;
public static function main() // this is the gameloop
{
// static entry point
startUp();
var running = true; // gives me a way to exit the gameloop
while (running)
{
logic();
render();
Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(event)
{
if (event.keyCode == Keyboard.ESCAPE)
{
running=false;
}
});
}
}
static function startUp() // runs once, when the game is started
{
obj= new ObjectManager();
stage.align = openfl.display.StageAlign.TOP_LEFT;
stage.scaleMode = openfl.display.StageScaleMode.NO_SCALE;
}
static function logic() // loops, this handles the logic
{
var thing = new GameObject("assets/pixel_thing.png", 1, obj);
var mech = new GameObject("assets/mechwarrior.png", 0, obj);
}
static function render() // runs right after logic and draws everything to the screen
{
for (i in obj.objects) //iterates through a list of gabeobjects and draws them, it is 2 dimensional so that I can draw objects in blocks
{
for (j in i)
{
Lib.current.addChild(j);
}
}
}
}
GameObject:
package ;
import openfl.display.BitmapData;
import openfl.Assets;
import openfl.display.Bitmap;
import openfl.display.Sprite;
import openfl.events.Event;
import openfl.Lib;
import openfl.text.TextField;
import openfl.text.TextFormat;
class GameObject extends Sprite
{
public function new(?image:String, zOrder:Int, objectManager:ObjectManager) // image is the image, zorder is which layer it's drawn on, lower layers are drawn on top objectmanager is just there to help me pass the list to the object
{
super();
var data = Assets.getBitmapData(image);//this is the image data
var bitmap:Bitmap = new Bitmap(data);//this is the actual image
Lib.current.stage.addChild(bitmap);//this sraws the image when the object is instantiated
objectManager.objects[zOrder].push(this);// this adds it to the list of objects
}
}
ObjectManager:
package ;
class ObjectManager
{
public var objects = new Array<Array<GameObject>>();
}
why is it that it works on flash but not windows? How do I fix this?
First off - this doesn't work fine on flash either. Are you running this in the flash debug player? If you don't, which I assume is the case, you won't see any exceptions.
There's a null reference error at this line:
objectManager.objects[zOrder].push(this);// this adds it to the list of objects
You are accessing the array at index zOrder, which doesn't exist. objects is being initialized to [], which does not include the "inner arrays" (it can't, really, how would it know how many of them there should be?).
Now, Windows builds don't give you very helpful debug information by default. A simple way around is to use neko (which mostly behaves the same as hxcpp builds, except it compiles faster and performs worse) for debugging, where you get a stacktrace by default on crashes.
Sure enough, it's the same issue as in flash, the only difference is that native builds crash while flash just "ignores it" and tries to carry on.
Invalid field access : objects
Called from GameObject::new line 92
Called from GameObject::$init line 83
Called from Main::logic line 61
Called from Main::main line 38
Called from Reflect::callMethod line 58
Called from ApplicationMain::main line 91
Called from openfl.Lib::create line 113
For better hxcpp build debug info, you might want to have a look at the crashdumper lib.

How to get location of mouse in JavaFX?

I am a beginner in java(fx).
How do you get the mouse location in x and y in JavaFX? I tried using AWT's MouseInfo(also imported it), but it's not working. I also saw the code for it in Ensembles(that dragging the ball-window in "advanced stage", that's what I need to do, drag my undecorated JavaFX stage), but it also doesn't work. I am using FXML with controller, and I guess that's the main problem. Should I switch back to the single-file simple JavaFX? I know FXML is better for laying out the UI, but I can't get many of such codes to work. Or do I need some other sort of code for my controller? Please give proper codes with comments wherever possible.
If you need a bit of my code to inspect, feel free to ask.
There are a few items in your question - I'll tackle them one at a time.
How do you get the mouse location in x and y in JavaFX?
Add a mouse event handler to the appropriate JavaFX component that you want to track the mouse location in. A JavaFX mouse event will report multiple different kinds of co-ordinates. The x and y co-ordinates are relative to the top left corner of the node whose location is being monitored. The sceneX and sceneY co-ordinates are relative to the scene's top left 0,0 co-ordinates. The screenX and screenY co-ordinates are relative to the top left 0,0 co-ordinates of the current screen.
These co-ordinates are documented in the MouseEvent documentation. There is extra information in understanding co-ordinate systems in the Node and Scene documentation.
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.*;
public class MouseLocationReporter extends Application {
private static final String OUTSIDE_TEXT = "Outside Label";
public static void main(String[] args) { launch(args); }
#Override public void start(final Stage stage) {
final Label reporter = new Label(OUTSIDE_TEXT);
Label monitored = createMonitoredLabel(reporter);
VBox layout = new VBox(10);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10px;");
layout.getChildren().setAll(
monitored,
reporter
);
layout.setPrefWidth(500);
stage.setScene(
new Scene(layout)
);
stage.show();
}
private Label createMonitoredLabel(final Label reporter) {
final Label monitored = new Label("Mouse Location Monitor");
monitored.setStyle("-fx-background-color: forestgreen; -fx-text-fill: white; -fx-font-size: 20px;");
monitored.setOnMouseMoved(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
String msg =
"(x: " + event.getX() + ", y: " + event.getY() + ") -- " +
"(sceneX: " + event.getSceneX() + ", sceneY: " + event.getSceneY() + ") -- " +
"(screenX: " + event.getScreenX()+ ", screenY: " + event.getScreenY() + ")";
reporter.setText(msg);
}
});
monitored.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent event) {
reporter.setText(OUTSIDE_TEXT);
}
});
return monitored;
}
}
I tried using AWT's MouseInfo(also imported it), but it's not working.
Don't do this. Mixing different graphical toolkits (for example Swing/AWT and JavaFX) is an advanced topic. In general, if you are writing a JavaFX application, avoid importing anything from the java.awt namespace and the javax.swing namespace. You only really need to use those if you have a large, existing Swing based application or framework that you need to inter-operate with your JavaFX application. In this case, you don't have that situation.
I also saw the code for it in Ensembles(that dragging the ball-window in "advanced stage", that's what I need to do, drag my undecorated JavaFX stage), but it also doesn't work.
I tried the Ensemble Advanced Stage sample and dragging that stage around worked for me.
Another sample for dragging an undecorated stage in JavaFX is in the answer to How to draw a clock with JavaFX 2? which has associated sample code. The method used to make the undecorated stage draggable for the clock sample is:
/** makes a stage draggable using a given node */
public static void makeDraggable(final Stage stage, final Node byNode) {
final Delta dragDelta = new Delta();
byNode.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
// record a delta distance for the drag and drop operation.
dragDelta.x = stage.getX() - mouseEvent.getScreenX();
dragDelta.y = stage.getY() - mouseEvent.getScreenY();
byNode.setCursor(Cursor.MOVE);
}
});
byNode.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
byNode.setCursor(Cursor.HAND);
}
});
byNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
stage.setX(mouseEvent.getScreenX() + dragDelta.x);
stage.setY(mouseEvent.getScreenY() + dragDelta.y);
}
});
byNode.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
byNode.setCursor(Cursor.HAND);
}
}
});
byNode.setOnMouseExited(new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent mouseEvent) {
if (!mouseEvent.isPrimaryButtonDown()) {
byNode.setCursor(Cursor.DEFAULT);
}
}
});
}
I am using FXML with controller, and I guess that's the main problem. Should I switch back to the single-file simple JavaFX? I know FXML is better for laying out the UI, but I can't get many of such codes to work.
Lack of understanding and familiarity with the underlying JavaFX APIs is probably your main problem rather than use of FXML. However the additional complexity fxml implies together with the lighter documentation and samples for it on the web may be contributing to your hardships. If use of FXML is making it difficult for you to understand how to get some JavaFX functions to work, I advise to stop using FXML for now. Code the logic by hand using the Java APIs and refer to the Oracle JavaFX tutorials and the Ensemble sample code when you encounter things which are difficult for you.
Once you are comfortable coding directly to the JavaFX API, switch back to using FXML for larger projects which contain many GUI elements. The FXML elements and attributes themselves are built almost completely upon reflection of the standard JavaFX APIs. So, if you understand the core JavaFX APIs, you also understand almost everything about FXML.
Please do not post follow up comments to this answer (as this answer is long enough as it is). If you have new questions, create a new question (one question per question).
What about using Robot for that purpose ?
http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Robot.html
Using Robots, it is different from posting event to AWT event queue. Events are generated in the native event queue. Actually, with Robot.mouseMove you will not only set mouse position and not only get position.
For getting mouse position, you may stick to MouseInfo
import java.awt.MouseInfo;
// get the mouse's position
Point p = MouseInfo.getPointerInfo().getLocation();
It's not working: are you with Mac ? Which is your version of JavaFX ? seems to be issues corrected for FX8. For mac only, you may use
com.sun.glass.ui.Robot robot =
com.sun.glass.ui.Application.GetApplication().createRobot();
// getPosition of the mouse in Mac
int x = robot.getMouseX();
int y = robot.getMouseY();
JavaFx 8 WindowEvent doesn't provide the (x,y) location of the mouse, unfortunately. I solved this (and it works fine) by using the AWT MouseInfo like this:
Tooltip t = new Tooltip();
Tooltip.install(yournode, t);
t.setOnShowing(ev -> {// called just prior to being shown
Point mouse = java.awt.MouseInfo.getPointerInfo().getLocation();
Point2D local = yournode.screenToLocal(mouse.x, mouse.y);
// my app-specific code to get the chart's yaxis value
// then set the text as I want
double pitch = yaxis.getValueForDisplay(local.getY()).doubleValue();
double freq = AudioUtil.pitch2frequency(pitch);
t.setText(String.format("Pitch %.1f: %.1f Hz %.1f samples", pitch, freq, audio.rate / freq));
});

Resources