mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 22:10:54 +03:00
Tree:
- Fixed missing tree lines (if enabled) for wide-selected rows. (issue #598) - Fixed scaling of tree lines and fixed alignment to expand/collapse arrows. - Removed support for dashed tree lines. `Tree.lineTypeDashed` is now ignored.
This commit is contained in:
@@ -17,6 +17,10 @@ FlatLaf Change Log
|
|||||||
- FileChooser: Fixed layout of (optional) accessory component and fixed too
|
- FileChooser: Fixed layout of (optional) accessory component and fixed too
|
||||||
large right margin. (issue #604; regression since implementing PR #522 in
|
large right margin. (issue #604; regression since implementing PR #522 in
|
||||||
FlatLaf 2.3)
|
FlatLaf 2.3)
|
||||||
|
- Tree:
|
||||||
|
- Fixed missing tree lines (if enabled) for wide-selected rows. (issue #598)
|
||||||
|
- Fixed scaling of tree lines and fixed alignment to expand/collapse arrows.
|
||||||
|
- Removed support for dashed tree lines. `Tree.lineTypeDashed` is now ignored.
|
||||||
|
|
||||||
|
|
||||||
## 2.6
|
## 2.6
|
||||||
|
|||||||
@@ -25,7 +25,11 @@ import java.awt.Insets;
|
|||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseListener;
|
import java.awt.event.MouseListener;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.CellRendererPane;
|
import javax.swing.CellRendererPane;
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
@@ -152,6 +156,7 @@ public class FlatTreeUI
|
|||||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||||
/** @since 2 */ @Styleable protected boolean paintSelection = true;
|
/** @since 2 */ @Styleable protected boolean paintSelection = true;
|
||||||
|
|
||||||
|
private boolean paintLines;
|
||||||
private Color defaultCellNonSelectionBackground;
|
private Color defaultCellNonSelectionBackground;
|
||||||
private Color defaultSelectionBackground;
|
private Color defaultSelectionBackground;
|
||||||
private Color defaultSelectionForeground;
|
private Color defaultSelectionForeground;
|
||||||
@@ -185,6 +190,7 @@ public class FlatTreeUI
|
|||||||
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
|
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
|
||||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||||
|
|
||||||
|
paintLines = UIManager.getBoolean( "Tree.paintLines" );
|
||||||
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
||||||
defaultSelectionBackground = selectionBackground;
|
defaultSelectionBackground = selectionBackground;
|
||||||
defaultSelectionForeground = selectionForeground;
|
defaultSelectionForeground = selectionForeground;
|
||||||
@@ -381,6 +387,125 @@ public class FlatTreeUI
|
|||||||
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
return FlatStylingSupport.getAnnotatedStyleableValue( this, key );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g, JComponent c ) {
|
||||||
|
if( treeState == null )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// use clip bounds to limit painting to needed rows
|
||||||
|
Rectangle clipBounds = g.getClipBounds();
|
||||||
|
TreePath firstPath = getClosestPathForLocation( tree, 0, clipBounds.y );
|
||||||
|
Enumeration<TreePath> visiblePaths = treeState.getVisiblePathsFrom( firstPath );
|
||||||
|
|
||||||
|
if( visiblePaths != null ) {
|
||||||
|
Insets insets = tree.getInsets();
|
||||||
|
|
||||||
|
HashSet<TreePath> verticalLinePaths = paintLines ? new HashSet<>() : null;
|
||||||
|
ArrayList<Runnable> paintLinesLater = paintLines ? new ArrayList<>() : null;
|
||||||
|
ArrayList<Runnable> paintExpandControlsLater = paintLines ? new ArrayList<>() : null;
|
||||||
|
|
||||||
|
// add parents for later painting of vertical lines
|
||||||
|
if( paintLines ) {
|
||||||
|
for( TreePath path = firstPath.getParentPath(); path != null; path = path.getParentPath() )
|
||||||
|
verticalLinePaths.add( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle boundsBuffer = new Rectangle();
|
||||||
|
boolean rootVisible = isRootVisible();
|
||||||
|
int row = treeState.getRowForPath( firstPath );
|
||||||
|
boolean leftToRight = tree.getComponentOrientation().isLeftToRight();
|
||||||
|
int treeWidth = tree.getWidth();
|
||||||
|
|
||||||
|
// iterate over visible rows and paint rows, expand control and lines
|
||||||
|
while( visiblePaths.hasMoreElements() ) {
|
||||||
|
TreePath path = visiblePaths.nextElement();
|
||||||
|
if( path == null )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// compute path bounds
|
||||||
|
Rectangle bounds = treeState.getBounds( path, boundsBuffer );
|
||||||
|
if( bounds == null )
|
||||||
|
break;
|
||||||
|
|
||||||
|
// add tree insets to path bounds
|
||||||
|
if( leftToRight )
|
||||||
|
bounds.x += insets.left;
|
||||||
|
else
|
||||||
|
bounds.x = treeWidth - insets.right - (bounds.x + bounds.width);
|
||||||
|
bounds.y += insets.top;
|
||||||
|
|
||||||
|
boolean isLeaf = treeModel.isLeaf( path.getLastPathComponent() );
|
||||||
|
boolean isExpanded = isLeaf ? false : treeState.getExpandedState( path );
|
||||||
|
boolean hasBeenExpanded = isLeaf ? false : tree.hasBeenExpanded( path );
|
||||||
|
|
||||||
|
// paint row (including selection)
|
||||||
|
paintRow( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
|
||||||
|
|
||||||
|
// collect lines for later painting
|
||||||
|
if( paintLines ) {
|
||||||
|
TreePath parentPath = path.getParentPath();
|
||||||
|
|
||||||
|
// add parent for later painting of vertical lines
|
||||||
|
if( parentPath != null )
|
||||||
|
verticalLinePaths.add( parentPath );
|
||||||
|
|
||||||
|
// paint horizontal line later (for using rendering hints)
|
||||||
|
if( parentPath != null || (rootVisible && row == 0) ) {
|
||||||
|
Rectangle bounds2 = new Rectangle( bounds );
|
||||||
|
int row2 = row;
|
||||||
|
paintLinesLater.add( () -> {
|
||||||
|
paintHorizontalPartOfLeg( g, clipBounds, insets, bounds2, path, row2, isExpanded, hasBeenExpanded, isLeaf );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint expand control
|
||||||
|
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
|
||||||
|
if( paintLines ) {
|
||||||
|
// need to paint after painting lines
|
||||||
|
Rectangle bounds2 = new Rectangle( bounds );
|
||||||
|
int row2 = row;
|
||||||
|
paintExpandControlsLater.add( () -> {
|
||||||
|
paintExpandControl( g, clipBounds, insets, bounds2, path, row2, isExpanded, hasBeenExpanded, isLeaf );
|
||||||
|
} );
|
||||||
|
} else
|
||||||
|
paintExpandControl( g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bounds.y + bounds.height >= clipBounds.y + clipBounds.height )
|
||||||
|
break;
|
||||||
|
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( paintLines ) {
|
||||||
|
// enable antialiasing for line painting
|
||||||
|
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
|
||||||
|
|
||||||
|
// paint horizontal lines
|
||||||
|
for( Runnable r : paintLinesLater )
|
||||||
|
r.run();
|
||||||
|
|
||||||
|
// paint vertical lines
|
||||||
|
g.setColor( Color.green );
|
||||||
|
for( TreePath path : verticalLinePaths )
|
||||||
|
paintVerticalPartOfLeg( g, clipBounds, insets, path );
|
||||||
|
|
||||||
|
// restore rendering hints
|
||||||
|
if( oldRenderingHints != null )
|
||||||
|
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
|
||||||
|
|
||||||
|
// paint expand controls
|
||||||
|
for( Runnable r : paintExpandControlsLater )
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
paintDropLine( g );
|
||||||
|
|
||||||
|
rendererPane.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to super.paintRow(), but supports wide selection and uses
|
* Similar to super.paintRow(), but supports wide selection and uses
|
||||||
* inactive selection background/foreground if tree is not focused.
|
* inactive selection background/foreground if tree is not focused.
|
||||||
@@ -544,13 +669,6 @@ public class FlatTreeUI
|
|||||||
|
|
||||||
FlatUIUtils.paintSelection( (Graphics2D) g, 0, bounds.y, tree.getWidth(), bounds.height,
|
FlatUIUtils.paintSelection( (Graphics2D) g, 0, bounds.y, tree.getWidth(), bounds.height,
|
||||||
UIScale.scale( selectionInsets ), arcTop, arcTop, arcBottom, arcBottom, 0 );
|
UIScale.scale( selectionInsets ), arcTop, arcTop, arcBottom, arcBottom, 0 );
|
||||||
|
|
||||||
// paint expand/collapse icon
|
|
||||||
// (was already painted before, but painted over with wide selection)
|
|
||||||
if( shouldPaintExpandControl( path, row, isExpanded, hasBeenExpanded, isLeaf ) ) {
|
|
||||||
paintExpandControl( g, clipBounds, insets, bounds,
|
|
||||||
path, row, isExpanded, hasBeenExpanded, isLeaf );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds,
|
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds,
|
||||||
@@ -596,6 +714,16 @@ public class FlatTreeUI
|
|||||||
(selectionInsets == null || (selectionInsets.top == 0 && selectionInsets.bottom == 0));
|
(selectionInsets == null || (selectionInsets.top == 0 && selectionInsets.bottom == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintVerticalLine( Graphics g, JComponent c, int x, int top, int bottom ) {
|
||||||
|
((Graphics2D)g).fill( new Rectangle2D.Float( x, top, UIScale.scale( 1f ), bottom - top ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintHorizontalLine( Graphics g, JComponent c, int y, int left, int right ) {
|
||||||
|
((Graphics2D)g).fill( new Rectangle2D.Float( left, y, right - left, UIScale.scale( 1f ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether dropping on a row.
|
* Checks whether dropping on a row.
|
||||||
* See DefaultTreeCellRenderer.getTreeCellRendererComponent().
|
* See DefaultTreeCellRenderer.getTreeCellRendererComponent().
|
||||||
|
|||||||
@@ -473,6 +473,22 @@ public class FlatComponents2Test
|
|||||||
tree.putClientProperty( FlatClientProperties.TREE_PAINT_SELECTION, paintSelection );
|
tree.putClientProperty( FlatClientProperties.TREE_PAINT_SELECTION, paintSelection );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void treePaintLinesChanged() {
|
||||||
|
boolean paintLines = treePaintLinesCheckBox.isSelected();
|
||||||
|
UIManager.put( "Tree.paintLines", paintLines ? true : null );
|
||||||
|
for( JTree tree : allTrees )
|
||||||
|
tree.updateUI();
|
||||||
|
|
||||||
|
treeRedLinesCheckBox.setEnabled( paintLines );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void treeRedLinesChanged() {
|
||||||
|
boolean redLines = treeRedLinesCheckBox.isSelected();
|
||||||
|
UIManager.put( "Tree.hash", redLines ? Color.red : null );
|
||||||
|
for( JTree tree : allTrees )
|
||||||
|
tree.updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
private void treeEditableChanged() {
|
private void treeEditableChanged() {
|
||||||
boolean editable = treeEditableCheckBox.isSelected();
|
boolean editable = treeEditableCheckBox.isSelected();
|
||||||
for( JTree tree : allTrees )
|
for( JTree tree : allTrees )
|
||||||
@@ -575,6 +591,8 @@ public class FlatComponents2Test
|
|||||||
treeRendererComboBox = new JComboBox<>();
|
treeRendererComboBox = new JComboBox<>();
|
||||||
treeWideSelectionCheckBox = new JCheckBox();
|
treeWideSelectionCheckBox = new JCheckBox();
|
||||||
treePaintSelectionCheckBox = new JCheckBox();
|
treePaintSelectionCheckBox = new JCheckBox();
|
||||||
|
treePaintLinesCheckBox = new JCheckBox();
|
||||||
|
treeRedLinesCheckBox = new JCheckBox();
|
||||||
treeEditableCheckBox = new JCheckBox();
|
treeEditableCheckBox = new JCheckBox();
|
||||||
JPanel tableOptionsPanel = new JPanel();
|
JPanel tableOptionsPanel = new JPanel();
|
||||||
JLabel autoResizeModeLabel = new JLabel();
|
JLabel autoResizeModeLabel = new JLabel();
|
||||||
@@ -917,6 +935,7 @@ public class FlatComponents2Test
|
|||||||
"[]" +
|
"[]" +
|
||||||
"[]0" +
|
"[]0" +
|
||||||
"[]0" +
|
"[]0" +
|
||||||
|
"[]0" +
|
||||||
"[]"));
|
"[]"));
|
||||||
|
|
||||||
//---- treeRendererLabel ----
|
//---- treeRendererLabel ----
|
||||||
@@ -946,10 +965,21 @@ public class FlatComponents2Test
|
|||||||
treePaintSelectionCheckBox.addActionListener(e -> treePaintSelectionChanged());
|
treePaintSelectionCheckBox.addActionListener(e -> treePaintSelectionChanged());
|
||||||
treeOptionsPanel.add(treePaintSelectionCheckBox, "cell 0 2");
|
treeOptionsPanel.add(treePaintSelectionCheckBox, "cell 0 2");
|
||||||
|
|
||||||
|
//---- treePaintLinesCheckBox ----
|
||||||
|
treePaintLinesCheckBox.setText("paint lines");
|
||||||
|
treePaintLinesCheckBox.addActionListener(e -> treePaintLinesChanged());
|
||||||
|
treeOptionsPanel.add(treePaintLinesCheckBox, "cell 0 3");
|
||||||
|
|
||||||
|
//---- treeRedLinesCheckBox ----
|
||||||
|
treeRedLinesCheckBox.setText("red lines");
|
||||||
|
treeRedLinesCheckBox.setEnabled(false);
|
||||||
|
treeRedLinesCheckBox.addActionListener(e -> treeRedLinesChanged());
|
||||||
|
treeOptionsPanel.add(treeRedLinesCheckBox, "cell 0 3");
|
||||||
|
|
||||||
//---- treeEditableCheckBox ----
|
//---- treeEditableCheckBox ----
|
||||||
treeEditableCheckBox.setText("editable");
|
treeEditableCheckBox.setText("editable");
|
||||||
treeEditableCheckBox.addActionListener(e -> treeEditableChanged());
|
treeEditableCheckBox.addActionListener(e -> treeEditableChanged());
|
||||||
treeOptionsPanel.add(treeEditableCheckBox, "cell 0 3");
|
treeOptionsPanel.add(treeEditableCheckBox, "cell 0 4");
|
||||||
}
|
}
|
||||||
add(treeOptionsPanel, "cell 0 4 4 1");
|
add(treeOptionsPanel, "cell 0 4 4 1");
|
||||||
|
|
||||||
@@ -1083,6 +1113,8 @@ public class FlatComponents2Test
|
|||||||
private JComboBox<String> treeRendererComboBox;
|
private JComboBox<String> treeRendererComboBox;
|
||||||
private JCheckBox treeWideSelectionCheckBox;
|
private JCheckBox treeWideSelectionCheckBox;
|
||||||
private JCheckBox treePaintSelectionCheckBox;
|
private JCheckBox treePaintSelectionCheckBox;
|
||||||
|
private JCheckBox treePaintLinesCheckBox;
|
||||||
|
private JCheckBox treeRedLinesCheckBox;
|
||||||
private JCheckBox treeEditableCheckBox;
|
private JCheckBox treeEditableCheckBox;
|
||||||
private JComboBox<String> autoResizeModeField;
|
private JComboBox<String> autoResizeModeField;
|
||||||
private JComboBox<String> sortIconPositionComboBox;
|
private JComboBox<String> sortIconPositionComboBox;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.5.0.404" Java: "17.0.2" encoding: "UTF-8"
|
JFDML JFormDesigner: "8.0.0.0.194" Java: "17.0.2" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -395,7 +395,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "hidemode 3"
|
"$layoutConstraints": "hidemode 3"
|
||||||
"$columnConstraints": "[left]"
|
"$columnConstraints": "[left]"
|
||||||
"$rowConstraints": "[][]0[]0[]"
|
"$rowConstraints": "[][]0[]0[]0[]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "treeOptionsPanel"
|
name: "treeOptionsPanel"
|
||||||
"border": new javax.swing.border.TitledBorder( "JTree Control" )
|
"border": new javax.swing.border.TitledBorder( "JTree Control" )
|
||||||
@@ -445,6 +445,27 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 2"
|
"value": "cell 0 2"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "treePaintLinesCheckBox"
|
||||||
|
"text": "paint lines"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treePaintLinesChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 3"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "treeRedLinesCheckBox"
|
||||||
|
"text": "red lines"
|
||||||
|
"enabled": false
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeRedLinesChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 3"
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
name: "treeEditableCheckBox"
|
name: "treeEditableCheckBox"
|
||||||
"text": "editable"
|
"text": "editable"
|
||||||
@@ -453,7 +474,7 @@ new FormModel {
|
|||||||
}
|
}
|
||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeEditableChanged", false ) )
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeEditableChanged", false ) )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 3"
|
"value": "cell 0 4"
|
||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 4 4 1"
|
"value": "cell 0 4 4 1"
|
||||||
|
|||||||
Reference in New Issue
Block a user