Multi select in tableView javafx - javafx

I want to multi select row in my TableView. The problem is that my application is a multitouch application, I have not a keyboard, so not a CTRL key.
I have a code follow :
tableViewArticle.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
But I want to select a lot of row only with a mouse click. For exemple, when I selected one row, the row change in blue, and if after I select an other row, I have two rows in blue.

You could use a custom event filter for the TableView that handles the selection, if a click happened on a table row:
tableViewArticle.addEventFilter(MouseEvent.MOUSE_PRESSED, evt -> {
Node node = evt.getPickResult().getIntersectedNode();
// go up from the target node until a row is found or it's clear the
// target node wasn't a node.
while (node != null && node != tableViewArticle && !(node instanceof TableRow)) {
node = node.getParent();
}
// if is part of a row or the row,
// handle event instead of using standard handling
if (node instanceof TableRow) {
// prevent further handling
evt.consume();
TableRow row = (TableRow) node;
TableView tv = row.getTableView();
// focus the tableview
tv.requestFocus();
if (!row.isEmpty()) {
// handle selection for non-empty nodes
int index = row.getIndex();
if (row.isSelected()) {
tv.getSelectionModel().clearSelection(index);
} else {
tv.getSelectionModel().select(index);
}
}
}
});
If you want to handle touch events differently to mouse events, you can also use MouseEvent.isSynthesized to check, if the event is a touch event.

Related

Change css for a new row added in TableView Javafx

I'm sorry for mistake I'm french.
So I have a tableView empty. I have a button "Add" when on click added row in a tableView. And when I select an row in my tableView, a new button "Cancel" show.
And when I click on a button "Cancel", the row's css change on my row selected (added a class css ".cancel").
The problem is that I click on button "Cancel", and after I click in the button "Add", the css ".cancel" is applicated at an other row while I don't clicked in the button "Add".
I think that there is a problem in index row.
In my method initialize :
articleTable.setRowFactory(param -> new TableRow<LigneTicket>() {
#Override
protected void updateItem(LigneTicket paramT, boolean empty) {
super.updateItem(paramT, empty);
if (!isEmpty() && paramT != null && paramT.getArticle().isArticleCanceled()) {
getStyleClass().add("cancel");
}
}
});
my code on button "Cancel" :
public void cancelLigneTicket() {
int indexSelected = articleTable.getSelectionModel().getSelectedIndex();
articleTable.getItems().get(indexSelected).getArticle().setArticleAnnuler(true);
articleTable.getSelectionModel().clearSelection();
List<LigneTicket> items = new ArrayList<>(articleTable.getItems());
articleTable.getItems().setAll(items);
buttonAnnulArt.setVisible(false);
Help !!
Thanks.
TableRows are used to display the table items. That doesn't mean however, that it will be used with only one item.
This can result in the following sequence of events for a row r:
The item of r is updated to a canceled item and thus the cancel CSS class is added.
The item of r is updated to a non-canceled item, but the cancel CSS class is not removed.
You need to remove the class again. Furthermore with your code the style class could be added multiple times leading to unnecessary memory consumption.
boolean canceled = !empty && paramT != null && paramT.getArticle().isArticleCanceled());
if (canceled) {
if (!getStyleClass().contains("cancel"))
getStyleClass().add("cancel");
} else {
getStyleClass().remove("cancel");
}
or using PseudoClass:
private static final PseudoClass CANCELED = PseudoClass.getPseudoClass("cancel");
...
pseudoClassStateChanged(CANCELED, !empty && paramT != null && paramT.getArticle().isArticleCanceled());
Furthermore you should prefer the TableView.refresh (available in JavaFX >= 8u60) method to refresh the cell items instead of copying the list and setting the items.

Flex multiple selection drop down list with scrolling

I'm working in flex and I made a custom drop down where there are check boxes to allow the user to select multiple options. I used this template.
However this does not have scrolling because if you allow scrolling for some reason the checkboxes start to mess up. For instance if you have options 1 to 8 and only 1 to 5 are shown. You select option 1 and then scroll down to select option 7. When you scroll up the checkboxes start to switch around like option 3 all of a sudden is showing selected. Keep scrolling up and down and the checkbox selection just changes on it's own. I think this is a rendering issue and the actual selection data isn't changed at all (it knows only option 1 and option 7 were selected). Any ideas on how to fix this?
public function onOpen(event:DropDownEvent):void
{//load the checkboxes and set the mouse tracker
activateAllCheckBoxes();
this.scroller.verticalScrollBar.addEventListener(Event.CHANGE, list_verticalScrollBar_change);
callLater(observeMouse);
}
private function list_verticalScrollBar_change(evt:Event):void
{
//currentlySelectedCheckBoxes = selectedCheckboxes;
UpdateCheckBoxesWhenScrolling();
selectedIndex = -1;
}
protected function UpdateCheckBoxesWhenScrolling():void
{
for (var c:int = 0; c < dataGroup.numElements; c++) {
var obj:DropDownCheckBox = dataGroup.getElementAt(c) as DropDownCheckBox;
if(obj!=null)
{
var judgDebtorFromCheckBox:JudgDebtor = (obj.data) as JudgDebtor;
if(FindInCurrentList(judgDebtorFromCheckBox.JudgmentDebtorId)>0)
{
obj.checkbox.selected = true;
}
else
{
obj.checkbox.selected = false;
}
}
}
}
private function FindInCurrentList(ID:int):int
{
for(var i:int=0;i<currentlySelectedCheckBoxes.length;i++)
{
var JD:JudgDebtor = currentlySelectedCheckBoxes.getItemAt(i) as JudgDebtor;
if(JD.JudgmentDebtorId == ID)
return 1;
}
return -1;
}
So above code I register a scroll event listener on the drop down. It will update the drop down entries which has a check box and it uses an array collection called: currentlySelectedCheckBoxes. I debug the UpdateCheckBoxesWhenScrolling function and it's working fine, in other words it will check off the ones selected but for some reason it still is showing the wrong results for instance 11 entries in the list and only the second one is selected I scroll down and I can't see the the second entry but all of a sudden the last entry is showing that it's checked off.
This happens because the drop down list reuses the renderers when you scroll. For example if you have checked 1st item and scroll, the renderer for that is reused to display the item that becomes visible when you scroll. So the last item shows as checked. To avoid messing up the selection, you will have to do the following in the renderer that you are using
override public function set data(value:Object):void
{
super.data = value;
//inspect the property which indicates whether to select the checkbox or not
//and set the value of selected property accordingly
}
Hope this helps

No events when drag target is removed from the scenegraph while dragging

JavaFX scene has an object of class inherited from the Region. This object has a handler of MOUSE_DRAGGED event. When this handler is called, all object's child nodes are removed and new child nodes are added. The problem is when all children are removed from my object, it doesn't receive any events anymore, because target of MOUSE_DRAGGED event is removed child node. How to solve it?
I cannot use setMouseTransparent method, because some elements inside my object have mouse event handlers.
Ok, perhaps I got the question:
A region has many children. If the user left-clicks and dragges on these children, they will be modified or even removed. As the Mouse-Drag event is 'locked' to the first child where the drag started, no other child will receive further events if the mouse is dragged over some of the other children.
You might benefit from the fact, that the MouseDrag event is passed to the parent region after removing the child. So it is possible to register an onMouseDragged handler on th eparent regon receiving that event. Now the handler is able to 'pick' any childs below mouse for further actions using event.getPickEvent():
void mouseDragPop(Pane region) {
region.setOnMouseDragged(e -> {
Node node = e.getPickResult().getIntersectedNode();
if (node instanceof Circle) {
region.getChildren().remove(node);
}
});
for (int i = 1; i < 10; i++) {
final int n = i;
Circle circle = new Circle(20);
circle.setTranslateX(0);
circle.setTranslateY(0);
circle.setFill(Color.rgb(180, 200, 170));
circle.setLayoutX(System.nanoTime()/1000 % 200);
circle.setLayoutY(System.nanoTime()/3000 % 100);
region.getChildren().add(circle);
circle.setOnMouseDragged(e -> {
region.getChildren().remove(circle);
e.consume();
});
}
}
Now you are able to click and 'pop' all circle on your mouse-drag way...

Cursor moves to the start location on selection in spark combobox?

I have a . I provide arraylist as its data provider. my question is why moves to the ing location in when I select any item using enter key. Also when I press space from keyboard, again moves to ing location. How can I fix this? Thanks
protected function onInputKeyDown(e:KeyboardEvent):void
{
if(e.keyCode == 13)
{
AddPath(cb.textInput.text);
cb.dataProvider = recentList;
}
}
here recentList is a Bindable ArrayList. Every Time when I enter anything in ComboBox and press Enter, The cursor moves to the beginning in the Text Area of ComboBox. AddPath function simply adds the new data to the recentList.
When you set cb.dataProvider = recentList; you are essentially assigning a new pointer which overrides the previous list and resets the cursor.
You should be able to create a variable containing the selected item and manually set the ComboBox to that item on click/enter after you carry out the cb.dataProvider = recentList;
protected function onInputKeyDown(e:KeyboardEvent):void
{
if(e.keyCode == 13)
{
var selectedItem:String = cb.selectedItem
AddPath(cb.textInput.text);
cb.dataProvider = recentList;
cb.selectedItem(selectedItem);
}
}
Apologies if the code isn't perfect, but the theory should be right.

Flexlib scheduleViewer.. how to handle clicks on items

I'm trying to use a flexlib schedule viewer in my application.
I want to have it so that when I click on a scheduled event, it calls a function in my main app (that will allow me to edit the event). But there doesn't seem to be any specific function for anything like this built into the class ie no event dispatched when I click on an event.
I can use the 'click' function to detect that the item has been clicked on.. and have tried something like this:
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
<code:ScheduleViewer id="exerciseSeries" click="exerciseClickHandler(event)" />
This method isn't very reliable because if it only works the first time.. once an item is selected, it stays selected so all following clicks on the item fulfills the condition.
Is there any way to determine whether an event was being clicked on?
Or do I have to extend the component and add some sort of clickEvent when an event is clicked on.
Since exerciseClickHandler is firing up when you click on the component, wouldn't this work?
Instead of
private function exerciseClickHandler(event:MouseEvent):void{
if (exerciseSeries.selectedItem != null){
//code
}
}
write
private function exerciseClickHandler(event:MouseEvent):void{
switch (exerciseSeries.selectedItem)
{
//code
case xy:
break;
}
}
or
private function exerciseClickHandler(event:MouseEvent):void{
//do something with exerciseSeries.selectedItem
}
What I mean is that you wrote that everything stops after the first element is clicked. And according to the code you provided it has to stop, beacuse after the first click exerciseSeries.selectedItem won't be null anymore, since it's selected. So remove the conditional you wrote and use the instance.
I'd suggest you set up a ChangeWatcher to keep an eye on the selectedItem (or selectedItems if you are going to allow multiple selection at some point). Example:
protected exerciseSeriesCreationCompleteHandler(event:FlexEvent):void{
ChangeWatcher.watch(this,['exerciseSeries','selectedItem'], handleChange_SelectedItem);
}
protected function handleChange_SelectedItem(event:PropertyChangeEvent):void{
// Either
dispatchedEvent(//some custom event);
// Or
someDirectMethodCall();
}
An alternative would be to search for an instance of the the event class in the view hierarchy under the mouse coordinates whenever a user clicks.
//Attach this click handler to the component
private function handleClick(event : MouseEvent) : void {
var obj : *EventClass*= null;
var applicationStage : Stage = FlexGlobals.topLevelApplication.stage as Stage;
var mousePoint : Point = new Point(applicationStage.mouseX, applicationStage.mouseY);
var objects : Array = applicationStage.getObjectsUnderPoint(mousePoint);
for (var i : int = objects.length - 1; i >= 0; i--) {
if (objects[i] is *EventClass*) {
obj = objects[i] as *EventClass*;
break;
}
}
if(obj is *EventClass*){
//Dispatch some custom event with obj being the item that was clicked on.
}
}
Where EventClass is the class of the objects that represent events
I have had similar problems and sometimes you can get by with wrapping the object with a Box and putting the click event on the Box. If you have not already tried that, it's a cheap, easy fix (if it works for you).
<mx:Box click="exerciseClickHandler(event)">
<code:ScheduleViewer id="exerciseSeries" />
</mx:Box>

Resources