mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +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
|
||||
large right margin. (issue #604; regression since implementing PR #522 in
|
||||
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
|
||||
|
||||
@@ -25,7 +25,11 @@ import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.Icon;
|
||||
@@ -152,6 +156,7 @@ public class FlatTreeUI
|
||||
// only used via styling (not in UI defaults, but has likewise client properties)
|
||||
/** @since 2 */ @Styleable protected boolean paintSelection = true;
|
||||
|
||||
private boolean paintLines;
|
||||
private Color defaultCellNonSelectionBackground;
|
||||
private Color defaultSelectionBackground;
|
||||
private Color defaultSelectionForeground;
|
||||
@@ -185,6 +190,7 @@ public class FlatTreeUI
|
||||
wideSelection = UIManager.getBoolean( "Tree.wideSelection" );
|
||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||
|
||||
paintLines = UIManager.getBoolean( "Tree.paintLines" );
|
||||
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
||||
defaultSelectionBackground = selectionBackground;
|
||||
defaultSelectionForeground = selectionForeground;
|
||||
@@ -381,6 +387,125 @@ public class FlatTreeUI
|
||||
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
|
||||
* 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,
|
||||
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,
|
||||
@@ -596,6 +714,16 @@ public class FlatTreeUI
|
||||
(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.
|
||||
* See DefaultTreeCellRenderer.getTreeCellRendererComponent().
|
||||
|
||||
@@ -473,6 +473,22 @@ public class FlatComponents2Test
|
||||
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() {
|
||||
boolean editable = treeEditableCheckBox.isSelected();
|
||||
for( JTree tree : allTrees )
|
||||
@@ -575,6 +591,8 @@ public class FlatComponents2Test
|
||||
treeRendererComboBox = new JComboBox<>();
|
||||
treeWideSelectionCheckBox = new JCheckBox();
|
||||
treePaintSelectionCheckBox = new JCheckBox();
|
||||
treePaintLinesCheckBox = new JCheckBox();
|
||||
treeRedLinesCheckBox = new JCheckBox();
|
||||
treeEditableCheckBox = new JCheckBox();
|
||||
JPanel tableOptionsPanel = new JPanel();
|
||||
JLabel autoResizeModeLabel = new JLabel();
|
||||
@@ -917,6 +935,7 @@ public class FlatComponents2Test
|
||||
"[]" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]"));
|
||||
|
||||
//---- treeRendererLabel ----
|
||||
@@ -946,10 +965,21 @@ public class FlatComponents2Test
|
||||
treePaintSelectionCheckBox.addActionListener(e -> treePaintSelectionChanged());
|
||||
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.setText("editable");
|
||||
treeEditableCheckBox.addActionListener(e -> treeEditableChanged());
|
||||
treeOptionsPanel.add(treeEditableCheckBox, "cell 0 3");
|
||||
treeOptionsPanel.add(treeEditableCheckBox, "cell 0 4");
|
||||
}
|
||||
add(treeOptionsPanel, "cell 0 4 4 1");
|
||||
|
||||
@@ -1083,6 +1113,8 @@ public class FlatComponents2Test
|
||||
private JComboBox<String> treeRendererComboBox;
|
||||
private JCheckBox treeWideSelectionCheckBox;
|
||||
private JCheckBox treePaintSelectionCheckBox;
|
||||
private JCheckBox treePaintLinesCheckBox;
|
||||
private JCheckBox treeRedLinesCheckBox;
|
||||
private JCheckBox treeEditableCheckBox;
|
||||
private JComboBox<String> autoResizeModeField;
|
||||
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 {
|
||||
contentType: "form/swing"
|
||||
@@ -395,7 +395,7 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[left]"
|
||||
"$rowConstraints": "[][]0[]0[]"
|
||||
"$rowConstraints": "[][]0[]0[]0[]"
|
||||
} ) {
|
||||
name: "treeOptionsPanel"
|
||||
"border": new javax.swing.border.TitledBorder( "JTree Control" )
|
||||
@@ -445,6 +445,27 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"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" ) {
|
||||
name: "treeEditableCheckBox"
|
||||
"text": "editable"
|
||||
@@ -453,7 +474,7 @@ new FormModel {
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeEditableChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
"value": "cell 0 4"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 4 4 1"
|
||||
|
||||
Reference in New Issue
Block a user