mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-06 14:00:55 +03:00
FlatSmoothScrollingTest:
- better list/tree/etc items for easier recognizing jittery scrolling - sliders to modify animation duration and resolution - slider to invoke `scrollRectToVisible()` - option to show row header for table - use viewport.viewPosition for chart (instead of scrollbar.value) - highlight methods in stack of tooltip (e.g. JViewport.setViewPosition())
This commit is contained in:
@@ -180,7 +180,7 @@ public class FlatAnimatorTest
|
||||
value = startValue + Math.round( (targetValue - startValue) * fraction );
|
||||
valueLabel.setText( String.valueOf( value ) );
|
||||
|
||||
lineChartPanel.addValue( value / (double) MAX_VALUE, value, false, Color.red, null );
|
||||
lineChartPanel.addValue( Color.red, value / (double) MAX_VALUE, value, null );
|
||||
}, () -> {
|
||||
targetValue = -1;
|
||||
} );
|
||||
@@ -198,7 +198,7 @@ public class FlatAnimatorTest
|
||||
// for unprecise wheels the rotation value is usually -1 or +1
|
||||
// for precise wheels the rotation value is in range ca. -10 to +10,
|
||||
// depending how fast the wheel is rotated
|
||||
lineChartPanel.addValue( 0.5 + (preciseWheelRotation / 20.), (int) (preciseWheelRotation * 1000), true, Color.red, null );
|
||||
lineChartPanel.addDot( Color.red, 0.5 + (preciseWheelRotation / 20.), (int) (preciseWheelRotation * 1000), null, null );
|
||||
|
||||
// increase/decrease target value if animation is in progress
|
||||
int newValue = (int) ((targetValue < 0 ? value : targetValue) + (STEP * preciseWheelRotation));
|
||||
@@ -215,7 +215,7 @@ public class FlatAnimatorTest
|
||||
value = newValue;
|
||||
valueLabel.setText( String.valueOf( value ) );
|
||||
|
||||
lineChartPanel.addValue( value / (double) MAX_VALUE, value, false, Color.red, null );
|
||||
lineChartPanel.addValue( Color.red, value / (double) MAX_VALUE, value, null );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -30,6 +31,8 @@ import javax.swing.event.ChangeEvent;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.tree.*;
|
||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||
import com.formdev.flatlaf.util.Animator;
|
||||
import com.formdev.flatlaf.util.ColorFunctions;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
import net.miginfocom.swing.*;
|
||||
@@ -51,8 +54,7 @@ public class FlatSmoothScrollingTest
|
||||
FlatSmoothScrollingTest() {
|
||||
initComponents();
|
||||
|
||||
ToolTipManager.sharedInstance().setInitialDelay( 0 );
|
||||
ToolTipManager.sharedInstance().setDismissDelay( Integer.MAX_VALUE );
|
||||
initializeDurationAndResolution();
|
||||
|
||||
// allow enabling/disabling smooth scrolling with Alt+S without moving focus to checkbox
|
||||
registerKeyboardAction(
|
||||
@@ -93,13 +95,15 @@ public class FlatSmoothScrollingTest
|
||||
customScrollPane.getHorizontalScrollBar().getModel().addChangeListener( new ScrollBarChangeHandler( customScrollPane, false, "custom horz", Color.pink.darker() ) );
|
||||
|
||||
ArrayList<String> items = new ArrayList<>();
|
||||
for( char ch = '0'; ch < 'z'; ch++ ) {
|
||||
if( (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a') )
|
||||
continue;
|
||||
|
||||
char[] chars = new char[ch - '0' + 1];
|
||||
Arrays.fill( chars, ch );
|
||||
items.add( new String( chars ) );
|
||||
for( int i = 0; i < 10; i++ ) {
|
||||
for( int j = 0; j < 10; j++ ) {
|
||||
char[] chars = new char[i*10 + j + 1];
|
||||
Arrays.fill( chars, ' ' );
|
||||
chars[chars.length - 1] = (char) ('0' + j);
|
||||
if( i >= 5 )
|
||||
chars[50 - 1 - ((i-5)*10) - j] = (char) ('0' + j);
|
||||
items.add( new String( chars ) );
|
||||
}
|
||||
}
|
||||
|
||||
// list model
|
||||
@@ -137,12 +141,10 @@ public class FlatSmoothScrollingTest
|
||||
}
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 4;
|
||||
return (table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF) ? 100 : 2;
|
||||
}
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex ) {
|
||||
if( columnIndex > 0 )
|
||||
rowIndex = (items.size() + rowIndex - ((items.size() / 4) * columnIndex)) % items.size();
|
||||
return items.get( rowIndex );
|
||||
}
|
||||
} );
|
||||
@@ -155,17 +157,49 @@ public class FlatSmoothScrollingTest
|
||||
}
|
||||
|
||||
// text components
|
||||
String longText = items.stream().collect( Collectors.joining( " " ) ) + ' '
|
||||
+ items.stream().limit( 20 ).collect( Collectors.joining( " " ) );
|
||||
String longText = "";
|
||||
for( int i = 0; i < 100; i++ )
|
||||
longText += String.format( "%-5d ", i );
|
||||
longText += "100";
|
||||
String text = items.stream().collect( Collectors.joining( "\n" ) ) + '\n';
|
||||
textArea.setText( longText + '\n' + text );
|
||||
textPane.setText( text );
|
||||
editorPane.setText( text );
|
||||
|
||||
// move selection to beginning in text components
|
||||
textArea.select( 0, 0 );
|
||||
textPane.select( 0, 0 );
|
||||
editorPane.select( 0, 0 );
|
||||
|
||||
// custom scrollable
|
||||
StringBuilder buf = new StringBuilder()
|
||||
.append( "<html>" )
|
||||
.append( customButton.getText() );
|
||||
for( String item : items ) {
|
||||
buf.append( "<br>" );
|
||||
for( int i = 0; i < item.length(); i++ ) {
|
||||
char ch = item.charAt( i );
|
||||
if( ch == ' ' )
|
||||
buf.append( " " );
|
||||
else
|
||||
buf.append( ch );
|
||||
}
|
||||
}
|
||||
buf.append( "</html>" );
|
||||
customButton.setText( buf.toString() );
|
||||
|
||||
// line chart
|
||||
lineChartPanel.addMethodHighlight( JViewport.class.getName() + ".setViewPosition", "#0000bb" );
|
||||
lineChartPanel.addMethodHighlight( JViewport.class.getName() + ".scrollRectToVisible", "#00bbbb" );
|
||||
lineChartPanel.addMethodHighlight( JScrollBar.class.getName() + ".setValue", "#00aa00" );
|
||||
lineChartPanel.addMethodHighlight( Animator.class.getName() + ".timingEvent", "#bb0000" );
|
||||
lineChartPanel.addMethodHighlight( JComponent.class.getName() + ".processKeyBinding", "#bb0000" );
|
||||
lineChartPanel.addMethodHighlight( Component.class.getName() + ".processMouseEvent", "#bb0000" );
|
||||
lineChartPanel.addMethodHighlight( Component.class.getName() + ".processMouseWheelEvent", "#bb0000" );
|
||||
lineChartPanel.addMethodHighlight( Component.class.getName() + ".processMouseMotionEvent", "#bb0000" );
|
||||
lineChartPanel.addMethodHighlight( "actionPerformed", "#bbbb00" );
|
||||
|
||||
// request focus for list
|
||||
EventQueue.invokeLater( () -> {
|
||||
EventQueue.invokeLater( () -> {
|
||||
list.requestFocusInWindow();
|
||||
@@ -177,6 +211,82 @@ public class FlatSmoothScrollingTest
|
||||
UIManager.put( "ScrollPane.smoothScrolling", smoothScrollingCheckBox.isSelected() );
|
||||
}
|
||||
|
||||
private void initializeDurationAndResolution() {
|
||||
int duration = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.duration", 200 );
|
||||
int resolution = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.resolution", 10 );
|
||||
|
||||
durationSlider.setValue( duration );
|
||||
resolutionSlider.setValue( resolution );
|
||||
|
||||
updateDurationAndResolutionLabels( duration, resolution );
|
||||
}
|
||||
|
||||
private void durationOrResolutionChanged() {
|
||||
int duration = durationSlider.getValue();
|
||||
int resolution = resolutionSlider.getValue();
|
||||
|
||||
updateDurationAndResolutionLabels( duration, resolution );
|
||||
|
||||
UIManager.put( "ScrollPane.smoothScrolling.duration", duration );
|
||||
UIManager.put( "ScrollPane.smoothScrolling.resolution", resolution );
|
||||
|
||||
// update UI of scroll bars to force re-creation of animator
|
||||
JScrollPane[] scrollPanes = { listScrollPane, treeScrollPane, tableScrollPane,
|
||||
textAreaScrollPane, textPaneScrollPane, editorPaneScrollPane, customScrollPane };
|
||||
for( JScrollPane scrollPane : scrollPanes ) {
|
||||
scrollPane.getVerticalScrollBar().updateUI();
|
||||
scrollPane.getHorizontalScrollBar().updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDurationAndResolutionLabels( int duration, int resolution ) {
|
||||
durationValueLabel.setText( duration + " ms" );
|
||||
resolutionValueLabel.setText( resolution + " ms" );
|
||||
}
|
||||
|
||||
private void scrollToChanged() {
|
||||
if( scrollToSlider.getValueIsAdjusting() )
|
||||
return;
|
||||
|
||||
int value = scrollToSlider.getValue();
|
||||
JComponent[] comps = { list, tree, table, textArea, textPane, editorPane, customButton };
|
||||
for( JComponent c : comps ) {
|
||||
int x = (c.getWidth() * value) / 100;
|
||||
int y = (c.getHeight() * value) / 100;
|
||||
c.scrollRectToVisible( new Rectangle( x, y, 1, 1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void rowHeaderChanged() {
|
||||
JTable rowHeader = null;
|
||||
if( rowHeaderCheckBox.isSelected() ) {
|
||||
rowHeader = new JTable();
|
||||
rowHeader.setPreferredScrollableViewportSize( new Dimension( UIScale.scale( 50 ), 100 ) );
|
||||
rowHeader.setModel( new AbstractTableModel() {
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return table.getRowCount();
|
||||
}
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 1;
|
||||
}
|
||||
@Override
|
||||
public Object getValueAt( int rowIndex, int columnIndex ) {
|
||||
char[] chars = new char[10];
|
||||
Arrays.fill( chars, ' ' );
|
||||
int i = rowIndex % 10;
|
||||
if( (rowIndex / 10) % 2 == 0 )
|
||||
chars[i] = (char) ('0' + i);
|
||||
else
|
||||
chars[9 - i] = (char) ('A' + i);
|
||||
return new String( chars );
|
||||
}
|
||||
} );
|
||||
}
|
||||
tableScrollPane.setRowHeaderView( rowHeader );
|
||||
}
|
||||
|
||||
private void showTableGridChanged() {
|
||||
boolean showGrid = showTableGridCheckBox.isSelected();
|
||||
table.setShowHorizontalLines( showGrid );
|
||||
@@ -187,6 +297,7 @@ public class FlatSmoothScrollingTest
|
||||
|
||||
private void autoResizeModeChanged() {
|
||||
table.setAutoResizeMode( autoResizeModeCheckBox.isSelected() ? JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS : JTable.AUTO_RESIZE_OFF );
|
||||
((AbstractTableModel)table.getModel()).fireTableStructureChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,12 +312,20 @@ public class FlatSmoothScrollingTest
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
smoothScrollingCheckBox = new JCheckBox();
|
||||
JPanel hSpacer1 = new JPanel(null);
|
||||
JLabel durationLabel = new JLabel();
|
||||
durationSlider = new JSlider();
|
||||
durationValueLabel = new JLabel();
|
||||
JLabel resolutionLabel = new JLabel();
|
||||
resolutionSlider = new JSlider();
|
||||
resolutionValueLabel = new JLabel();
|
||||
splitPane1 = new JSplitPane();
|
||||
splitPane2 = new JSplitPane();
|
||||
panel1 = new JPanel();
|
||||
listLabel = new JLabel();
|
||||
treeLabel = new JLabel();
|
||||
tableLabel = new JLabel();
|
||||
rowHeaderCheckBox = new JCheckBox();
|
||||
showTableGridCheckBox = new JCheckBox();
|
||||
autoResizeModeCheckBox = new JCheckBox();
|
||||
listScrollPane = new FlatSmoothScrollingTest.DebugScrollPane();
|
||||
@@ -215,6 +334,7 @@ public class FlatSmoothScrollingTest
|
||||
tree = new JTree();
|
||||
tableScrollPane = new FlatSmoothScrollingTest.DebugScrollPane();
|
||||
table = new JTable();
|
||||
scrollToSlider = new JSlider();
|
||||
panel2 = new JPanel();
|
||||
textAreaLabel = new JLabel();
|
||||
textPaneLabel = new JLabel();
|
||||
@@ -227,7 +347,7 @@ public class FlatSmoothScrollingTest
|
||||
editorPaneScrollPane = new FlatSmoothScrollingTest.DebugScrollPane();
|
||||
editorPane = new JEditorPane();
|
||||
customScrollPane = new FlatSmoothScrollingTest.DebugScrollPane();
|
||||
button1 = new JButton();
|
||||
customButton = new JButton();
|
||||
lineChartPanel = new LineChartPanel();
|
||||
|
||||
//======== this ========
|
||||
@@ -245,6 +365,41 @@ public class FlatSmoothScrollingTest
|
||||
smoothScrollingCheckBox.setMnemonic('S');
|
||||
smoothScrollingCheckBox.addActionListener(e -> smoothScrollingChanged());
|
||||
add(smoothScrollingCheckBox, "cell 0 0,alignx left,growx 0");
|
||||
add(hSpacer1, "cell 0 0,growx");
|
||||
|
||||
//---- durationLabel ----
|
||||
durationLabel.setText("Duration:");
|
||||
add(durationLabel, "cell 0 0");
|
||||
|
||||
//---- durationSlider ----
|
||||
durationSlider.setMaximum(5000);
|
||||
durationSlider.setValue(200);
|
||||
durationSlider.setSnapToTicks(true);
|
||||
durationSlider.setMinimum(100);
|
||||
durationSlider.setMinorTickSpacing(50);
|
||||
durationSlider.addChangeListener(e -> durationOrResolutionChanged());
|
||||
add(durationSlider, "cell 0 0");
|
||||
|
||||
//---- durationValueLabel ----
|
||||
durationValueLabel.setText("0000 ms");
|
||||
add(durationValueLabel, "cell 0 0,width 50");
|
||||
|
||||
//---- resolutionLabel ----
|
||||
resolutionLabel.setText("Resolution:");
|
||||
add(resolutionLabel, "cell 0 0");
|
||||
|
||||
//---- resolutionSlider ----
|
||||
resolutionSlider.setMaximum(1000);
|
||||
resolutionSlider.setMinimum(10);
|
||||
resolutionSlider.setValue(10);
|
||||
resolutionSlider.setMinorTickSpacing(10);
|
||||
resolutionSlider.setSnapToTicks(true);
|
||||
resolutionSlider.addChangeListener(e -> durationOrResolutionChanged());
|
||||
add(resolutionSlider, "cell 0 0");
|
||||
|
||||
//---- resolutionValueLabel ----
|
||||
resolutionValueLabel.setText("0000 ms");
|
||||
add(resolutionValueLabel, "cell 0 0,width 50");
|
||||
|
||||
//======== splitPane1 ========
|
||||
{
|
||||
@@ -264,7 +419,8 @@ public class FlatSmoothScrollingTest
|
||||
"[200,grow,fill]" +
|
||||
"[200,grow,fill]" +
|
||||
"[200,grow,fill]" +
|
||||
"[200,grow,fill]",
|
||||
"[200,grow,fill]" +
|
||||
"[fill]",
|
||||
// rows
|
||||
"[]0" +
|
||||
"[200,grow,fill]"));
|
||||
@@ -284,6 +440,11 @@ public class FlatSmoothScrollingTest
|
||||
tableLabel.setHorizontalTextPosition(SwingConstants.LEADING);
|
||||
panel1.add(tableLabel, "cell 2 0 2 1");
|
||||
|
||||
//---- rowHeaderCheckBox ----
|
||||
rowHeaderCheckBox.setText("Row header");
|
||||
rowHeaderCheckBox.addActionListener(e -> rowHeaderChanged());
|
||||
panel1.add(rowHeaderCheckBox, "cell 2 0 2 1,alignx right,growx 0");
|
||||
|
||||
//---- showTableGridCheckBox ----
|
||||
showTableGridCheckBox.setText("Show table grid");
|
||||
showTableGridCheckBox.setMnemonic('G');
|
||||
@@ -313,6 +474,13 @@ public class FlatSmoothScrollingTest
|
||||
tableScrollPane.setViewportView(table);
|
||||
}
|
||||
panel1.add(tableScrollPane, "cell 2 1 2 1,width 100,height 100");
|
||||
|
||||
//---- scrollToSlider ----
|
||||
scrollToSlider.setOrientation(SwingConstants.VERTICAL);
|
||||
scrollToSlider.setValue(0);
|
||||
scrollToSlider.setInverted(true);
|
||||
scrollToSlider.addChangeListener(e -> scrollToChanged());
|
||||
panel1.add(scrollToSlider, "cell 4 1");
|
||||
}
|
||||
splitPane2.setTopComponent(panel1);
|
||||
|
||||
@@ -369,12 +537,11 @@ public class FlatSmoothScrollingTest
|
||||
//======== customScrollPane ========
|
||||
{
|
||||
|
||||
//---- button1 ----
|
||||
button1.setText("I'm a large button, but do not implement Scrollable interface");
|
||||
button1.setPreferredSize(new Dimension(800, 800));
|
||||
button1.setHorizontalAlignment(SwingConstants.LEADING);
|
||||
button1.setVerticalAlignment(SwingConstants.TOP);
|
||||
customScrollPane.setViewportView(button1);
|
||||
//---- customButton ----
|
||||
customButton.setText("I'm a large button, but do not implement Scrollable interface");
|
||||
customButton.setHorizontalAlignment(SwingConstants.LEADING);
|
||||
customButton.setVerticalAlignment(SwingConstants.TOP);
|
||||
customScrollPane.setViewportView(customButton);
|
||||
}
|
||||
panel2.add(customScrollPane, "cell 3 1");
|
||||
}
|
||||
@@ -394,12 +561,17 @@ public class FlatSmoothScrollingTest
|
||||
|
||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||
private JCheckBox smoothScrollingCheckBox;
|
||||
private JSlider durationSlider;
|
||||
private JLabel durationValueLabel;
|
||||
private JSlider resolutionSlider;
|
||||
private JLabel resolutionValueLabel;
|
||||
private JSplitPane splitPane1;
|
||||
private JSplitPane splitPane2;
|
||||
private JPanel panel1;
|
||||
private JLabel listLabel;
|
||||
private JLabel treeLabel;
|
||||
private JLabel tableLabel;
|
||||
private JCheckBox rowHeaderCheckBox;
|
||||
private JCheckBox showTableGridCheckBox;
|
||||
private JCheckBox autoResizeModeCheckBox;
|
||||
private FlatSmoothScrollingTest.DebugScrollPane listScrollPane;
|
||||
@@ -408,6 +580,7 @@ public class FlatSmoothScrollingTest
|
||||
private JTree tree;
|
||||
private FlatSmoothScrollingTest.DebugScrollPane tableScrollPane;
|
||||
private JTable table;
|
||||
private JSlider scrollToSlider;
|
||||
private JPanel panel2;
|
||||
private JLabel textAreaLabel;
|
||||
private JLabel textPaneLabel;
|
||||
@@ -420,7 +593,7 @@ public class FlatSmoothScrollingTest
|
||||
private FlatSmoothScrollingTest.DebugScrollPane editorPaneScrollPane;
|
||||
private JEditorPane editorPane;
|
||||
private FlatSmoothScrollingTest.DebugScrollPane customScrollPane;
|
||||
private JButton button1;
|
||||
private JButton customButton;
|
||||
private LineChartPanel lineChartPanel;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
@@ -433,6 +606,7 @@ public class FlatSmoothScrollingTest
|
||||
private final Color chartColor; // for smooth scrolling
|
||||
private final Color chartColor2; // for non-smooth scrolling
|
||||
private int count;
|
||||
private int lastValue;
|
||||
private long lastTime;
|
||||
|
||||
ScrollBarChangeHandler( DebugScrollPane scrollPane, boolean vertical, String name, Color chartColor ) {
|
||||
@@ -442,20 +616,27 @@ public class FlatSmoothScrollingTest
|
||||
|
||||
// add change listener to viewport that is invoked from JViewport.setViewPosition()
|
||||
scrollPane.getViewport().addChangeListener( e -> {
|
||||
// add dot to chart if blit scroll mode is disabled
|
||||
if( vertical == scrollPane.lastScrollingWasVertical &&
|
||||
scrollPane.getViewport().getScrollMode() != JViewport.BLIT_SCROLL_MODE )
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Point viewPosition = viewport.getViewPosition();
|
||||
|
||||
if( (vertical && viewPosition.y != scrollPane.previousViewPosition.y) ||
|
||||
(!vertical && viewPosition.x != scrollPane.previousViewPosition.x) )
|
||||
{
|
||||
// calculate value from view position because scrollbar value is not yet up-to-date
|
||||
JViewport viewport = scrollPane.getViewport();
|
||||
Point viewPosition = viewport.getViewPosition();
|
||||
Dimension viewSize = viewport.getViewSize();
|
||||
double value = vertical
|
||||
? ((double) viewPosition.y) / (viewSize.height - viewport.getHeight())
|
||||
: ((double) viewPosition.x) / (viewSize.width - viewport.getWidth());
|
||||
int ivalue = vertical ? viewPosition.y : viewPosition.x;
|
||||
|
||||
lineChartPanel.addValue( value, ivalue, true, chartColor, name );
|
||||
// add dot to chart if blit scroll mode is disabled
|
||||
boolean dot = (scrollPane.getViewport().getScrollMode() != JViewport.BLIT_SCROLL_MODE);
|
||||
|
||||
Color color = smoothScrollingCheckBox.isSelected() ? this.chartColor : chartColor2;
|
||||
if( dot )
|
||||
lineChartPanel.addValueWithDot( color, value, ivalue, null, name );
|
||||
else
|
||||
lineChartPanel.addValue( color, value, ivalue, name );
|
||||
}
|
||||
} );
|
||||
}
|
||||
@@ -463,26 +644,25 @@ public class FlatSmoothScrollingTest
|
||||
@Override
|
||||
public void stateChanged( ChangeEvent e ) {
|
||||
DefaultBoundedRangeModel m = (DefaultBoundedRangeModel) e.getSource();
|
||||
boolean smoothScrolling = smoothScrollingCheckBox.isSelected();
|
||||
|
||||
lineChartPanel.addValue( getChartValue( m ), m.getValue(), false,
|
||||
smoothScrolling ? chartColor : chartColor2, name );
|
||||
|
||||
int value = m.getValue();
|
||||
/*
|
||||
double chartValue = (double) (value - m.getMinimum()) / (double) (m.getMaximum() - m.getExtent());
|
||||
lineChartPanel.addValue( chartValue, value, false, false,
|
||||
smoothScrollingCheckBox.isSelected() ? chartColor : chartColor2, name );
|
||||
*/
|
||||
long t = System.nanoTime() / 1000000;
|
||||
|
||||
System.out.printf( "%s (%d): %4d %3d ms %b%n",
|
||||
System.out.printf( "%s (%d): %4d --> %4d %3d ms %-5b %s%n",
|
||||
name, ++count,
|
||||
m.getValue(),
|
||||
lastValue,
|
||||
value,
|
||||
t - lastTime,
|
||||
m.getValueIsAdjusting() );
|
||||
m.getValueIsAdjusting(),
|
||||
value > lastValue ? "down" : value < lastValue ? "up" : "" );
|
||||
|
||||
lastValue = value;
|
||||
lastTime = t;
|
||||
}
|
||||
|
||||
private double getChartValue( BoundedRangeModel m ) {
|
||||
int value = m.getValue();
|
||||
return (double) (value - m.getMinimum()) / (double) (m.getMaximum() - m.getExtent());
|
||||
}
|
||||
}
|
||||
|
||||
//---- class DebugViewport ------------------------------------------------
|
||||
@@ -490,7 +670,7 @@ public class FlatSmoothScrollingTest
|
||||
private static class DebugScrollPane
|
||||
extends JScrollPane
|
||||
{
|
||||
boolean lastScrollingWasVertical;
|
||||
Point previousViewPosition = new Point();
|
||||
|
||||
@Override
|
||||
protected JViewport createViewport() {
|
||||
@@ -504,34 +684,11 @@ public class FlatSmoothScrollingTest
|
||||
|
||||
@Override
|
||||
public void setViewPosition( Point p ) {
|
||||
// remember whether scrolling vertically or horizontally
|
||||
Component view = getView();
|
||||
if( view != null ) {
|
||||
int oldY = (view instanceof JComponent)
|
||||
? ((JComponent) view).getY()
|
||||
: view.getBounds().y;
|
||||
|
||||
int newY = -p.y;
|
||||
lastScrollingWasVertical = (oldY != newY);
|
||||
} else
|
||||
lastScrollingWasVertical = true;
|
||||
// remember previous view position
|
||||
previousViewPosition = getViewPosition();
|
||||
|
||||
super.setViewPosition( p );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint( Graphics g ) {
|
||||
super.paint( g );
|
||||
|
||||
if( backingStoreImage != null ) {
|
||||
System.out.println( "---------------------------------------------" );
|
||||
System.out.println( "WARNING: backingStoreImage was used for painting" );
|
||||
System.out.println( "View: " + getView() );
|
||||
System.out.println( "Clip: " + g.getClipBounds() );
|
||||
new Exception().printStackTrace( System.out );
|
||||
System.out.println( "---------------------------------------------" );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,66 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0,alignx left,growx 0"
|
||||
} )
|
||||
add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) {
|
||||
name: "hSpacer1"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": true
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "durationLabel"
|
||||
"text": "Duration:"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": true
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JSlider" ) {
|
||||
name: "durationSlider"
|
||||
"maximum": 5000
|
||||
"value": 200
|
||||
"snapToTicks": true
|
||||
"minimum": 100
|
||||
"minorTickSpacing": 50
|
||||
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "durationOrResolutionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "durationValueLabel"
|
||||
"text": "0000 ms"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0,width 50"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "resolutionLabel"
|
||||
"text": "Resolution:"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": true
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JSlider" ) {
|
||||
name: "resolutionSlider"
|
||||
"maximum": 1000
|
||||
"minimum": 10
|
||||
"value": 10
|
||||
"minorTickSpacing": 10
|
||||
"snapToTicks": true
|
||||
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "durationOrResolutionChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "resolutionValueLabel"
|
||||
"text": "0000 ms"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 0,width 50"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JSplitPane", new FormLayoutManager( class javax.swing.JSplitPane ) ) {
|
||||
name: "splitPane1"
|
||||
"orientation": 0
|
||||
@@ -27,7 +87,7 @@ new FormModel {
|
||||
"orientation": 0
|
||||
"resizeWeight": 0.5
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$columnConstraints": "[200,grow,fill][200,grow,fill][200,grow,fill][200,grow,fill]"
|
||||
"$columnConstraints": "[200,grow,fill][200,grow,fill][200,grow,fill][200,grow,fill][fill]"
|
||||
"$rowConstraints": "[]0[200,grow,fill]"
|
||||
"$layoutConstraints": "ltr,insets 3,hidemode 3"
|
||||
} ) {
|
||||
@@ -53,6 +113,13 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 0 2 1"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "rowHeaderCheckBox"
|
||||
"text": "Row header"
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "rowHeaderChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 0 2 1,alignx right,growx 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "showTableGridCheckBox"
|
||||
"text": "Show table grid"
|
||||
@@ -97,6 +164,15 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 1 2 1,width 100,height 100"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JSlider" ) {
|
||||
name: "scrollToSlider"
|
||||
"orientation": 1
|
||||
"value": 0
|
||||
"inverted": true
|
||||
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "scrollToChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 4 1"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||
"value": "left"
|
||||
} )
|
||||
@@ -160,9 +236,8 @@ new FormModel {
|
||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatSmoothScrollingTest$DebugScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "customScrollPane"
|
||||
add( new FormComponent( "javax.swing.JButton" ) {
|
||||
name: "button1"
|
||||
name: "customButton"
|
||||
"text": "I'm a large button, but do not implement Scrollable interface"
|
||||
"preferredSize": new java.awt.Dimension( 800, 800 )
|
||||
"horizontalAlignment": 10
|
||||
"verticalAlignment": 1
|
||||
} )
|
||||
|
||||
@@ -61,6 +61,10 @@ class LineChartPanel
|
||||
if( (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && isShowing() )
|
||||
EventQueue.invokeLater( this::clearChart );
|
||||
} );
|
||||
|
||||
// show chart tooltips immediately and forever
|
||||
ToolTipManager.sharedInstance().setInitialDelay( 0 );
|
||||
ToolTipManager.sharedInstance().setDismissDelay( Integer.MAX_VALUE );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,8 +110,24 @@ class LineChartPanel
|
||||
updateChartDelayedCheckBox.setSelected( updateChartDelayed );
|
||||
}
|
||||
|
||||
void addValue( double value, int ivalue, boolean dot, Color chartColor, String name ) {
|
||||
lineChart.addValue( value, ivalue, dot, chartColor, name );
|
||||
void addValue( Color chartColor, double value, int ivalue, String name ) {
|
||||
lineChart.addValue( chartColor, value, ivalue, null, false, name );
|
||||
}
|
||||
|
||||
void addValueWithDot( Color chartColor, double value, int ivalue, Color dotColor, String name ) {
|
||||
if( dotColor == null )
|
||||
dotColor = chartColor;
|
||||
lineChart.addValue( chartColor, value, ivalue, dotColor, false, name );
|
||||
}
|
||||
|
||||
void addDot( Color chartColor, double value, int ivalue, Color dotColor, String name ) {
|
||||
if( dotColor == null )
|
||||
dotColor = chartColor;
|
||||
lineChart.addValue( chartColor, value, ivalue, dotColor, true, name );
|
||||
}
|
||||
|
||||
void addMethodHighlight( String classAndMethod, String highlightColor ) {
|
||||
lineChart.methodHighlightMap.put( classAndMethod, highlightColor );
|
||||
}
|
||||
|
||||
private void oneSecondWidthChanged() {
|
||||
@@ -255,19 +275,22 @@ class LineChartPanel
|
||||
|
||||
private int oneSecondWidth = 1000;
|
||||
private int msPerLineX = 200;
|
||||
private final HashMap<String, String> methodHighlightMap = new HashMap<>();
|
||||
|
||||
private static class Data {
|
||||
final double value;
|
||||
final int ivalue;
|
||||
final boolean dot;
|
||||
final Color dotColor;
|
||||
final boolean dotOnly;
|
||||
final long time; // in milliseconds
|
||||
final String name;
|
||||
final Exception stack;
|
||||
|
||||
Data( double value, int ivalue, boolean dot, long time, String name, Exception stack ) {
|
||||
Data( double value, int ivalue, Color dotColor, boolean dotOnly, long time, String name, Exception stack ) {
|
||||
this.value = value;
|
||||
this.ivalue = ivalue;
|
||||
this.dot = dot;
|
||||
this.dotColor = dotColor;
|
||||
this.dotOnly = dotOnly;
|
||||
this.time = time;
|
||||
this.name = name;
|
||||
this.stack = stack;
|
||||
@@ -276,7 +299,8 @@ class LineChartPanel
|
||||
@Override
|
||||
public String toString() {
|
||||
// for debugging
|
||||
return "value=" + value + ", ivalue=" + ivalue + ", dot=" + dot + ", time=" + time + ", name=" + name;
|
||||
return "value=" + value + ", ivalue=" + ivalue + ", dotColor=" + dotColor
|
||||
+ ", dotOnly=" + dotOnly + ", time=" + time + ", name=" + name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,9 +321,9 @@ class LineChartPanel
|
||||
ToolTipManager.sharedInstance().registerComponent( this );
|
||||
}
|
||||
|
||||
void addValue( double value, int ivalue, boolean dot, Color chartColor, String name ) {
|
||||
void addValue( Color chartColor, double value, int ivalue, Color dotColor, boolean dotOnly, String name ) {
|
||||
List<Data> chartData = color2dataMap.computeIfAbsent( chartColor, k -> new ArrayList<>() );
|
||||
chartData.add( new Data( value, ivalue, dot, System.nanoTime() / 1000000, name, new Exception() ) );
|
||||
chartData.add( new Data( value, ivalue, dotColor, dotOnly, System.nanoTime() / 1000000, name, new Exception() ) );
|
||||
|
||||
lastUsedChartColor = chartColor;
|
||||
|
||||
@@ -452,12 +476,13 @@ class LineChartPanel
|
||||
lastPoints.add( new Point( dx, dy ) );
|
||||
lastDatas.add( data );
|
||||
|
||||
if( data.dot ) {
|
||||
if( data.dotColor != null ) {
|
||||
int s1 = (int) Math.round( UIScale.scale( 1 ) * scaleFactor );
|
||||
int s3 = (int) Math.round( UIScale.scale( 3 ) * scaleFactor );
|
||||
g.setColor( chartColor );
|
||||
g.setColor( data.dotColor );
|
||||
g.fillRect( dx - s1, dy - s1, s3, s3 );
|
||||
continue;
|
||||
if( data.dotOnly )
|
||||
continue;
|
||||
}
|
||||
|
||||
if( !newSeq ) {
|
||||
@@ -479,7 +504,7 @@ class LineChartPanel
|
||||
int stage = 0;
|
||||
for( int j = i + 1; j < size && stage <= 2 && !isTemporaryValue; j++ ) {
|
||||
Data nextData = chartData.get( j );
|
||||
if( nextData.dot )
|
||||
if( nextData.dotOnly )
|
||||
continue; // ignore dots
|
||||
|
||||
// check whether next data point is within 10 milliseconds
|
||||
@@ -592,7 +617,7 @@ class LineChartPanel
|
||||
|
||||
Data data = lastDatas.get( i );
|
||||
buf.append( "<h2>" );
|
||||
if( data.dot )
|
||||
if( data.dotOnly )
|
||||
buf.append( "DOT: " );
|
||||
buf.append( data.name ).append( ' ' ).append( data.ivalue ).append( "</h2>" );
|
||||
|
||||
@@ -601,6 +626,7 @@ class LineChartPanel
|
||||
StackTraceElement stackElement = stackTrace[j];
|
||||
String className = stackElement.getClassName();
|
||||
String methodName = stackElement.getMethodName();
|
||||
String classAndMethod = className + '.' + methodName;
|
||||
|
||||
// ignore methods from this class
|
||||
if( className.startsWith( LineChartPanel.class.getName() ) )
|
||||
@@ -614,11 +640,24 @@ class LineChartPanel
|
||||
}
|
||||
j += repeatCount;
|
||||
|
||||
String highlight = methodHighlightMap.get( classAndMethod );
|
||||
if( highlight == null )
|
||||
highlight = methodHighlightMap.get( className );
|
||||
if( highlight == null )
|
||||
highlight = methodHighlightMap.get( methodName );
|
||||
if( highlight != null )
|
||||
buf.append( "<span color=\"" ).append( highlight ).append( "\">" );
|
||||
|
||||
// append method
|
||||
buf.append( className )
|
||||
.append( ".<b>" )
|
||||
.append( methodName )
|
||||
.append( "</b> <span color=\"#888888\">" );
|
||||
.append( "</b>" );
|
||||
if( highlight != null )
|
||||
buf.append( "</span>" );
|
||||
|
||||
// append source
|
||||
buf.append( " <span color=\"#888888\">" );
|
||||
if( stackElement.getFileName() != null ) {
|
||||
buf.append( '(' );
|
||||
buf.append( stackElement.getFileName() );
|
||||
@@ -628,14 +667,19 @@ class LineChartPanel
|
||||
} else
|
||||
buf.append( "(Unknown Source)" );
|
||||
buf.append( "</span>" );
|
||||
|
||||
// append repeat count
|
||||
if( repeatCount > 0 )
|
||||
buf.append( " <b>" ).append( repeatCount + 1 ).append( "x</b>" );
|
||||
buf.append( "<br>" );
|
||||
|
||||
// break at some methods to make stack smaller
|
||||
if( (className.startsWith( "java.awt.event.InvocationEvent" ) && methodName.equals( "dispatch" )) ||
|
||||
(className.startsWith( "java.awt.Component" ) && methodName.equals( "processMouseWheelEvent" )) ||
|
||||
(className.startsWith( "javax.swing.JComponent" ) && methodName.equals( "processKeyBinding" )) )
|
||||
if( classAndMethod.equals( "java.awt.event.InvocationEvent.dispatch" ) ||
|
||||
classAndMethod.equals( "java.awt.Component.processMouseEvent" ) ||
|
||||
classAndMethod.equals( "java.awt.Component.processMouseWheelEvent" ) ||
|
||||
classAndMethod.equals( "java.awt.Component.processMouseMotionEvent" ) ||
|
||||
classAndMethod.equals( "javax.swing.JComponent.processKeyBinding" ) ||
|
||||
classAndMethod.equals( "com.formdev.flatlaf.util.Animator.timingEvent" ) )
|
||||
break;
|
||||
}
|
||||
buf.append( "..." );
|
||||
|
||||
Reference in New Issue
Block a user