How to skip DRAG_DETECTED Events from TableHeaderRow (resizing TableColumns) - javafx

In order to use a TableView (with resizable columns) as drag source,
I have attached an onDragDetected handler on that TableView with the effect, that resizing TableColumns does not work anymore: If the user clicks into the TableHeaderRow for dragging the column separators, these mouse events are consumed by my handler too.
The handler is attached to the whole TableView and I do not see a way to distinguish between events from TableRows and events from the TableHeaderRow.
Attaching the handler to the data-rows only is not appropriate in my case, since I need multiline selection (and do not want to have dependencies from the RowFactory to the application data model).
Any suggestions?
best Hans

I found the solution myself: I had to look up the TableHeaderRow instance with the lookup-method, and discard the DRAG_DETECTED event there.
Pane header = (Pane) mainTableView.lookup("TableHeaderRow");
header.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
System.out.println("ignoring drag operation from table header.");
event.consume();
}
});
After that, resising of table columns works. Maybe there is something wrong with my drag+drop event handling that initially caused the problem!? Somebody voted down without comment...

The solution by Hans does work, but only after the window is shown. I added a window.setOnShown((WindowEvent e) listener and then I was able to do the lookup and header.setOnDragDetected.
Here is how I added it:
window.setOnShown((WindowEvent e) -> {
Pane header = (Pane) mainTableView.lookup("TableHeaderRow");
....
});
Otherwise, lookup returns null.

Related

Adding eventhandler to tab context menu throws null pointer exception

I would like to add the event handler to a tab context menu. And after the tab context menu is selected I would like to remove the event handler from the node. The problem is that Tab2.getContextMenu().addEventHandler(Event.ANY,handler); throws a NullPointerException.
#FXML Tab Tab2; - Tab2 can be found in my fxml with fx:id="Tab2"
EventHandler<Event> handler = (new EventHandler<Event>() {
public void handle(Event event) {
System.out.println("Tab2 is selected!");
Tab2.getContextMenu().removeEventHandler(Event.ANY, this);
}
});
Tab2.getContextMenu().addEventHandler(Event.ANY, handler);
The code takes place in initialize function.
I would like to achive a similar solution like this:
Tab2.setOnSelectionChanged(e -> {
if(Tab2.isSelected()) {
System.out.println("Tab2 is selected!");
}
});
Unfortunately, with this solution it will run all the time on selection. But I want it to happen only once and also remove the event listener.
This asker used a similar solution like me:
How to remove an event handler?
But he had no problem with adding the event handler.
EDIT:
It seems like getContextMenu() function causes the nullpointer exception and it also seems I kind of misunderstood what that function does. I wanted to get the tab's "header".
But the question remains the same. How can I add an event listener to a tab, and after it is selected the first time remove the event listener from it. That's all.
You can set the listener value as null
e.g.:
tab1.setOnSelectionChanged((e)->{
if(tab1.isSelected()){
tab1.setOnSelectionChanged(null);
}
});

JavaFX TreeView: remove expand / collapse button (disclosure node) & functionality

I want to have a TreeView that has all of its children permanently expanded, and I don't want the user to be able to expand or collapse any of the children.
To do this I've found that I need to do the following:
Remove icon with CSS (Done)
Change expand and collapse image TreeView JavaFX 2.2
[edit] Above link should be used to change image; to remove completely, use this solution: https://stackoverflow.com/a/27831191/4430591
Remove double click functionality (Done)
Disable TreeItem's default expand/collapse on double click JavaFX 2.2
[edit] Remove ability to collapse / expand using keyboard arrrow keys (Done)
Given in José Pereda's solution below ( https://stackoverflow.com/a/27831085/4430591 )
[edit] Remove ability to right click for a ContextMenu (Done)
Given in José Pereda's solution below ( https://stackoverflow.com/a/27831085/4430591 )
Remove icon's clickablity (How do I do this?)
[edit] solution: https://stackoverflow.com/a/27831191/4430591
Even though the icon is no longer visible, it's still clickable. I don't see any way of filtering this; I only see ways to be able to respond to it after the fact.
Also, if I'm missing anything else that I need to do to ensure this functionality, please let me know.
I feel quite silly. I think this was mostly just a matter of not knowing what that darn arrow was called. Apparently it's a disclosureNode? Maybe that's common knowledge.
In the custom defined TreeCell, all I did was add this line in the updateItem method:
setDisclosureNode(null);
The solution to avoid modifying the skin or the default behavior is more simple if we trap the clicks before they are dispatched, and consume the right ones.
For that we can use an EventDispatcher, to filter both the mouse pressed and the right click over the arrows, which are StackPane nodes:
class CellEventDispatcher implements EventDispatcher {
private final EventDispatcher original;
public CellEventDispatcher(EventDispatcher original) {
this.original = original;
}
#Override
public Event dispatchEvent(Event event, EventDispatchChain tail) {
if (event.getEventType().equals(MouseEvent.MOUSE_PRESSED) ||
event.getEventType().equals(ContextMenuEvent.ANY)){
event.consume();
}
if(event instanceof KeyEvent && event.getEventType().equals(KeyEvent.KEY_PRESSED)){
if((((KeyEvent)event).getCode().equals(KeyCode.LEFT) ||
((KeyEvent)event).getCode().equals(KeyCode.RIGHT))){
event.consume();
}
}
return original.dispatchEvent(event, tail);
}
}
Now we apply our custom dispatcher to the tree view:
#Override
public void start(Stage primaryStage) {
TreeView<String> tree = new TreeView<>();
...
EventDispatcher treeOriginal = tree.getEventDispatcher();
tree.setEventDispatcher(new CellEventDispatcher(treeOriginal));
Scene scene = new Scene(tree);
primaryStage.setScene(scene);
primaryStage.show();
}
This will consume any click (left or right) over the arrows on the tree.
EDIT
Added to the event dispatcher class the case where the user uses the keyboard to traverse the tree view, consuming the collapse/expand events with arrow LEFT or RIGHT.

Refreshing tableView in JavaFx after closing dialog

I have two layouts in JavaFX app. The first one contains table view whereas the second one is a simple dialog to input data. The problem is that I want to refresh data after closing the dialog. Now I have a button on the first layout which refreshes data:
data.removeAll(data);
loadDataToTable();
But I don't want to invoke methods shown above with the button but automatically right after closing the dialog. I don't know how to make this, let's say, connection between those controllers.
thanks in advance
The new Dialog, if I am not wrong must be a new Stage ! Let us consider the new Stage to be modifyStage. We can call the onSetCloseRequest of the new Stage and put your code in it.
modifyStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent paramT) {
data.removeAll(data);
loadDataToTable();
}
});

How to expand .NET TreeView node by clicking its text instead of +/-

I've been using hardcoded hyperlinks for my web app navigation, but the app has grown since and managing it is becoming a real pain. I've decided to replace what I have with the TreeView control, however I want to make several changes to the way it looks.
Is there any property that needs to be set, that would allow user to expand the TreeView node by clicking its text instead of +/- ?
I've already set ShowExpandColapse to 'false'.
I want my final result to end up as something similar to the TreeView on the left of the MSDN site.
Could anyone point me at the right direction please?
Set TreeNode.SelectAction to either Expand, or SelectExpand.
you can use xml data source or direct binding from db to treview
in the TreeView DataBound event we can write d recursive function as below to fetch each node and assign expand action to them.
protected void TreeView1_DataBound(object sender, EventArgs e)
{
foreach (TreeNode node in TreeView1.Nodes)
{
node.SelectAction = TreeNodeSelectAction.Expand;
PrintNodesRecursive(node);
}
}
public void PrintNodesRecursive(TreeNode oParentNode)
{
// Start recursion on all subnodes.
foreach(TreeNode oSubNode in oParentNode.ChildNodes)
{
oSubNode.SelectAction = TreeNodeSelectAction.Expand;
PrintNodesRecursive(oSubNode);
}
}
I think you just have to do this in code: handle the Click event, determine the currently-selected tree node, and toggle its Expanded property (I think that's what it's called here).
You can do this only this way! http://geekswithblogs.net/rajiv/archive/2006/03/16/72575.aspx
With respect,
Alexander

'Databinding complete' event for Silverlight 4.0 DataGrid?

I have a DataGrid that I have bound to a property:
<cd:DataGrid
Name="myDataGrid"
ItemsSource="{Binding Mode=OneWay,Path=Thingies}"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
...
When the Thingies property changes, once all rows in the DataGrid have been populated with the new contents of Thingies, I want the DataGrid to scroll to the bottom row.
In WinForms, I would have done this by subscribing to the DataBindingComplete event. MSDN Forums contains several suggestions on how to do this with Silverlight 4.0 but they range from completely evil to just plain fugly:
start a 100ms timer on load, and scroll when it elapses
count rows as they're added, and scroll to the bottom when the number of added rows equals the number of entities in the data source
Is there an idiomatic, elegant way of doing what I want in Silverlight 4.0?
I stumbled upon this while searching for a resolution to the same problem. I was finding that when I attempted to scroll the selected item into view after filter and sort changes that I frequently received a run time error (index out of bounds). I knew instinctively that this was because the grid was not populated at that particular moment.
Aaron's suggestion worked for me. When the grid is defined, I add an event listener:
_TheGrid.LayoutUpdated += (sender, args) => TheGrid.ScrollIntoView(TheGrid.SelectedItem, TheGrid.CurrentColumn);
This solved my problem, and seems to silently exit when the parameters are null, too.
Why not derive from DataGrid and simply create your own ItemsSourceChanged event?
public class DataGridExtended : DataGrid
{
public delegate void ItemsSourceChangedHandler(object sender, EventArgs e);
public event ItemsSourceChangedHandler ItemSourceChanged;
public new System.Collections.IEnumerable ItemsSource
{
get { return base.ItemsSource; }
set
{
base.ItemsSource = value;
EventArgs e = new EventArgs();
OnItemsSourceChanged(e);
}
}
protected virtual void OnItemsSourceChanged(EventArgs e)
{
if (ItemSourceChanged != null)
ItemSourceChanged(this, e);
}
}
Use the ScrollIntoView method for achieving this.
myDataGrid.ItemSource = Thingies;
myDataGrid.UpdateLayout();
myDataGrid.ScrollIntoView(MyObservableCollection[MyObservableCollection.Count - 1], myDataGrid.Columns[1]);
You don't need to have any special event for this.
I think the nice way to do it, in xaml, is to have the binding NotifyOnTargetUpdated=true, and then you can hook the TargetUpdated to any event of your choice.
<ThisControl BindedProperty="{Binding xxx, NotifyOnTargetUpdated=true}"
TargetUpdated="BindingEndedHandler">

Resources