Tree: improved support for JTree.getPathForLocation(int x, int y) in wide selection (issue #373)

this is experimental and disabled by default; enable with:
`UIManager.put( "FlatLaf.experimental.tree.widePathForLocation", true );`
This commit is contained in:
Karl Tauber
2021-08-13 00:19:34 +02:00
parent 7bc9be686f
commit 268fe15004
3 changed files with 73 additions and 1 deletions

View File

@@ -230,6 +230,26 @@ public class FlatTreeUI
tree.repaint( 0, r.y, tree.getWidth(), r.height );
}
@Override
public Rectangle getPathBounds( JTree tree, TreePath path ) {
Rectangle bounds = super.getPathBounds( tree, path );
// If this method was invoked from JTree.getPathForLocation(int x, int y) to check whether
// the location is within tree node bounds, then return the bounds of a wide node.
// This changes the behavior of JTree.getPathForLocation(int x, int y) and
// JTree.getRowForLocation(int x, int y), which now return the path/row even
// if [x,y] is in the wide row area outside of the actual tree node.
if( bounds != null &&
isWideSelection() &&
UIManager.getBoolean( "FlatLaf.experimental.tree.widePathForLocation" ) &&
StackUtils.wasInvokedFrom( JTree.class.getName(), "getPathForLocation", 5 ) )
{
bounds.x = 0;
bounds.width = tree.getWidth();
}
return bounds;
}
/**
* Same as super.paintRow(), but supports wide selection and uses
* inactive selection background/foreground if tree is not focused.

View File

@@ -24,6 +24,7 @@ import java.awt.EventQueue;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.*;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@@ -39,6 +40,7 @@ import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.icons.FlatMenuArrowIcon;
@@ -69,6 +71,7 @@ public class FlatComponents2Test
SwingUtilities.invokeLater( () -> {
FlatTestFrame frame = FlatTestFrame.create( args, "FlatComponents2Test" );
frame.useApplyComponentOrientation = true;
UIManager.put( "FlatLaf.experimental.tree.widePathForLocation", true );
frame.showFrame( FlatComponents2Test::new );
} );
}
@@ -378,6 +381,23 @@ public class FlatComponents2Test
tree.putClientProperty( FlatClientProperties.TREE_PAINT_SELECTION, paintSelection );
}
private void treeMouseClicked( MouseEvent e ) {
JTree tree = (JTree) e.getSource();
int x = e.getX();
int y = e.getY();
TreePath path = tree.getPathForLocation( x, y );
TreePath closestPath = tree.getClosestPathForLocation( x, y );
int row = tree.getRowForLocation( x, y );
int closestRow = tree.getClosestRowForLocation( x, y );
System.out.println( "---- tree mouseClicked " + x + "," + y + " ----" );
System.out.println( " path: " + path );
System.out.println( "closest path: " + closestPath );
System.out.println( " row: " + row );
System.out.println( "closest row: " + closestRow );
}
@Override
public void applyComponentOrientation( ComponentOrientation o ) {
super.applyComponentOrientation( o );
@@ -605,6 +625,12 @@ public class FlatComponents2Test
//---- tree1 ----
tree1.setShowsRootHandles(true);
tree1.setEditable(true);
tree1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
treeMouseClicked(e);
}
});
scrollPane3.setViewportView(tree1);
}
add(scrollPane3, "cell 1 2");
@@ -614,6 +640,12 @@ public class FlatComponents2Test
//---- tree2 ----
tree2.setEnabled(false);
tree2.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
treeMouseClicked(e);
}
});
scrollPane4.setViewportView(tree2);
}
add(scrollPane4, "cell 2 2");
@@ -655,12 +687,28 @@ public class FlatComponents2Test
//======== scrollPane5 ========
{
//---- xTree1 ----
xTree1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
treeMouseClicked(e);
}
});
scrollPane5.setViewportView(xTree1);
}
add(scrollPane5, "cell 1 3");
//======== scrollPane6 ========
{
//---- checkBoxTree1 ----
checkBoxTree1.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
treeMouseClicked(e);
}
});
scrollPane6.setViewportView(checkBoxTree1);
}
add(scrollPane6, "cell 2 3");

View File

@@ -1,4 +1,4 @@
JFDML JFormDesigner: "7.0.3.1.342" Java: "16" encoding: "UTF-8"
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -185,6 +185,7 @@ new FormModel {
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.MouseListener", "mouseClicked", "treeMouseClicked", true ) )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 2"
@@ -197,6 +198,7 @@ new FormModel {
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.MouseListener", "mouseClicked", "treeMouseClicked", true ) )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 2"
@@ -255,6 +257,7 @@ new FormModel {
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.MouseListener", "mouseClicked", "treeMouseClicked", true ) )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 3"
@@ -266,6 +269,7 @@ new FormModel {
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.MouseListener", "mouseClicked", "treeMouseClicked", true ) )
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 3"