JavaFX Dragboard setContent interfering with setOnMouseDragged? - drag-and-drop

I would like to use drag and drop in JavaFX and have a feature where you can visually see the item being dragged. I've implemented what I thought would be a working solution, but there seems to be an issue with the API.
According to the API startDragAndDrop(TransferMode...) MUST be initialized inside setOnDragDetected. This is where I use a Dragboard to store content I'd like to transfer to another node.
EDIT: This appears to have something to do with the TrasferMode. If I use TransferMode.NONE there is no issue, but use of COPY, ANY, LINK always results in this problem.
But calling dragBoard.setContent(some clipboard content) only allows very small increments of movement with the mouse (a max of 4 pixels in any direction!). Removing this line of code, I can then drag the item and see it being dragged anywhere, but of course, I then can't store clipboard content.
The problem I see is that setOnMouseDragged(..) gets called before setOnDragDetected! It doesn't make much sense why setOnMouseDragged gets run before setOnDragDetected...
Is there something obvious to you in my code that's maybe causing a problem? I'd simply like to be able to see the imgView moving when dragging and be able to drop it on a target as usual, with the clipboard content.
EDIT 2: Updated code below to reflect using only Drag events, rather than Drag and Mouse events. Using both caused issues. The problem that still remains is that I'm unable to drop on a target, since using setOnDragOver makes the dragged node always right below the cursor.
protected ImageView initImageView(Image img){
final Pane ldzPane = GameBoard.getInstance().getLDZpane();
final ObjectProperty<Point2D> dragAnchor = new SimpleObjectProperty<>();
final ImageView imgView = new ImageView(img);
final DoubleProperty initX = new SimpleDoubleProperty();
final DoubleProperty initY = new SimpleDoubleProperty();
final DoubleProperty dragX = new SimpleDoubleProperty();
final DoubleProperty dragY = new SimpleDoubleProperty();
final DoubleProperty newXPosition = new SimpleDoubleProperty();
final DoubleProperty newYPosition = new SimpleDoubleProperty();
final int buffer = 3;
imgView.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
initX.set(imgView.getTranslateX());
initY.set(imgView.getTranslateY());
dragAnchor.set(new Point2D(event.getSceneX(), event.getSceneY()));
ClipboardContent content = new ClipboardContent();
content.putString(RHSIconizedToken.this.tokenLookupInfo());
Dragboard db = imgView.startDragAndDrop(TransferMode.ANY);
db.setContent(content);
event.consume();
}
});
imgView.setOnDragOver(new EventHandler<DragEvent>(){
#Override
public void handle(DragEvent event) {
imgView.toFront();
dragX.set(event.getSceneX() - dragAnchor.get().getX());
dragY.set(event.getSceneY() - dragAnchor.get().getY());
imgView.setOpacity(0.5);
newXPosition.set(initX.get() + dragX.get());
newYPosition.set(initY.get() + dragY.get());
//if( (Math.abs((newXPosition.get() - ldzPane.getWidth())) <= ldzPane.getWidth() + startX + buffer) &&
// ((newXPosition.get() + startX + imgView.getImage().getWidth()+ buffer)<= ldzPane.getWidth()))
imgView.setTranslateX(newXPosition.get());
//if( (Math.abs((newYPosition.get() - ldzPane.getHeight())) <= ldzPane.getHeight() + startY + buffer) &&
// ((newYPosition.get() + startY + imgView.getImage().getHeight()+ buffer)<= ldzPane.getHeight()))
imgView.setTranslateY(newYPosition.get());
event.consume();
}
});
imgView.setOnDragDone(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
LinkedList<RHSIconizedToken> iTokens = GameBoard.getInstance().getTokenBayItokens();
if (event.getTransferMode() == TransferMode.MOVE) {
RHSIconizedToken element = iTokens.remove(index);
iTokens.add(index, new RHSIconizedToken(element.getImage(), new SourceToken("removed", "removed"), index));
imgView.setVisible(false);
GameBoard theGameBoard = GameBoard.getInstance();
GUI theGUI = GUI.getInstance();
//was this the last one removed from the rhs?
//if so we need to signal the CompileButton to be turned on!
if(theGameBoard.isRHSempty())
theGUI.enableCompileButton();
else
theGUI.disableCompileButton();
}
event.consume();
}
});
imgView.setOnMouseEntered(new EventHandler <MouseEvent>() {
public void handle(MouseEvent event) {
imgView.setEffect(new Glow(0.5));
event.consume();
}
});
imgView.setOnMouseExited(new EventHandler <MouseEvent>() {
public void handle(MouseEvent event) {
imgView.setEffect(new Glow(0.0));
imgView.setOpacity(1);
event.consume();
}
});
return imgView;
}

Java 8 is scheduled to ship with more support for visual drag and drop. DragBoard's setDragView (Image, XOffset, YOffset) method works great, and is available with the Java 8 beta.
imgView.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
ClipboardContent content = new ClipboardContent();
content.putString(RHSIconizedToken.this.tokenLookupInfo());
Dragboard db = imgView.startDragAndDrop(TransferMode.ANY);
db.setDragView(image, 7, 7);
db.setContent(content);
event.consume();
}
});

I think this would help you:
DraggablePanelsExample.java
I usedd this for my Panels too, and it works for ImageView like a charm.
EDIT:
You are combining this false! You can not combine DragDetected with MouseDragged.
If you start dragging in JavaFX, the mouseevents does not get fired anymore.
If you want a Drag-Board-String then simply save you String in you class.
ps: replace DragDone with MouseReleased

Related

KeyEvent on Dialog not consumed when closing in JavaFX

I have a requirement to navigate a table when the user hits the ENTER key. For this I have created an event filter similar to:
private EventHandler<KeyEvent> keyReleasedFilter = event -> {
if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
previousPosition = table.getFocusModel().getFocusedCell();
//do my navigation
}
}
I have run into an issue where JavaFX Modal Dialogs used during navigation of the table to indicate an error, cause issues with this filter. If the user closed the dialog with the ENTER key, that event is trapped by my event filter on the parent stage. I am not sure how to prevent that. It is causing inconsistent navigation.
Here is a simple application that demonstrates the behavior:
public void start(Stage primaryStage) {
final Alert d = new Alert(Alert.AlertType.ERROR);
d.initModality(Modality.WINDOW_MODAL);
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.addEventFilter(KeyEvent.KEY_RELEASED, event -> {
if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
d.showAndWait();
}
});
Scene scene = new Scene(new StackPane(btn), 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
I have noticed that the dialog is closed with the KEY_PRESSED event, and will not capture the KEY_RELEASED event.
I have tried adding an EVENT FILTER to the dialog (Button/DialogPane/Scene and even Stage) - none intercept the KEY_RELEASED event.
Thanks.
Unless there is another reason to use the KEY_RELEASED event, then I would recommend switching to triggering on KEY_PRESSED for navigation as well and switch your EventFilter to an EventHandler. The example below will allow you to toggle the Alert on and off. When it's on, you'll notice that the button text doesn't change. When it's off, the button text will change. Take a look at how JavaFX constructs Event chains here if you haven't already.
boolean error = false;
int i = 0;
#Override
public void start(Stage primaryStage)
{
final Alert d = new Alert(Alert.AlertType.ERROR);
d.initModality(Modality.WINDOW_MODAL);
Button err = new Button();
err.setText("Error off");
err.addEventHandler(ActionEvent.ACTION, t ->
{
error = !error;
if (error)
err.setText("Error on");
else
err.setText("Error off");
});
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.addEventHandler(KeyEvent.KEY_PRESSED, event ->
{
if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
if (error)
{
d.showAndWait();
}
else
{
i++;
btn.setText(String.valueOf(i));
}
}
});
Scene scene = new Scene(new VBox(btn, err), 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
So I have a hack that works - I really don't like it, so I am hoping that there is a better solution (a clean one) to solve this issue....
Basically, right before I open my dialog, I set a boolean so I know it's open. Then in my event filter, kick out if that is set to true.
public class EventTester extends Application{
public static void main(String[] args){
launch(args);
}
private boolean modalWasShowing = false;
#Override
public void start(Stage primaryStage) {
final Alert d = new Alert(Alert.AlertType.ERROR);
d.initModality(Modality.WINDOW_MODAL);
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.addEventFilter(KeyEvent.KEY_RELEASED, event -> {
if(modalWasShowing){
modalWasShowing=false;
return;
}
if ((event.getCode() == KeyCode.ENTER || event.getCode() == KeyCode.TAB)) {
modalWasShowing = true;
d.showAndWait();
}
});
Scene scene = new Scene(new StackPane(btn), 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
Please let me know if you know of a better way to handle this.

How to change or override the tooltip in JavaFX ColorPicker

I am using JavaFX ColorPicker in my application. As per my requirements, I have mapped the default colors on the color picker to a number. I want this number to be displayed as tooltip on hover over the color instead of hex value of the color. How can I achieve this?
//Part of Code
public void handleNodes(Circle circularNode) {
final Delta offset = new Delta();
circularNode.setOnMouseEntered(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
((Circle)(event.getSource())).setCursor(Cursor.HAND);
}
});
circularNode.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
if(event.getButton().equals(MouseButton.SECONDARY)) {
System.out.println("Right click");
Circle parent = ((Circle)(event.getSource()));
final ContextMenu contextMenu = new ContextMenu();
MenuItem editLabel = new MenuItem("Edit Label");
editLabel.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Edit Label");
final ColorPicker colorPicker = new ColorPicker();
colorPicker.setStyle("-fx-border-radius: 10 10 10 10;"
+ "-fx-background-radius: 10 10 10 10;");
colorPicker.setValue((Color) parent.getFill());
colorPicker.showingProperty().addListener((obs,b,b1)->{
if(b1){
PopupWindow popupWindow = getPopupWindow();
javafx.scene.Node popup = popupWindow.getScene().getRoot().getChildrenUnmodifiable().get(0);
popup.lookupAll(".color-rect").stream()
.forEach(rect->{
Color c = (Color)((Rectangle)rect).getFill();
Tooltip.install(rect.getParent(), new Tooltip("Custom tip for "+c.toString()));
});
}
});
panelMain.getChildren().add(colorPicker);
}
});
This is really a hacky answer.
The first problem: you have to find the popup node on the scene once it shows up. But you won't... since its not in the same window!
Having a deep look at how ScenicView does it, the trick is getting the list of windows at that moment, but using a deprectated method:
private PopupWindow getPopupWindow() {
#SuppressWarnings("deprecation") final Iterator<Window> windows = Window.impl_getWindows();
while (windows.hasNext()) {
final Window window = windows.next();
if (window instanceof PopupWindow) {
return (PopupWindow)window;
}
}
return null;
}
Once you have the popup window, we can now check for all the Rectangle nodes using lookupAll and the CSS selector color-rect, to get their color, and install the tooltip over its parent container:
#Override
public void start(Stage primaryStage) {
ColorPicker picker = new ColorPicker();
StackPane root = new StackPane(picker);
Scene scene = new Scene(root, 500, 400);
primaryStage.setScene(scene);
primaryStage.show();
picker.showingProperty().addListener((obs,b,b1)->{
if(b1){
PopupWindow popupWindow = getPopupWindow();
Node popup = popupWindow.getScene().getRoot().getChildrenUnmodifiable().get(0);
popup.lookupAll(".color-rect").stream()
.forEach(rect->{
Color c = (Color)((Rectangle)rect).getFill();
Tooltip.install(rect.getParent(), new Tooltip("Custom tip for "+c.toString()));
});
}
});
}
This is what it looks like:
Based on the code posted by the OP after my first answer, and due to the substancial changes in the problem addressed, I'm adding a new answer that covers both situations:
The ColorPicker is embedded in the main scene, as a regular node
The ColorPicker is embedded in a ContextMenu
In the second situation, the proposed solution for the first one is no longer valid, since the window found will be the one with the context menu.
A task is required to keep looking for windows until the one with the ComboBoxPopupControl is found.
This is a full runnable example:
public class ColorPickerFinder extends Application {
ExecutorService findWindowExecutor = createExecutor("FindWindow");
#Override
public void start(Stage primaryStage) {
AnchorPane panCircles = new AnchorPane();
Scene scene = new Scene(panCircles, 400, 400);
final Random random = new Random();
IntStream.range(0,5).boxed().forEach(i->{
final Circle circle= new Circle(20+random.nextInt(80),
Color.rgb(random.nextInt(255),random.nextInt(255),random.nextInt(255)));
circle.setTranslateX(100+random.nextInt(200));
circle.setTranslateY(100+random.nextInt(200));
panCircles.getChildren().add(circle);
});
panCircles.setPrefSize(400, 400);
ColorPicker colorPicker = new ColorPicker();
panCircles.getChildren().add(colorPicker);
primaryStage.setScene(scene);
primaryStage.show();
// We add listeners AFTER showing the stage, as we are looking for nodes
// by css selectors, these will be available only after the stage is shown
colorPicker.showingProperty().addListener((obs,b,b1)->{
if(b1){
// No need for task in this case
getPopupWindow();
}
});
panCircles.getChildren().stream()
.filter(c->c instanceof Circle)
.map(c->(Circle)c)
.forEach(circle->{
circle.setOnMouseClicked(e->{
if(e.getButton().equals(MouseButton.SECONDARY)){
// We need a task, since the first window found is the ContextMenu one
findWindowExecutor.execute(new WindowTask());
final ColorPicker picker = new ColorPicker();
picker.setStyle("-fx-border-radius: 10 10 10 10;"
+ "-fx-background-radius: 10 10 10 10;");
picker.setValue((Color)(circle.getFill()));
picker.valueProperty().addListener((obs,c0,c1)->circle.setFill(c1));
final ContextMenu contextMenu = new ContextMenu();
MenuItem editLabel = new MenuItem();
contextMenu.getItems().add(editLabel);
editLabel.setGraphic(picker);
contextMenu.show(panCircles,e.getScreenX(),e.getScreenY());
}
});
});
}
private PopupWindow getPopupWindow() {
#SuppressWarnings("deprecation")
final Iterator<Window> windows = Window.impl_getWindows();
while (windows.hasNext()) {
final Window window = windows.next();
if (window instanceof PopupWindow) {
if(window.getScene()!=null && window.getScene().getRoot()!=null){
Parent root = window.getScene().getRoot();
if(root.getChildrenUnmodifiable().size()>0){
Node popup = root.getChildrenUnmodifiable().get(0);
if(popup.lookup(".combo-box-popup")!=null){
// only process ComboBoxPopupControl
Platform.runLater(()->{
popup.lookupAll(".color-rect").stream()
.forEach(rect->{
Color c = (Color)((Rectangle)rect).getFill();
Tooltip.install(rect.getParent(),
new Tooltip("Custom tip for "+c.toString()));
});
});
return (PopupWindow)window;
}
}
}
return null;
}
}
return null;
}
private class WindowTask extends Task<Void> {
#Override
protected Void call() throws Exception {
boolean found=false;
while(!found){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
found=(getPopupWindow()!=null);
}
return null;
}
}
private ExecutorService createExecutor(final String name) {
ThreadFactory factory = r -> {
Thread t = new Thread(r);
t.setName(name);
t.setDaemon(true);
return t;
};
return Executors.newSingleThreadExecutor(factory);
}
public static void main(String[] args) {
launch(args);
}
}
This will be the result after right clicking on a circle, and clicking on the color picker:

Why is a MenuItem not responding?

There is a ContextMenu which has two options and when the second option (item2 in the code) is pressed with the right mousebutton I want it to print out some text so I know I did actually activate it. Up till now nothing happens when I click on the second mousebutton.
I haven't had much experience yet with Eventhandlers so my apologies if I made a noobish mistake.
private void maakContextMenu() {
menu = new ContextMenu();
MenuItem item = new MenuItem("Kleur Assen");
MenuItem item2 = new MenuItem("tweede optie");
final LissajousCanvas canvas = this;
item.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
new KiesKleur(canvas).show();
}
});
item2.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent t) {
System.out.println("in the loop");
if(t.getSource()==MouseButton.SECONDARY){
System.out.println("in too deep");
}
new KiesKleur(canvas).show();
}
});
menu.getItems().addAll(item, item2);
}
A MenuItem is not actually a Node, so it's not part of the scene graph in the way that Nodes are. So I'm not really sure if this is a bug or not; I think it probably only implements EventTarget so it can specifically generate ActionEvents. You'll have noticed there is no setOnMouseClicked(...) method available.
Here's a workaround. I'm not sure why it only works with MOUSE_PRESSED and not with MOUSE_CLICKED, but it's likely something to do with the default mouse event handling that generates the action events:
private void maakContextMenu() {
menu = new ContextMenu();
MenuItem item = new MenuItem("", new Label("Kleur Assen"));
Label menuItem2Label = new Label("tweede optie");
MenuItem item2 = new MenuItem("", menuItem2Label);
final LissajousCanvas canvas = this;
item.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
new KiesKleur(canvas).show();
}
});
menuItem2Label.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent t) {
System.out.println("in the loop");
if(t.getButton()==MouseButton.SECONDARY){
System.out.println("in too deep");
}
new KiesKleur(canvas).show();
}
});
menu.getItems().addAll(item, item2);
}

CheckBox clickhandler code doesn't work...there is no compile time error...look at the snap shot

CheckBox clickhandler code doesn't work...there is no compile time error...look at the snap shotlook at the snap shot in which there is no image in popup...i have highlighted it
cb1.addClickHandler(new ClickHandler(){
public void onClick(ClickEvent event) {
System.out.println("hello2");
boolean checked = ((CheckBox) event.getSource()).getValue();
if (checked) {
System.out.println("hello3");
int left = toothWidget.getToothImage().getAbsoluteLeft();
int top = toothWidget.getVPanel().getAbsoluteTop();//toothWidget.getToothImage().getAbsoluteTop();
Image im = new Image();
im.setUrl(GWT.getHostPageBaseURL()+"/images/"+menuItem.getImg());
System.out.println(GWT.getHostPageBaseURL()+"/images/"+menuItem.getImg());
int offx = left;
int offy = top;
final PopupPanel popup1 = new PopupPanel(true);
popup1.setStylePrimaryName("transparent");
popup1.setPopupPosition(Math.max(offx, 0),Math.max(offy, 0));
//popup.add(im);
ToothWidget wgt = new ToothWidget(toothWidget.getToothNumber(),menuItem.getImg(), toothWidget.getTeeth());
toothWidget.getTeeth().getMap().get(toothWidget.getToothNumber()).put(menuItem.getName(), wgt);
wgt.setMenu(toothWidget.getMenu());
wgt.setPanel(popup1);
popup1.add(wgt);
popup1.show();
}
else{
ToothWidget wgt = toothWidget.getTeeth().getMap().get(toothWidget.getToothNumber()).remove(menuItem.getName());
wgt.getPanel().hide();
}
}
});
WEB Dev 101 - Always use FireFox/FireBug's Network/Image console to check for URL mismatch . You will be seeing 404 errors for the Image path.
Where is YOUR Image located?
1) public folder parallel to your gwt.xml
If you have images folder in your gwt module's public folder you need to use im.setUrl(GWT.getModuleBaseURL()+"/images/"+menuItem.getImg());
or
2) webapps folder
If you have images in deployed into your war/images you need to use
im.setUrl(GWT.getHostPageBaseURL()+"/images/"+menuItem.getImg());
If the above does not solve the issue then you may not have the image at all under "images"
try this. It is better to use the ValueChangeHandler that works for sure and is used for changing values.
CheckBox cb1 = new CheckBox();
cb1.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
#Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
Boolean isChecked = event.getValue();
if (isChecked) {
System.out.println("hello3");
int left = toothWidget.getToothImage().getAbsoluteLeft();
int top = toothWidget.getVPanel().getAbsoluteTop();//toothWidget.getToothImage().getAbsoluteTop();
Image im = new Image();
im.setUrl(GWT.getHostPageBaseURL()+"/images/"+menuItem.getImg());
System.out.println(GWT.getHostPageBaseURL()+"/images/"+menuItem.getImg());
int offx = left;
int offy = top;
final PopupPanel popup1 = new PopupPanel(true);
popup1.setStylePrimaryName("transparent");
popup1.setPopupPosition(Math.max(offx, 0),Math.max(offy, 0));
//popup.add(im);
ToothWidget wgt = new ToothWidget(toothWidget.getToothNumber(),menuItem.getImg(), toothWidget.getTeeth());
toothWidget.getTeeth().getMap().get(toothWidget.getToothNumber()).put(menuItem.getName(), wgt);
wgt.setMenu(toothWidget.getMenu());
wgt.setPanel(popup1);
popup1.add(wgt);
popup1.show();
}
else
{
ToothWidget wgt = toothWidget.getTeeth().getMap().get(toothWidget.getToothNumber()).remove(menuItem.getName());
wgt.getPanel().hide();
}
}
});
}
Plus the images/ folder must be inside the war forlder (though i think you already know that having developed this site)
Also check what menuItem.getImg() returns. It might return only the filename but not the extension or something else entirely.

GWT FlexTable - drag selection how?

I am trying to get a proper method for days to select multiple cells in a flextable's column.
So far i only managed to do it with clicks which works well, but a drag selection would be much better. I have been reading docs and searching, but all the stuff i found was based on deprecated code. I use GWT 2.0 .
I know i need some event handler which would run when drag selection mouse gesture occurs, and that handler needs to know the cell's index where the selection start and of course the cell's index where the selection ends.
Any advice || code would be much appreciated.
This needs to be improved but it should give you the basic idea. First you need to create a CustomTable that listens to MouseEvents. You can do this by extending composite to wrap a focuspanel and a flextable as such :
public class CustomTable extends Composite implements MouseDownHandler, MouseMoveHandler, MouseUpHandler{
List<CellWidget> widgets = new ArrayList<CellWidget>();
FlexTable table = new FlexTable();
FocusPanel focusPanel = new FocusPanel();
boolean selecting= false;
Point selectStart,selectEnd;
public CustomTable(){
focusPanel.setWidget(table);
focusPanel.addMouseDownHandler(this);
focusPanel.addMouseMoveHandler(this);
focusPanel.addMouseUpHandler(this);
initWidget(focusPanel);
}
public void setWidget(int row, int column, CellWidget widget){
widgets.add(widget);
table.setWidget(row, column, widget);
}
#Override
public void onMouseUp(MouseUpEvent event) {
event.preventDefault();
if (selecting){
selecting=false;
DOM.releaseCapture(this.getElement());
selectEnd = new Point(event.getClientX(),event.getClientY());
for (CellWidget widget : widgets){
if (widget.isIn(selectStart,selectEnd))
widget.say();
}
selectStart = selectEnd = null;
}
}
#Override
public void onMouseMove(MouseMoveEvent event) {
event.preventDefault();
if (selecting){
//do some fancy layout
}
}
#Override
public void onMouseDown(MouseDownEvent event) {
event.preventDefault();
selecting = true;
DOM.setCapture(this.getElement());
selectStart = new Point(event.getClientX(),event.getClientY());
}
}
Next you define a CellWidget which basically encapsulates what you would like to add to your cells. When added to DOM, CellWidget calculates and stores its position later to determine if it is in the selected area :
public class CellWidget extends Composite{
Widget content;
Point topLeft,topRight,bottomLeft,bottomRight;
public CellWidget(Widget w){
this.content = w;
initWidget(w);
}
#Override
protected void onLoad() {
topLeft = new Point(getAbsoluteLeft(),getAbsoluteTop());
topRight = new Point(getAbsoluteLeft()+getOffsetWidth(),getAbsoluteTop());
bottomLeft = new Point(getAbsoluteLeft(),getAbsoluteTop()+getOffsetHeight());
bottomRight = new Point(getAbsoluteLeft()+getOffsetWidth(),getAbsoluteTop()+getOffsetHeight());
}
public void say(){
Window.alert(content + " is selected!");
}
public boolean isIn(Point start, Point end){
if (topLeft.isBetween(start, end) || topRight.isBetween(start, end)
|| bottomLeft.isBetween(start, end) || bottomRight.isBetween(start, end))
return true;
else
return false;
}
}
A simple point implementation to make things easier :
public class Point {
int x,y;
public Point(int x,int y){
this.x=x;
this.y=y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public String toString() {
return x+","+y;
}
public boolean isBetween(Point p1,Point p2){
if (p1.getX() < x && p2.getX() > x && p1.getY() < y && p2.getY() > y)
return true;
return false;
}
}
Finally at your EntryPoint module you wrap things up by :
public void onModuleLoad() {
RootPanel rootPanel = RootPanel.get();
CustomTable table = new CustomTable();
table.setWidget(0, 0, new CellWidget(new Label("hello 0,0")));
table.setWidget(0, 1, new CellWidget(new Label("hello 0,1")));
table.setWidget(1, 0, new CellWidget(new Label("hello 1,0")));
table.setWidget(1, 1, new CellWidget(new Label("hello 1,1")));
rootPanel.add(table);
}
I know that the actual logic to determine if the widgets fall within the selected area is incomplete and needs to be improved but i think this solution is clear enough to give the basic idea. Cheers