mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
FlatSmoothScrollingTest: refactored line chart panel into own class for easier use in other test apps
This commit is contained in:
@@ -21,7 +21,6 @@ import java.awt.event.MouseWheelEvent;
|
|||||||
import java.awt.event.MouseWheelListener;
|
import java.awt.event.MouseWheelListener;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.border.*;
|
import javax.swing.border.*;
|
||||||
import com.formdev.flatlaf.testing.FlatSmoothScrollingTest.LineChartPanel;
|
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
import com.formdev.flatlaf.util.Animator;
|
import com.formdev.flatlaf.util.Animator;
|
||||||
import com.formdev.flatlaf.util.CubicBezierEasing;
|
import com.formdev.flatlaf.util.CubicBezierEasing;
|
||||||
@@ -46,9 +45,6 @@ public class FlatAnimatorTest
|
|||||||
FlatAnimatorTest() {
|
FlatAnimatorTest() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
updateChartDelayedChanged();
|
|
||||||
|
|
||||||
lineChartPanel.setOneSecondWidth( 500 );
|
|
||||||
mouseWheelTestPanel.lineChartPanel = lineChartPanel;
|
mouseWheelTestPanel.lineChartPanel = lineChartPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,14 +78,6 @@ public class FlatAnimatorTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateChartDelayedChanged() {
|
|
||||||
lineChartPanel.setUpdateDelayed( updateChartDelayedCheckBox.isSelected() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearChart() {
|
|
||||||
lineChartPanel.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initComponents() {
|
private void initComponents() {
|
||||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||||
JLabel linearLabel = new JLabel();
|
JLabel linearLabel = new JLabel();
|
||||||
@@ -99,11 +87,7 @@ public class FlatAnimatorTest
|
|||||||
startButton = new JButton();
|
startButton = new JButton();
|
||||||
JLabel mouseWheelTestLabel = new JLabel();
|
JLabel mouseWheelTestLabel = new JLabel();
|
||||||
mouseWheelTestPanel = new FlatAnimatorTest.MouseWheelTestPanel();
|
mouseWheelTestPanel = new FlatAnimatorTest.MouseWheelTestPanel();
|
||||||
JScrollPane lineChartScrollPane = new JScrollPane();
|
lineChartPanel = new LineChartPanel();
|
||||||
lineChartPanel = new FlatSmoothScrollingTest.LineChartPanel();
|
|
||||||
JLabel lineChartInfoLabel = new JLabel();
|
|
||||||
updateChartDelayedCheckBox = new JCheckBox();
|
|
||||||
JButton clearChartButton = new JButton();
|
|
||||||
|
|
||||||
//======== this ========
|
//======== this ========
|
||||||
setLayout(new MigLayout(
|
setLayout(new MigLayout(
|
||||||
@@ -116,8 +100,7 @@ public class FlatAnimatorTest
|
|||||||
"[]" +
|
"[]" +
|
||||||
"[]para" +
|
"[]para" +
|
||||||
"[top]" +
|
"[top]" +
|
||||||
"[400,grow,fill]" +
|
"[400,grow,fill]"));
|
||||||
"[]"));
|
|
||||||
|
|
||||||
//---- linearLabel ----
|
//---- linearLabel ----
|
||||||
linearLabel.setText("Linear:");
|
linearLabel.setText("Linear:");
|
||||||
@@ -150,28 +133,9 @@ public class FlatAnimatorTest
|
|||||||
mouseWheelTestPanel.setBorder(new LineBorder(Color.red));
|
mouseWheelTestPanel.setBorder(new LineBorder(Color.red));
|
||||||
add(mouseWheelTestPanel, "cell 1 3,height 100");
|
add(mouseWheelTestPanel, "cell 1 3,height 100");
|
||||||
|
|
||||||
//======== lineChartScrollPane ========
|
//---- lineChartPanel ----
|
||||||
{
|
lineChartPanel.setUpdateChartDelayed(false);
|
||||||
lineChartScrollPane.putClientProperty("JScrollPane.smoothScrolling", false);
|
add(lineChartPanel, "cell 0 4 2 1");
|
||||||
lineChartScrollPane.setViewportView(lineChartPanel);
|
|
||||||
}
|
|
||||||
add(lineChartScrollPane, "cell 0 4 2 1");
|
|
||||||
|
|
||||||
//---- lineChartInfoLabel ----
|
|
||||||
lineChartInfoLabel.setText("X: time (500ms per line) / Y: value (10% per line)");
|
|
||||||
add(lineChartInfoLabel, "cell 0 5 2 1");
|
|
||||||
|
|
||||||
//---- updateChartDelayedCheckBox ----
|
|
||||||
updateChartDelayedCheckBox.setText("Update chart delayed");
|
|
||||||
updateChartDelayedCheckBox.setMnemonic('U');
|
|
||||||
updateChartDelayedCheckBox.addActionListener(e -> updateChartDelayedChanged());
|
|
||||||
add(updateChartDelayedCheckBox, "cell 0 5 2 1,alignx right,growx 0");
|
|
||||||
|
|
||||||
//---- clearChartButton ----
|
|
||||||
clearChartButton.setText("Clear Chart");
|
|
||||||
clearChartButton.setMnemonic('C');
|
|
||||||
clearChartButton.addActionListener(e -> clearChart());
|
|
||||||
add(clearChartButton, "cell 0 5 2 1,alignx right,growx 0");
|
|
||||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,8 +144,7 @@ public class FlatAnimatorTest
|
|||||||
private JScrollBar easeInOutScrollBar;
|
private JScrollBar easeInOutScrollBar;
|
||||||
private JButton startButton;
|
private JButton startButton;
|
||||||
private FlatAnimatorTest.MouseWheelTestPanel mouseWheelTestPanel;
|
private FlatAnimatorTest.MouseWheelTestPanel mouseWheelTestPanel;
|
||||||
private FlatSmoothScrollingTest.LineChartPanel lineChartPanel;
|
private LineChartPanel lineChartPanel;
|
||||||
private JCheckBox updateChartDelayedCheckBox;
|
|
||||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
|
|
||||||
//---- class MouseWheelTestPanel ------------------------------------------
|
//---- class MouseWheelTestPanel ------------------------------------------
|
||||||
@@ -217,7 +180,7 @@ public class FlatAnimatorTest
|
|||||||
value = startValue + Math.round( (targetValue - startValue) * fraction );
|
value = startValue + Math.round( (targetValue - startValue) * fraction );
|
||||||
valueLabel.setText( String.valueOf( value ) );
|
valueLabel.setText( String.valueOf( value ) );
|
||||||
|
|
||||||
lineChartPanel.addValue( value / (double) MAX_VALUE, false, Color.red, null );
|
lineChartPanel.addValue( value / (double) MAX_VALUE, value, false, Color.red, null );
|
||||||
}, () -> {
|
}, () -> {
|
||||||
targetValue = -1;
|
targetValue = -1;
|
||||||
} );
|
} );
|
||||||
@@ -235,7 +198,7 @@ public class FlatAnimatorTest
|
|||||||
// for unprecise wheels the rotation value is usually -1 or +1
|
// for unprecise wheels the rotation value is usually -1 or +1
|
||||||
// for precise wheels the rotation value is in range ca. -10 to +10,
|
// for precise wheels the rotation value is in range ca. -10 to +10,
|
||||||
// depending how fast the wheel is rotated
|
// depending how fast the wheel is rotated
|
||||||
lineChartPanel.addValue( 0.5 + (preciseWheelRotation / 20.), true, Color.red, null );
|
lineChartPanel.addValue( 0.5 + (preciseWheelRotation / 20.), (int) (preciseWheelRotation * 1000), true, Color.red, null );
|
||||||
|
|
||||||
// increase/decrease target value if animation is in progress
|
// increase/decrease target value if animation is in progress
|
||||||
int newValue = (int) ((targetValue < 0 ? value : targetValue) + (STEP * preciseWheelRotation));
|
int newValue = (int) ((targetValue < 0 ? value : targetValue) + (STEP * preciseWheelRotation));
|
||||||
@@ -252,7 +215,7 @@ public class FlatAnimatorTest
|
|||||||
value = newValue;
|
value = newValue;
|
||||||
valueLabel.setText( String.valueOf( value ) );
|
valueLabel.setText( String.valueOf( value ) );
|
||||||
|
|
||||||
lineChartPanel.addValue( value / (double) MAX_VALUE, false, Color.red, null );
|
lineChartPanel.addValue( value / (double) MAX_VALUE, value, false, Color.red, null );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8"
|
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
|
||||||
|
|
||||||
new FormModel {
|
new FormModel {
|
||||||
contentType: "form/swing"
|
contentType: "form/swing"
|
||||||
@@ -9,7 +9,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[fill][grow,fill]"
|
"$columnConstraints": "[fill][grow,fill]"
|
||||||
"$rowConstraints": "[][][]para[top][400,grow,fill][]"
|
"$rowConstraints": "[][][]para[top][400,grow,fill]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "this"
|
name: "this"
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
@@ -69,42 +69,14 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 3,height 100"
|
"value": "cell 1 3,height 100"
|
||||||
} )
|
} )
|
||||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
add( new FormComponent( "com.formdev.flatlaf.testing.LineChartPanel" ) {
|
||||||
name: "lineChartScrollPane"
|
name: "lineChartPanel"
|
||||||
"$client.JScrollPane.smoothScrolling": false
|
"updateChartDelayed": false
|
||||||
add( new FormComponent( "com.formdev.flatlaf.testing.FlatSmoothScrollingTest$LineChartPanel" ) {
|
|
||||||
name: "lineChartPanel"
|
|
||||||
auxiliary() {
|
|
||||||
"JavaCodeGenerator.variableLocal": false
|
|
||||||
}
|
|
||||||
} )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 4 2 1"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
|
||||||
name: "lineChartInfoLabel"
|
|
||||||
"text": "X: time (500ms per line) / Y: value (10% per line)"
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 5 2 1"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
|
||||||
name: "updateChartDelayedCheckBox"
|
|
||||||
"text": "Update chart delayed"
|
|
||||||
"mnemonic": 85
|
|
||||||
auxiliary() {
|
auxiliary() {
|
||||||
"JavaCodeGenerator.variableLocal": false
|
"JavaCodeGenerator.variableLocal": false
|
||||||
}
|
}
|
||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "updateChartDelayedChanged", false ) )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 5 2 1,alignx right,growx 0"
|
"value": "cell 0 4 2 1"
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JButton" ) {
|
|
||||||
name: "clearChartButton"
|
|
||||||
"text": "Clear Chart"
|
|
||||||
"mnemonic": 67
|
|
||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "clearChart", false ) )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 5 2 1,alignx right,growx 0"
|
|
||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
|
|||||||
@@ -21,29 +21,16 @@ import java.awt.Component;
|
|||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.event.HierarchyEvent;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.text.MessageFormat;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ChangeEvent;
|
import javax.swing.event.ChangeEvent;
|
||||||
import javax.swing.event.ChangeListener;
|
import javax.swing.event.ChangeListener;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
import javax.swing.tree.*;
|
import javax.swing.tree.*;
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
|
||||||
import com.formdev.flatlaf.ui.FlatUIUtils;
|
|
||||||
import com.formdev.flatlaf.util.ColorFunctions;
|
import com.formdev.flatlaf.util.ColorFunctions;
|
||||||
import com.formdev.flatlaf.util.HSLColor;
|
|
||||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
import net.miginfocom.swing.*;
|
import net.miginfocom.swing.*;
|
||||||
|
|
||||||
@@ -64,9 +51,6 @@ public class FlatSmoothScrollingTest
|
|||||||
FlatSmoothScrollingTest() {
|
FlatSmoothScrollingTest() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
oneSecondWidthChanged();
|
|
||||||
updateChartDelayedChanged();
|
|
||||||
|
|
||||||
ToolTipManager.sharedInstance().setInitialDelay( 0 );
|
ToolTipManager.sharedInstance().setInitialDelay( 0 );
|
||||||
ToolTipManager.sharedInstance().setDismissDelay( Integer.MAX_VALUE );
|
ToolTipManager.sharedInstance().setDismissDelay( Integer.MAX_VALUE );
|
||||||
|
|
||||||
@@ -79,14 +63,6 @@ public class FlatSmoothScrollingTest
|
|||||||
KeyStroke.getKeyStroke( "alt " + (char) smoothScrollingCheckBox.getMnemonic() ),
|
KeyStroke.getKeyStroke( "alt " + (char) smoothScrollingCheckBox.getMnemonic() ),
|
||||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
||||||
|
|
||||||
// allow clearing chart with Alt+C without moving focus to button
|
|
||||||
registerKeyboardAction(
|
|
||||||
e -> {
|
|
||||||
clearChart();
|
|
||||||
},
|
|
||||||
KeyStroke.getKeyStroke( "alt " + (char) clearChartButton.getMnemonic() ),
|
|
||||||
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
|
||||||
|
|
||||||
listLabel.setIcon( new ColorIcon( Color.red.darker() ) );
|
listLabel.setIcon( new ColorIcon( Color.red.darker() ) );
|
||||||
treeLabel.setIcon( new ColorIcon( Color.blue.darker() ) );
|
treeLabel.setIcon( new ColorIcon( Color.blue.darker() ) );
|
||||||
tableLabel.setIcon( new ColorIcon( Color.green.darker() ) );
|
tableLabel.setIcon( new ColorIcon( Color.green.darker() ) );
|
||||||
@@ -116,12 +92,6 @@ public class FlatSmoothScrollingTest
|
|||||||
customScrollPane.getVerticalScrollBar().getModel().addChangeListener( new ScrollBarChangeHandler( customScrollPane, true, "custom vert", Color.pink ) );
|
customScrollPane.getVerticalScrollBar().getModel().addChangeListener( new ScrollBarChangeHandler( customScrollPane, true, "custom vert", Color.pink ) );
|
||||||
customScrollPane.getHorizontalScrollBar().getModel().addChangeListener( new ScrollBarChangeHandler( customScrollPane, false, "custom horz", Color.pink.darker() ) );
|
customScrollPane.getHorizontalScrollBar().getModel().addChangeListener( new ScrollBarChangeHandler( customScrollPane, false, "custom horz", Color.pink.darker() ) );
|
||||||
|
|
||||||
// clear chart on startup
|
|
||||||
addHierarchyListener( e -> {
|
|
||||||
if( (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && isShowing() )
|
|
||||||
EventQueue.invokeLater( this::clearChart );
|
|
||||||
});
|
|
||||||
|
|
||||||
ArrayList<String> items = new ArrayList<>();
|
ArrayList<String> items = new ArrayList<>();
|
||||||
for( char ch = '0'; ch < 'z'; ch++ ) {
|
for( char ch = '0'; ch < 'z'; ch++ ) {
|
||||||
if( (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a') )
|
if( (ch > '9' && ch < 'A') || (ch > 'Z' && ch < 'a') )
|
||||||
@@ -207,33 +177,6 @@ public class FlatSmoothScrollingTest
|
|||||||
UIManager.put( "ScrollPane.smoothScrolling", smoothScrollingCheckBox.isSelected() );
|
UIManager.put( "ScrollPane.smoothScrolling", smoothScrollingCheckBox.isSelected() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void oneSecondWidthChanged() {
|
|
||||||
int oneSecondWidth = oneSecondWidthSlider.getValue();
|
|
||||||
int msPerLineX =
|
|
||||||
oneSecondWidth <= 2000 ? 100 :
|
|
||||||
oneSecondWidth <= 4000 ? 50 :
|
|
||||||
oneSecondWidth <= 8000 ? 25 :
|
|
||||||
10;
|
|
||||||
|
|
||||||
lineChartPanel.setOneSecondWidth( oneSecondWidth );
|
|
||||||
lineChartPanel.setMsPerLineX( msPerLineX );
|
|
||||||
lineChartPanel.revalidate();
|
|
||||||
lineChartPanel.repaint();
|
|
||||||
|
|
||||||
if( xLabelText == null )
|
|
||||||
xLabelText = xLabel.getText();
|
|
||||||
xLabel.setText( MessageFormat.format( xLabelText, msPerLineX ) );
|
|
||||||
}
|
|
||||||
private String xLabelText;
|
|
||||||
|
|
||||||
private void clearChart() {
|
|
||||||
lineChartPanel.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateChartDelayedChanged() {
|
|
||||||
lineChartPanel.setUpdateDelayed( updateChartDelayedCheckBox.isSelected() );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showTableGridChanged() {
|
private void showTableGridChanged() {
|
||||||
boolean showGrid = showTableGridCheckBox.isSelected();
|
boolean showGrid = showTableGridCheckBox.isSelected();
|
||||||
table.setShowHorizontalLines( showGrid );
|
table.setShowHorizontalLines( showGrid );
|
||||||
@@ -285,18 +228,7 @@ public class FlatSmoothScrollingTest
|
|||||||
editorPane = new JEditorPane();
|
editorPane = new JEditorPane();
|
||||||
customScrollPane = new FlatSmoothScrollingTest.DebugScrollPane();
|
customScrollPane = new FlatSmoothScrollingTest.DebugScrollPane();
|
||||||
button1 = new JButton();
|
button1 = new JButton();
|
||||||
panel3 = new JPanel();
|
lineChartPanel = new LineChartPanel();
|
||||||
chartScrollPane = new JScrollPane();
|
|
||||||
lineChartPanel = new FlatSmoothScrollingTest.LineChartPanel();
|
|
||||||
panel4 = new JPanel();
|
|
||||||
xLabel = new JLabel();
|
|
||||||
JLabel rectsLabel = new JLabel();
|
|
||||||
JLabel yLabel = new JLabel();
|
|
||||||
JLabel dotsLabel = new JLabel();
|
|
||||||
JLabel oneSecondWidthLabel = new JLabel();
|
|
||||||
oneSecondWidthSlider = new JSlider();
|
|
||||||
updateChartDelayedCheckBox = new JCheckBox();
|
|
||||||
clearChartButton = new JButton();
|
|
||||||
|
|
||||||
//======== this ========
|
//======== this ========
|
||||||
setLayout(new MigLayout(
|
setLayout(new MigLayout(
|
||||||
@@ -305,8 +237,7 @@ public class FlatSmoothScrollingTest
|
|||||||
"[200,grow,fill]",
|
"[200,grow,fill]",
|
||||||
// rows
|
// rows
|
||||||
"[]" +
|
"[]" +
|
||||||
"[grow,fill]" +
|
"[grow,fill]"));
|
||||||
"[]"));
|
|
||||||
|
|
||||||
//---- smoothScrollingCheckBox ----
|
//---- smoothScrollingCheckBox ----
|
||||||
smoothScrollingCheckBox.setText("Smooth scrolling");
|
smoothScrollingCheckBox.setText("Smooth scrolling");
|
||||||
@@ -451,79 +382,13 @@ public class FlatSmoothScrollingTest
|
|||||||
}
|
}
|
||||||
splitPane1.setTopComponent(splitPane2);
|
splitPane1.setTopComponent(splitPane2);
|
||||||
|
|
||||||
//======== panel3 ========
|
//---- lineChartPanel ----
|
||||||
{
|
lineChartPanel.setLegend1Text("Rectangles: scrollbar values (mouse hover shows stack)");
|
||||||
panel3.setLayout(new MigLayout(
|
lineChartPanel.setLegend2Text("Dots: disabled blitting mode in JViewport");
|
||||||
"insets 3,hidemode 3",
|
lineChartPanel.setLegendYValueText("scroll bar value");
|
||||||
// columns
|
splitPane1.setBottomComponent(lineChartPanel);
|
||||||
"[grow,fill]",
|
|
||||||
// rows
|
|
||||||
"[100:300,grow,fill]"));
|
|
||||||
|
|
||||||
//======== chartScrollPane ========
|
|
||||||
{
|
|
||||||
chartScrollPane.putClientProperty("JScrollPane.smoothScrolling", false);
|
|
||||||
chartScrollPane.setViewportView(lineChartPanel);
|
|
||||||
}
|
|
||||||
panel3.add(chartScrollPane, "cell 0 0");
|
|
||||||
}
|
|
||||||
splitPane1.setBottomComponent(panel3);
|
|
||||||
}
|
}
|
||||||
add(splitPane1, "cell 0 1");
|
add(splitPane1, "cell 0 1");
|
||||||
|
|
||||||
//======== panel4 ========
|
|
||||||
{
|
|
||||||
panel4.setLayout(new MigLayout(
|
|
||||||
"insets 0,hidemode 3,gapy 0",
|
|
||||||
// columns
|
|
||||||
"[fill]para" +
|
|
||||||
"[fill]",
|
|
||||||
// rows
|
|
||||||
"[]" +
|
|
||||||
"[]"));
|
|
||||||
|
|
||||||
//---- xLabel ----
|
|
||||||
xLabel.setText("X: time ({0}ms per line)");
|
|
||||||
panel4.add(xLabel, "cell 0 0");
|
|
||||||
|
|
||||||
//---- rectsLabel ----
|
|
||||||
rectsLabel.setText("Rectangles: scrollbar values (mouse hover shows stack)");
|
|
||||||
panel4.add(rectsLabel, "cell 1 0");
|
|
||||||
|
|
||||||
//---- yLabel ----
|
|
||||||
yLabel.setText("Y: scroll bar value (10% per line)");
|
|
||||||
panel4.add(yLabel, "cell 0 1");
|
|
||||||
|
|
||||||
//---- dotsLabel ----
|
|
||||||
dotsLabel.setText("Dots: disabled blitting mode in JViewport");
|
|
||||||
panel4.add(dotsLabel, "cell 1 1");
|
|
||||||
}
|
|
||||||
add(panel4, "cell 0 2");
|
|
||||||
|
|
||||||
//---- oneSecondWidthLabel ----
|
|
||||||
oneSecondWidthLabel.setText("Scale X:");
|
|
||||||
oneSecondWidthLabel.setDisplayedMnemonic('A');
|
|
||||||
oneSecondWidthLabel.setLabelFor(oneSecondWidthSlider);
|
|
||||||
add(oneSecondWidthLabel, "cell 0 2,alignx right,growx 0");
|
|
||||||
|
|
||||||
//---- oneSecondWidthSlider ----
|
|
||||||
oneSecondWidthSlider.setMinimum(1000);
|
|
||||||
oneSecondWidthSlider.setMaximum(10000);
|
|
||||||
oneSecondWidthSlider.addChangeListener(e -> oneSecondWidthChanged());
|
|
||||||
add(oneSecondWidthSlider, "cell 0 2,alignx right,growx 0,wmax 100");
|
|
||||||
|
|
||||||
//---- updateChartDelayedCheckBox ----
|
|
||||||
updateChartDelayedCheckBox.setText("Update chart delayed");
|
|
||||||
updateChartDelayedCheckBox.setMnemonic('P');
|
|
||||||
updateChartDelayedCheckBox.setSelected(true);
|
|
||||||
updateChartDelayedCheckBox.addActionListener(e -> updateChartDelayedChanged());
|
|
||||||
add(updateChartDelayedCheckBox, "cell 0 2,alignx right,growx 0");
|
|
||||||
|
|
||||||
//---- clearChartButton ----
|
|
||||||
clearChartButton.setText("Clear Chart");
|
|
||||||
clearChartButton.setMnemonic('C');
|
|
||||||
clearChartButton.addActionListener(e -> clearChart());
|
|
||||||
add(clearChartButton, "cell 0 2,alignx right,growx 0");
|
|
||||||
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
// JFormDesigner - End of component initialization //GEN-END:initComponents
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,14 +421,7 @@ public class FlatSmoothScrollingTest
|
|||||||
private JEditorPane editorPane;
|
private JEditorPane editorPane;
|
||||||
private FlatSmoothScrollingTest.DebugScrollPane customScrollPane;
|
private FlatSmoothScrollingTest.DebugScrollPane customScrollPane;
|
||||||
private JButton button1;
|
private JButton button1;
|
||||||
private JPanel panel3;
|
private LineChartPanel lineChartPanel;
|
||||||
private JScrollPane chartScrollPane;
|
|
||||||
private FlatSmoothScrollingTest.LineChartPanel lineChartPanel;
|
|
||||||
private JPanel panel4;
|
|
||||||
private JLabel xLabel;
|
|
||||||
private JSlider oneSecondWidthSlider;
|
|
||||||
private JCheckBox updateChartDelayedCheckBox;
|
|
||||||
private JButton clearChartButton;
|
|
||||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||||
|
|
||||||
//---- class ScrollBarChangeHandler ---------------------------------------
|
//---- class ScrollBarChangeHandler ---------------------------------------
|
||||||
@@ -595,8 +453,9 @@ public class FlatSmoothScrollingTest
|
|||||||
double value = vertical
|
double value = vertical
|
||||||
? ((double) viewPosition.y) / (viewSize.height - viewport.getHeight())
|
? ((double) viewPosition.y) / (viewSize.height - viewport.getHeight())
|
||||||
: ((double) viewPosition.x) / (viewSize.width - viewport.getWidth());
|
: ((double) viewPosition.x) / (viewSize.width - viewport.getWidth());
|
||||||
|
int ivalue = vertical ? viewPosition.y : viewPosition.x;
|
||||||
|
|
||||||
lineChartPanel.addValue( value, true, chartColor, name );
|
lineChartPanel.addValue( value, ivalue, true, chartColor, name );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
@@ -606,7 +465,8 @@ public class FlatSmoothScrollingTest
|
|||||||
DefaultBoundedRangeModel m = (DefaultBoundedRangeModel) e.getSource();
|
DefaultBoundedRangeModel m = (DefaultBoundedRangeModel) e.getSource();
|
||||||
boolean smoothScrolling = smoothScrollingCheckBox.isSelected();
|
boolean smoothScrolling = smoothScrollingCheckBox.isSelected();
|
||||||
|
|
||||||
lineChartPanel.addValue( getChartValue( m ), false, smoothScrolling ? chartColor : chartColor2, name );
|
lineChartPanel.addValue( getChartValue( m ), m.getValue(), false,
|
||||||
|
smoothScrolling ? chartColor : chartColor2, name );
|
||||||
|
|
||||||
long t = System.nanoTime() / 1000000;
|
long t = System.nanoTime() / 1000000;
|
||||||
|
|
||||||
@@ -676,425 +536,6 @@ public class FlatSmoothScrollingTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- class LineChartPanel -----------------------------------------------
|
|
||||||
|
|
||||||
static class LineChartPanel
|
|
||||||
extends JComponent
|
|
||||||
implements Scrollable
|
|
||||||
{
|
|
||||||
private static final int NEW_SEQUENCE_TIME_LAG = 500;
|
|
||||||
private static final int NEW_SEQUENCE_GAP = 100;
|
|
||||||
private static final int HIT_OFFSET = 4;
|
|
||||||
|
|
||||||
private int oneSecondWidth = 1000;
|
|
||||||
private int msPerLineX = 200;
|
|
||||||
|
|
||||||
private static class Data {
|
|
||||||
final double value;
|
|
||||||
final boolean dot;
|
|
||||||
final long time; // in milliseconds
|
|
||||||
final String name;
|
|
||||||
final Exception stack;
|
|
||||||
|
|
||||||
Data( double value, boolean dot, long time, String name, Exception stack ) {
|
|
||||||
this.value = value;
|
|
||||||
this.dot = dot;
|
|
||||||
this.time = time;
|
|
||||||
this.name = name;
|
|
||||||
this.stack = stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
// for debugging
|
|
||||||
return "value=" + value + ", dot=" + dot + ", time=" + time + ", name=" + name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<Color, List<Data>> color2dataMap = new HashMap<>();
|
|
||||||
private final Timer repaintTime;
|
|
||||||
private Color lastUsedChartColor;
|
|
||||||
private boolean updateDelayed;
|
|
||||||
|
|
||||||
private final List<Point> lastPoints = new ArrayList<>();
|
|
||||||
private final List<Data> lastDatas = new ArrayList<>();
|
|
||||||
private double lastSystemScaleFactor = 1;
|
|
||||||
private String lastToolTipPrinted;
|
|
||||||
|
|
||||||
LineChartPanel() {
|
|
||||||
int resolution = FlatUIUtils.getUIInt( "ScrollPane.smoothScrolling.resolution", 10 );
|
|
||||||
|
|
||||||
repaintTime = new Timer( resolution * 2, e -> repaintAndRevalidate() );
|
|
||||||
repaintTime.setRepeats( false );
|
|
||||||
|
|
||||||
ToolTipManager.sharedInstance().registerComponent( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
void addValue( double value, boolean dot, Color chartColor, String name ) {
|
|
||||||
List<Data> chartData = color2dataMap.computeIfAbsent( chartColor, k -> new ArrayList<>() );
|
|
||||||
chartData.add( new Data( value, dot, System.nanoTime() / 1000000, name, new Exception() ) );
|
|
||||||
|
|
||||||
lastUsedChartColor = chartColor;
|
|
||||||
|
|
||||||
if( updateDelayed ) {
|
|
||||||
repaintTime.stop();
|
|
||||||
repaintTime.start();
|
|
||||||
} else
|
|
||||||
repaintAndRevalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
color2dataMap.clear();
|
|
||||||
lastUsedChartColor = null;
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setUpdateDelayed( boolean updateDelayed ) {
|
|
||||||
this.updateDelayed = updateDelayed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOneSecondWidth( int oneSecondWidth ) {
|
|
||||||
this.oneSecondWidth = oneSecondWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMsPerLineX( int msPerLineX ) {
|
|
||||||
this.msPerLineX = msPerLineX;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void repaintAndRevalidate() {
|
|
||||||
repaint();
|
|
||||||
revalidate();
|
|
||||||
|
|
||||||
// scroll horizontally
|
|
||||||
if( lastUsedChartColor != null ) {
|
|
||||||
// compute chart width of last used color and start of last sequence
|
|
||||||
int[] lastSeqX = new int[1];
|
|
||||||
int cw = chartWidth( color2dataMap.get( lastUsedChartColor ), lastSeqX );
|
|
||||||
|
|
||||||
// scroll to end of last sequence (of last used color)
|
|
||||||
int lastSeqWidth = cw - lastSeqX[0];
|
|
||||||
int width = Math.min( lastSeqWidth, getParent().getWidth() );
|
|
||||||
int x = cw - width;
|
|
||||||
scrollRectToVisible( new Rectangle( x, 0, width, getHeight() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void paintComponent( Graphics g ) {
|
|
||||||
Graphics g2 = g.create();
|
|
||||||
try {
|
|
||||||
HiDPIUtils.paintAtScale1x( (Graphics2D) g2, this, this::paintImpl );
|
|
||||||
} finally {
|
|
||||||
g2.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
|
||||||
FlatUIUtils.setRenderingHints( g );
|
|
||||||
|
|
||||||
int oneSecondWidth = (int) (this.oneSecondWidth * scaleFactor);
|
|
||||||
int seqGapWidth = (int) (NEW_SEQUENCE_GAP * scaleFactor);
|
|
||||||
int hitOffset = (int) Math.round( UIScale.scale( HIT_OFFSET ) * scaleFactor );
|
|
||||||
|
|
||||||
Color lineColor = FlatUIUtils.getUIColor( "Component.borderColor", Color.lightGray );
|
|
||||||
Color lineColor2 = FlatLaf.isLafDark()
|
|
||||||
? new HSLColor( lineColor ).adjustTone( 30 )
|
|
||||||
: new HSLColor( lineColor ).adjustShade( 30 );
|
|
||||||
|
|
||||||
g.translate( x, y );
|
|
||||||
|
|
||||||
// fill background
|
|
||||||
g.setColor( UIManager.getColor( "Table.background" ) );
|
|
||||||
g.fillRect( x, y, width, height );
|
|
||||||
|
|
||||||
// paint horizontal lines
|
|
||||||
for( int i = 1; i < 10; i++ ) {
|
|
||||||
int hy = (height * i) / 10;
|
|
||||||
g.setColor( (i != 5) ? lineColor : lineColor2 );
|
|
||||||
g.drawLine( 0, hy, width, hy );
|
|
||||||
}
|
|
||||||
|
|
||||||
// paint vertical lines
|
|
||||||
int perLineXWidth = Math.round( (oneSecondWidth / 1000f) * msPerLineX );
|
|
||||||
for( int i = 1, xv = perLineXWidth; xv < width; xv += perLineXWidth, i++ ) {
|
|
||||||
g.setColor( (i % 5 != 0) ? lineColor : lineColor2 );
|
|
||||||
g.drawLine( xv, 0, xv, height );
|
|
||||||
}
|
|
||||||
|
|
||||||
lastPoints.clear();
|
|
||||||
lastDatas.clear();
|
|
||||||
lastSystemScaleFactor = scaleFactor;
|
|
||||||
|
|
||||||
// paint lines
|
|
||||||
for( Map.Entry<Color, List<Data>> e : color2dataMap.entrySet() ) {
|
|
||||||
List<Data> chartData = e.getValue();
|
|
||||||
Color chartColor = e.getKey();
|
|
||||||
if( FlatLaf.isLafDark() )
|
|
||||||
chartColor = new HSLColor( chartColor ).adjustTone( 50 );
|
|
||||||
Color temporaryValueColor = ColorFunctions.fade( chartColor, FlatLaf.isLafDark() ? 0.7f : 0.3f );
|
|
||||||
Color dataPointColor = ColorFunctions.fade( chartColor, FlatLaf.isLafDark() ? 0.6f : 0.2f );
|
|
||||||
|
|
||||||
// sequence start time and x coordinate
|
|
||||||
long seqTime = 0;
|
|
||||||
int seqX = 0;
|
|
||||||
|
|
||||||
// "previous" data point time, x/y coordinates and count
|
|
||||||
long ptime = 0;
|
|
||||||
int px = 0;
|
|
||||||
int py = 0;
|
|
||||||
int pcount = 0;
|
|
||||||
|
|
||||||
boolean first = true;
|
|
||||||
boolean isTemporaryValue = false;
|
|
||||||
int lastTemporaryValueIndex = -1;
|
|
||||||
|
|
||||||
int size = chartData.size();
|
|
||||||
for( int i = 0; i < size; i++ ) {
|
|
||||||
Data data = chartData.get( i );
|
|
||||||
|
|
||||||
boolean newSeq = (data.time > ptime + NEW_SEQUENCE_TIME_LAG);
|
|
||||||
ptime = data.time;
|
|
||||||
|
|
||||||
if( newSeq ) {
|
|
||||||
// paint short horizontal line for previous sequence that has only one data point
|
|
||||||
if( !first && pcount == 0 ) {
|
|
||||||
g.setColor( chartColor );
|
|
||||||
g.drawLine( px, py, px + (int) Math.round( UIScale.scale( 8 ) * scaleFactor ), py );
|
|
||||||
}
|
|
||||||
|
|
||||||
// start new sequence
|
|
||||||
seqTime = data.time;
|
|
||||||
seqX = !first ? px + seqGapWidth : 0;
|
|
||||||
px = seqX;
|
|
||||||
pcount = 0;
|
|
||||||
first = false;
|
|
||||||
isTemporaryValue = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// x/y coordinates of current data point
|
|
||||||
int dy = (int) ((height - 1) * data.value);
|
|
||||||
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * oneSecondWidth));
|
|
||||||
|
|
||||||
// paint rectangle to indicate data point
|
|
||||||
g.setColor( dataPointColor );
|
|
||||||
g.drawRect( dx - hitOffset, dy - hitOffset, hitOffset * 2, hitOffset * 2 );
|
|
||||||
|
|
||||||
// remember data point for tooltip
|
|
||||||
lastPoints.add( new Point( dx, dy ) );
|
|
||||||
lastDatas.add( data );
|
|
||||||
|
|
||||||
if( data.dot ) {
|
|
||||||
int s1 = (int) Math.round( UIScale.scale( 1 ) * scaleFactor );
|
|
||||||
int s3 = (int) Math.round( UIScale.scale( 3 ) * scaleFactor );
|
|
||||||
g.setColor( chartColor );
|
|
||||||
g.fillRect( dx - s1, dy - s1, s3, s3 );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !newSeq ) {
|
|
||||||
if( isTemporaryValue && i > lastTemporaryValueIndex )
|
|
||||||
isTemporaryValue = false;
|
|
||||||
|
|
||||||
g.setColor( isTemporaryValue ? temporaryValueColor : chartColor );
|
|
||||||
|
|
||||||
// line in sequence
|
|
||||||
g.drawLine( px, py, dx, dy );
|
|
||||||
|
|
||||||
px = dx;
|
|
||||||
pcount++;
|
|
||||||
|
|
||||||
// check next data points for "temporary" value(s)
|
|
||||||
if( !isTemporaryValue ) {
|
|
||||||
// one or two values between two equal values are considered "temporary",
|
|
||||||
// which means that they are the target value for the following scroll animation
|
|
||||||
int stage = 0;
|
|
||||||
for( int j = i + 1; j < size && stage <= 2 && !isTemporaryValue; j++ ) {
|
|
||||||
Data nextData = chartData.get( j );
|
|
||||||
if( nextData.dot )
|
|
||||||
continue; // ignore dots
|
|
||||||
|
|
||||||
// check whether next data point is within 10 milliseconds
|
|
||||||
if( nextData.time > data.time + 10 )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if( stage >= 1 && stage <= 2 && nextData.value == data.value ) {
|
|
||||||
isTemporaryValue = true;
|
|
||||||
lastTemporaryValueIndex = j;
|
|
||||||
}
|
|
||||||
stage++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
py = dy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int chartWidth() {
|
|
||||||
int width = 0;
|
|
||||||
for( List<Data> chartData : color2dataMap.values() )
|
|
||||||
width = Math.max( width, chartWidth( chartData, null ) );
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int chartWidth( List<Data> chartData, int[] lastSeqX ) {
|
|
||||||
long seqTime = 0;
|
|
||||||
int seqX = 0;
|
|
||||||
long ptime = 0;
|
|
||||||
int px = 0;
|
|
||||||
|
|
||||||
int size = chartData.size();
|
|
||||||
for( int i = 0; i < size; i++ ) {
|
|
||||||
Data data = chartData.get( i );
|
|
||||||
|
|
||||||
if( data.time > ptime + NEW_SEQUENCE_TIME_LAG ) {
|
|
||||||
// start new sequence
|
|
||||||
seqTime = data.time;
|
|
||||||
seqX = (i > 0) ? px + NEW_SEQUENCE_GAP : 0;
|
|
||||||
px = seqX;
|
|
||||||
} else {
|
|
||||||
// line in sequence
|
|
||||||
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * oneSecondWidth));
|
|
||||||
px = dx;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptime = data.time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( lastSeqX != null )
|
|
||||||
lastSeqX[0] = seqX;
|
|
||||||
|
|
||||||
return px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredSize() {
|
|
||||||
return new Dimension( chartWidth(), 200 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Dimension getPreferredScrollableViewportSize() {
|
|
||||||
return new Dimension( chartWidth(), 200 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) {
|
|
||||||
return oneSecondWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getScrollableBlockIncrement( Rectangle visibleRect, int orientation, int direction ) {
|
|
||||||
JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass( JViewport.class, this );
|
|
||||||
return (viewport != null) ? viewport.getWidth() : 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportWidth() {
|
|
||||||
JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass( JViewport.class, this );
|
|
||||||
return (viewport != null) ? viewport.getWidth() > chartWidth() : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getScrollableTracksViewportHeight() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getToolTipText( MouseEvent e ) {
|
|
||||||
int x = (int) Math.round( e.getX() * lastSystemScaleFactor );
|
|
||||||
int y = (int) Math.round( e.getY() * lastSystemScaleFactor );
|
|
||||||
int hitOffset = (int) Math.round( UIScale.scale( HIT_OFFSET ) * lastSystemScaleFactor );
|
|
||||||
StringBuilder buf = null;
|
|
||||||
|
|
||||||
int pointsCount = lastPoints.size();
|
|
||||||
for( int i = 0; i < pointsCount; i++ ) {
|
|
||||||
Point pt = lastPoints.get( i );
|
|
||||||
|
|
||||||
// check X/Y coordinates
|
|
||||||
if( x < pt.x - hitOffset || x > pt.x + hitOffset ||
|
|
||||||
y < pt.y - hitOffset || y > pt.y + hitOffset )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if( buf == null ) {
|
|
||||||
buf = new StringBuilder( 5000 );
|
|
||||||
buf.append( "<html>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
Data data = lastDatas.get( i );
|
|
||||||
buf.append( "<h2>" );
|
|
||||||
if( data.dot )
|
|
||||||
buf.append( "DOT: " );
|
|
||||||
buf.append( data.name ).append( ' ' ).append( data.value ).append( "</h2>" );
|
|
||||||
|
|
||||||
StackTraceElement[] stackTrace = data.stack.getStackTrace();
|
|
||||||
for( int j = 0; j < stackTrace.length; j++ ) {
|
|
||||||
StackTraceElement stackElement = stackTrace[j];
|
|
||||||
String className = stackElement.getClassName();
|
|
||||||
String methodName = stackElement.getMethodName();
|
|
||||||
|
|
||||||
// ignore methods from this class
|
|
||||||
if( className.startsWith( FlatSmoothScrollingTest.class.getName() ) )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
int repeatCount = 0;
|
|
||||||
for( int k = j + 1; k < stackTrace.length; k++ ) {
|
|
||||||
if( !stackElement.equals( stackTrace[k] ) )
|
|
||||||
break;
|
|
||||||
repeatCount++;
|
|
||||||
}
|
|
||||||
j += repeatCount;
|
|
||||||
|
|
||||||
// append method
|
|
||||||
buf.append( className )
|
|
||||||
.append( ".<b>" )
|
|
||||||
.append( methodName )
|
|
||||||
.append( "</b> <span color=\"#888888\">" );
|
|
||||||
if( stackElement.getFileName() != null ) {
|
|
||||||
buf.append( '(' );
|
|
||||||
buf.append( stackElement.getFileName() );
|
|
||||||
if( stackElement.getLineNumber() >= 0 )
|
|
||||||
buf.append( ':' ).append( stackElement.getLineNumber() );
|
|
||||||
buf.append( ')' );
|
|
||||||
} else
|
|
||||||
buf.append( "(Unknown Source)" );
|
|
||||||
buf.append( "</span>" );
|
|
||||||
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" )) )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf.append( "..." );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( buf == null )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
buf.append( "<html>" );
|
|
||||||
String toolTip = buf.toString();
|
|
||||||
|
|
||||||
// print to console
|
|
||||||
if( !Objects.equals( toolTip, lastToolTipPrinted ) ) {
|
|
||||||
lastToolTipPrinted = toolTip;
|
|
||||||
|
|
||||||
System.out.println( toolTip
|
|
||||||
.replace( "<br>", "\n" )
|
|
||||||
.replace( "<h2>", "\n---- " )
|
|
||||||
.replace( "</h2>", " ----\n" )
|
|
||||||
.replaceAll( "<[^>]+>", "" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---- class ColorIcon ----------------------------------------------------
|
//---- class ColorIcon ----------------------------------------------------
|
||||||
|
|
||||||
private static class ColorIcon
|
private static class ColorIcon
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ new FormModel {
|
|||||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||||
"$columnConstraints": "[200,grow,fill]"
|
"$columnConstraints": "[200,grow,fill]"
|
||||||
"$rowConstraints": "[][grow,fill][]"
|
"$rowConstraints": "[][grow,fill]"
|
||||||
} ) {
|
} ) {
|
||||||
name: "this"
|
name: "this"
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
@@ -175,105 +175,17 @@ new FormModel {
|
|||||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
"value": "left"
|
"value": "left"
|
||||||
} )
|
} )
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
add( new FormComponent( "com.formdev.flatlaf.testing.LineChartPanel" ) {
|
||||||
"$layoutConstraints": "insets 3,hidemode 3"
|
name: "lineChartPanel"
|
||||||
"$columnConstraints": "[grow,fill]"
|
"legend1Text": "Rectangles: scrollbar values (mouse hover shows stack)"
|
||||||
"$rowConstraints": "[100:300,grow,fill]"
|
"legend2Text": "Dots: disabled blitting mode in JViewport"
|
||||||
} ) {
|
"legendYValueText": "scroll bar value"
|
||||||
name: "panel3"
|
|
||||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
|
||||||
name: "chartScrollPane"
|
|
||||||
"$client.JScrollPane.smoothScrolling": false
|
|
||||||
add( new FormComponent( "com.formdev.flatlaf.testing.FlatSmoothScrollingTest$LineChartPanel" ) {
|
|
||||||
name: "lineChartPanel"
|
|
||||||
} )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 0"
|
|
||||||
} )
|
|
||||||
}, new FormLayoutConstraints( class java.lang.String ) {
|
}, new FormLayoutConstraints( class java.lang.String ) {
|
||||||
"value": "right"
|
"value": "right"
|
||||||
} )
|
} )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 0 1"
|
"value": "cell 0 1"
|
||||||
} )
|
} )
|
||||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
|
||||||
"$layoutConstraints": "insets 0,hidemode 3,gapy 0"
|
|
||||||
"$columnConstraints": "[fill]para[fill]"
|
|
||||||
"$rowConstraints": "[][]"
|
|
||||||
} ) {
|
|
||||||
name: "panel4"
|
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
|
||||||
name: "xLabel"
|
|
||||||
"text": "X: time ({0}ms per line)"
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 0"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
|
||||||
name: "rectsLabel"
|
|
||||||
"text": "Rectangles: scrollbar values (mouse hover shows stack)"
|
|
||||||
auxiliary() {
|
|
||||||
"JavaCodeGenerator.variableLocal": true
|
|
||||||
}
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 1 0"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
|
||||||
name: "yLabel"
|
|
||||||
"text": "Y: scroll bar value (10% per line)"
|
|
||||||
auxiliary() {
|
|
||||||
"JavaCodeGenerator.variableLocal": true
|
|
||||||
}
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 1"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
|
||||||
name: "dotsLabel"
|
|
||||||
"text": "Dots: disabled blitting mode in JViewport"
|
|
||||||
auxiliary() {
|
|
||||||
"JavaCodeGenerator.variableLocal": true
|
|
||||||
}
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 1 1"
|
|
||||||
} )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 2"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
|
||||||
name: "oneSecondWidthLabel"
|
|
||||||
"text": "Scale X:"
|
|
||||||
"displayedMnemonic": 65
|
|
||||||
"labelFor": new FormReference( "oneSecondWidthSlider" )
|
|
||||||
auxiliary() {
|
|
||||||
"JavaCodeGenerator.variableLocal": true
|
|
||||||
}
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 2,alignx right,growx 0"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JSlider" ) {
|
|
||||||
name: "oneSecondWidthSlider"
|
|
||||||
"minimum": 1000
|
|
||||||
"maximum": 10000
|
|
||||||
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "oneSecondWidthChanged", false ) )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 2,alignx right,growx 0,wmax 100"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
|
||||||
name: "updateChartDelayedCheckBox"
|
|
||||||
"text": "Update chart delayed"
|
|
||||||
"mnemonic": 80
|
|
||||||
"selected": true
|
|
||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "updateChartDelayedChanged", false ) )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 2,alignx right,growx 0"
|
|
||||||
} )
|
|
||||||
add( new FormComponent( "javax.swing.JButton" ) {
|
|
||||||
name: "clearChartButton"
|
|
||||||
"text": "Clear Chart"
|
|
||||||
"mnemonic": 67
|
|
||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "clearChart", false ) )
|
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
|
||||||
"value": "cell 0 2,alignx right,growx 0"
|
|
||||||
} )
|
|
||||||
}, new FormLayoutConstraints( null ) {
|
}, new FormLayoutConstraints( null ) {
|
||||||
"location": new java.awt.Point( 0, 0 )
|
"location": new java.awt.Point( 0, 0 )
|
||||||
"size": new java.awt.Dimension( 875, 715 )
|
"size": new java.awt.Dimension( 875, 715 )
|
||||||
|
|||||||
@@ -0,0 +1,664 @@
|
|||||||
|
/*
|
||||||
|
/*
|
||||||
|
* Copyright 2023 FormDev Software GmbH
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.formdev.flatlaf.testing;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.event.HierarchyEvent;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import javax.swing.*;
|
||||||
|
import com.formdev.flatlaf.FlatClientProperties;
|
||||||
|
import com.formdev.flatlaf.FlatLaf;
|
||||||
|
import com.formdev.flatlaf.ui.FlatUIUtils;
|
||||||
|
import com.formdev.flatlaf.util.ColorFunctions;
|
||||||
|
import com.formdev.flatlaf.util.HSLColor;
|
||||||
|
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||||
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
import net.miginfocom.swing.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class LineChartPanel
|
||||||
|
extends JPanel
|
||||||
|
{
|
||||||
|
LineChartPanel() {
|
||||||
|
initComponents();
|
||||||
|
|
||||||
|
lineChartScrollPane.putClientProperty( FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING, false );
|
||||||
|
|
||||||
|
oneSecondWidthChanged();
|
||||||
|
updateChartDelayedChanged();
|
||||||
|
|
||||||
|
// clear chart on startup
|
||||||
|
addHierarchyListener( e -> {
|
||||||
|
if( (e.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0 && isShowing() )
|
||||||
|
EventQueue.invokeLater( this::clearChart );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addNotify() {
|
||||||
|
super.addNotify();
|
||||||
|
|
||||||
|
// allow clearing chart with Alt+C without moving focus to button
|
||||||
|
getRootPane().registerKeyboardAction(
|
||||||
|
e -> clearChart(),
|
||||||
|
KeyStroke.getKeyStroke( "alt " + (char) clearChartButton.getMnemonic() ),
|
||||||
|
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLegendYValueText() {
|
||||||
|
return yValueLabel.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLegendYValueText( String s ) {
|
||||||
|
yValueLabel.setText( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLegend1Text() {
|
||||||
|
return legend1Label.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLegend1Text( String s ) {
|
||||||
|
legend1Label.setText( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLegend2Text() {
|
||||||
|
return legend2Label.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLegend2Text( String s ) {
|
||||||
|
legend2Label.setText( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpdateChartDelayed() {
|
||||||
|
return updateChartDelayedCheckBox.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateChartDelayed( boolean updateChartDelayed ) {
|
||||||
|
updateChartDelayedCheckBox.setSelected( updateChartDelayed );
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValue( double value, int ivalue, boolean dot, Color chartColor, String name ) {
|
||||||
|
lineChart.addValue( value, ivalue, dot, chartColor, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void oneSecondWidthChanged() {
|
||||||
|
int oneSecondWidth = oneSecondWidthSlider.getValue();
|
||||||
|
int msPerLineX =
|
||||||
|
oneSecondWidth <= 2000 ? 100 :
|
||||||
|
oneSecondWidth <= 4000 ? 50 :
|
||||||
|
oneSecondWidth <= 8000 ? 25 :
|
||||||
|
10;
|
||||||
|
|
||||||
|
lineChart.setOneSecondWidth( oneSecondWidth );
|
||||||
|
lineChart.setMsPerLineX( msPerLineX );
|
||||||
|
lineChart.revalidate();
|
||||||
|
lineChart.repaint();
|
||||||
|
|
||||||
|
if( xLabelText == null )
|
||||||
|
xLabelText = xLabel.getText();
|
||||||
|
xLabel.setText( MessageFormat.format( xLabelText, msPerLineX ) );
|
||||||
|
}
|
||||||
|
private String xLabelText;
|
||||||
|
|
||||||
|
private void updateChartDelayedChanged() {
|
||||||
|
lineChart.setUpdateDelayed( updateChartDelayedCheckBox.isSelected() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearChart() {
|
||||||
|
lineChart.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initComponents() {
|
||||||
|
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
|
||||||
|
lineChartScrollPane = new JScrollPane();
|
||||||
|
lineChart = new LineChartPanel.LineChart();
|
||||||
|
JPanel legendPanel = new JPanel();
|
||||||
|
xLabel = new JLabel();
|
||||||
|
legend1Label = new JLabel();
|
||||||
|
JLabel yLabel = new JLabel();
|
||||||
|
yValueLabel = new JLabel();
|
||||||
|
JLabel yLabel2 = new JLabel();
|
||||||
|
JPanel hSpacer1 = new JPanel(null);
|
||||||
|
legend2Label = new JLabel();
|
||||||
|
JLabel oneSecondWidthLabel = new JLabel();
|
||||||
|
oneSecondWidthSlider = new JSlider();
|
||||||
|
updateChartDelayedCheckBox = new JCheckBox();
|
||||||
|
clearChartButton = new JButton();
|
||||||
|
|
||||||
|
//======== this ========
|
||||||
|
setLayout(new MigLayout(
|
||||||
|
"hidemode 3",
|
||||||
|
// columns
|
||||||
|
"[grow,fill]",
|
||||||
|
// rows
|
||||||
|
"[100:300,grow,fill]" +
|
||||||
|
"[]"));
|
||||||
|
|
||||||
|
//======== lineChartScrollPane ========
|
||||||
|
{
|
||||||
|
lineChartScrollPane.setViewportView(lineChart);
|
||||||
|
}
|
||||||
|
add(lineChartScrollPane, "cell 0 0");
|
||||||
|
|
||||||
|
//======== legendPanel ========
|
||||||
|
{
|
||||||
|
legendPanel.setLayout(new MigLayout(
|
||||||
|
"insets 0,hidemode 3,gapy 0",
|
||||||
|
// columns
|
||||||
|
"[fill]para" +
|
||||||
|
"[fill]",
|
||||||
|
// rows
|
||||||
|
"[]" +
|
||||||
|
"[]"));
|
||||||
|
|
||||||
|
//---- xLabel ----
|
||||||
|
xLabel.setText("X: time ({0}ms per line)");
|
||||||
|
legendPanel.add(xLabel, "cell 0 0");
|
||||||
|
legendPanel.add(legend1Label, "cell 1 0");
|
||||||
|
|
||||||
|
//---- yLabel ----
|
||||||
|
yLabel.setText("Y: ");
|
||||||
|
legendPanel.add(yLabel, "cell 0 1,gapx 0 0");
|
||||||
|
|
||||||
|
//---- yValueLabel ----
|
||||||
|
yValueLabel.setText("value");
|
||||||
|
legendPanel.add(yValueLabel, "cell 0 1,gapx 0 0");
|
||||||
|
|
||||||
|
//---- yLabel2 ----
|
||||||
|
yLabel2.setText(" (10% per line)");
|
||||||
|
legendPanel.add(yLabel2, "cell 0 1,gapx 0 0");
|
||||||
|
legendPanel.add(hSpacer1, "cell 0 1,growx");
|
||||||
|
legendPanel.add(legend2Label, "cell 1 1");
|
||||||
|
}
|
||||||
|
add(legendPanel, "cell 0 1");
|
||||||
|
|
||||||
|
//---- oneSecondWidthLabel ----
|
||||||
|
oneSecondWidthLabel.setText("Scale X:");
|
||||||
|
oneSecondWidthLabel.setDisplayedMnemonic('A');
|
||||||
|
oneSecondWidthLabel.setLabelFor(oneSecondWidthSlider);
|
||||||
|
add(oneSecondWidthLabel, "cell 0 1,alignx right,growx 0");
|
||||||
|
|
||||||
|
//---- oneSecondWidthSlider ----
|
||||||
|
oneSecondWidthSlider.setMinimum(1000);
|
||||||
|
oneSecondWidthSlider.setMaximum(10000);
|
||||||
|
oneSecondWidthSlider.addChangeListener(e -> oneSecondWidthChanged());
|
||||||
|
add(oneSecondWidthSlider, "cell 0 1,alignx right,growx 0,wmax 100");
|
||||||
|
|
||||||
|
//---- updateChartDelayedCheckBox ----
|
||||||
|
updateChartDelayedCheckBox.setText("Update chart delayed");
|
||||||
|
updateChartDelayedCheckBox.setMnemonic('P');
|
||||||
|
updateChartDelayedCheckBox.setSelected(true);
|
||||||
|
updateChartDelayedCheckBox.addActionListener(e -> updateChartDelayedChanged());
|
||||||
|
add(updateChartDelayedCheckBox, "cell 0 1,alignx right,growx 0");
|
||||||
|
|
||||||
|
//---- clearChartButton ----
|
||||||
|
clearChartButton.setText("Clear Chart");
|
||||||
|
clearChartButton.setMnemonic('C');
|
||||||
|
clearChartButton.addActionListener(e -> clearChart());
|
||||||
|
add(clearChartButton, "cell 0 1,alignx right,growx 0");
|
||||||
|
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
|
||||||
|
}
|
||||||
|
|
||||||
|
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
|
||||||
|
private JScrollPane lineChartScrollPane;
|
||||||
|
private LineChartPanel.LineChart lineChart;
|
||||||
|
private JLabel xLabel;
|
||||||
|
private JLabel legend1Label;
|
||||||
|
private JLabel yValueLabel;
|
||||||
|
private JLabel legend2Label;
|
||||||
|
private JSlider oneSecondWidthSlider;
|
||||||
|
private JCheckBox updateChartDelayedCheckBox;
|
||||||
|
private JButton clearChartButton;
|
||||||
|
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
|
||||||
|
|
||||||
|
|
||||||
|
//---- class LineChart ----------------------------------------------------
|
||||||
|
|
||||||
|
private static class LineChart
|
||||||
|
extends JComponent
|
||||||
|
implements Scrollable
|
||||||
|
{
|
||||||
|
private static final int UPDATE_DELAY_MS = 20;
|
||||||
|
|
||||||
|
private static final int NEW_SEQUENCE_TIME_LAG = 500;
|
||||||
|
private static final int NEW_SEQUENCE_GAP = 100;
|
||||||
|
private static final int HIT_OFFSET = 4;
|
||||||
|
|
||||||
|
private int oneSecondWidth = 1000;
|
||||||
|
private int msPerLineX = 200;
|
||||||
|
|
||||||
|
private static class Data {
|
||||||
|
final double value;
|
||||||
|
final int ivalue;
|
||||||
|
final boolean dot;
|
||||||
|
final long time; // in milliseconds
|
||||||
|
final String name;
|
||||||
|
final Exception stack;
|
||||||
|
|
||||||
|
Data( double value, int ivalue, boolean dot, long time, String name, Exception stack ) {
|
||||||
|
this.value = value;
|
||||||
|
this.ivalue = ivalue;
|
||||||
|
this.dot = dot;
|
||||||
|
this.time = time;
|
||||||
|
this.name = name;
|
||||||
|
this.stack = stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
// for debugging
|
||||||
|
return "value=" + value + ", ivalue=" + ivalue + ", dot=" + dot + ", time=" + time + ", name=" + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Map<Color, List<Data>> color2dataMap = new HashMap<>();
|
||||||
|
private final Timer repaintTime;
|
||||||
|
private Color lastUsedChartColor;
|
||||||
|
private boolean updateDelayed;
|
||||||
|
|
||||||
|
private final List<Point> lastPoints = new ArrayList<>();
|
||||||
|
private final List<Data> lastDatas = new ArrayList<>();
|
||||||
|
private double lastSystemScaleFactor = 1;
|
||||||
|
private String lastToolTipPrinted;
|
||||||
|
|
||||||
|
LineChart() {
|
||||||
|
repaintTime = new Timer( UPDATE_DELAY_MS, e -> repaintAndRevalidate() );
|
||||||
|
repaintTime.setRepeats( false );
|
||||||
|
|
||||||
|
ToolTipManager.sharedInstance().registerComponent( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValue( double value, int ivalue, boolean dot, Color chartColor, String name ) {
|
||||||
|
List<Data> chartData = color2dataMap.computeIfAbsent( chartColor, k -> new ArrayList<>() );
|
||||||
|
chartData.add( new Data( value, ivalue, dot, System.nanoTime() / 1000000, name, new Exception() ) );
|
||||||
|
|
||||||
|
lastUsedChartColor = chartColor;
|
||||||
|
|
||||||
|
if( updateDelayed ) {
|
||||||
|
repaintTime.stop();
|
||||||
|
repaintTime.start();
|
||||||
|
} else
|
||||||
|
repaintAndRevalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
color2dataMap.clear();
|
||||||
|
lastUsedChartColor = null;
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUpdateDelayed( boolean updateDelayed ) {
|
||||||
|
this.updateDelayed = updateDelayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOneSecondWidth( int oneSecondWidth ) {
|
||||||
|
this.oneSecondWidth = oneSecondWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMsPerLineX( int msPerLineX ) {
|
||||||
|
this.msPerLineX = msPerLineX;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void repaintAndRevalidate() {
|
||||||
|
repaint();
|
||||||
|
revalidate();
|
||||||
|
|
||||||
|
// scroll horizontally
|
||||||
|
if( lastUsedChartColor != null ) {
|
||||||
|
// compute chart width of last used color and start of last sequence
|
||||||
|
int[] lastSeqX = new int[1];
|
||||||
|
int cw = chartWidth( color2dataMap.get( lastUsedChartColor ), lastSeqX );
|
||||||
|
|
||||||
|
// scroll to end of last sequence (of last used color)
|
||||||
|
int lastSeqWidth = cw - lastSeqX[0];
|
||||||
|
int width = Math.min( lastSeqWidth, getParent().getWidth() );
|
||||||
|
int x = cw - width;
|
||||||
|
scrollRectToVisible( new Rectangle( x, 0, width, getHeight() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent( Graphics g ) {
|
||||||
|
Graphics g2 = g.create();
|
||||||
|
try {
|
||||||
|
HiDPIUtils.paintAtScale1x( (Graphics2D) g2, this, this::paintImpl );
|
||||||
|
} finally {
|
||||||
|
g2.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void paintImpl( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) {
|
||||||
|
FlatUIUtils.setRenderingHints( g );
|
||||||
|
|
||||||
|
int oneSecondWidth = (int) (UIScale.scale( this.oneSecondWidth ) * scaleFactor);
|
||||||
|
int seqGapWidth = (int) (NEW_SEQUENCE_GAP * scaleFactor);
|
||||||
|
int hitOffset = (int) Math.round( UIScale.scale( HIT_OFFSET ) * scaleFactor );
|
||||||
|
|
||||||
|
Color lineColor = FlatUIUtils.getUIColor( "Component.borderColor", Color.lightGray );
|
||||||
|
Color lineColor2 = FlatLaf.isLafDark()
|
||||||
|
? new HSLColor( lineColor ).adjustTone( 30 )
|
||||||
|
: new HSLColor( lineColor ).adjustShade( 30 );
|
||||||
|
|
||||||
|
g.translate( x, y );
|
||||||
|
|
||||||
|
// fill background
|
||||||
|
g.setColor( UIManager.getColor( "Table.background" ) );
|
||||||
|
g.fillRect( x, y, width, height );
|
||||||
|
|
||||||
|
// paint horizontal lines
|
||||||
|
for( int i = 1; i < 10; i++ ) {
|
||||||
|
int hy = (height * i) / 10;
|
||||||
|
g.setColor( (i != 5) ? lineColor : lineColor2 );
|
||||||
|
g.drawLine( 0, hy, width, hy );
|
||||||
|
}
|
||||||
|
|
||||||
|
// paint vertical lines
|
||||||
|
int perLineXWidth = Math.round( (oneSecondWidth / 1000f) * msPerLineX );
|
||||||
|
for( int i = 1, xv = perLineXWidth; xv < width; xv += perLineXWidth, i++ ) {
|
||||||
|
g.setColor( (i % 5 != 0) ? lineColor : lineColor2 );
|
||||||
|
g.drawLine( xv, 0, xv, height );
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPoints.clear();
|
||||||
|
lastDatas.clear();
|
||||||
|
lastSystemScaleFactor = scaleFactor;
|
||||||
|
|
||||||
|
// paint lines
|
||||||
|
for( Map.Entry<Color, List<Data>> e : color2dataMap.entrySet() ) {
|
||||||
|
List<Data> chartData = e.getValue();
|
||||||
|
Color chartColor = e.getKey();
|
||||||
|
if( FlatLaf.isLafDark() )
|
||||||
|
chartColor = new HSLColor( chartColor ).adjustTone( 50 );
|
||||||
|
Color temporaryValueColor = ColorFunctions.fade( chartColor, FlatLaf.isLafDark() ? 0.7f : 0.3f );
|
||||||
|
Color dataPointColor = ColorFunctions.fade( chartColor, FlatLaf.isLafDark() ? 0.6f : 0.2f );
|
||||||
|
|
||||||
|
// sequence start time and x coordinate
|
||||||
|
long seqTime = 0;
|
||||||
|
int seqX = 0;
|
||||||
|
|
||||||
|
// "previous" data point time, x/y coordinates and count
|
||||||
|
long ptime = 0;
|
||||||
|
int px = 0;
|
||||||
|
int py = 0;
|
||||||
|
int pcount = 0;
|
||||||
|
|
||||||
|
boolean first = true;
|
||||||
|
boolean isTemporaryValue = false;
|
||||||
|
int lastTemporaryValueIndex = -1;
|
||||||
|
|
||||||
|
int size = chartData.size();
|
||||||
|
for( int i = 0; i < size; i++ ) {
|
||||||
|
Data data = chartData.get( i );
|
||||||
|
|
||||||
|
boolean newSeq = (data.time > ptime + NEW_SEQUENCE_TIME_LAG);
|
||||||
|
ptime = data.time;
|
||||||
|
|
||||||
|
if( newSeq ) {
|
||||||
|
// paint short horizontal line for previous sequence that has only one data point
|
||||||
|
if( !first && pcount == 0 ) {
|
||||||
|
g.setColor( chartColor );
|
||||||
|
g.drawLine( px, py, px + (int) Math.round( UIScale.scale( 8 ) * scaleFactor ), py );
|
||||||
|
}
|
||||||
|
|
||||||
|
// start new sequence
|
||||||
|
seqTime = data.time;
|
||||||
|
seqX = !first ? px + seqGapWidth : 0;
|
||||||
|
px = seqX;
|
||||||
|
pcount = 0;
|
||||||
|
first = false;
|
||||||
|
isTemporaryValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// x/y coordinates of current data point
|
||||||
|
int dy = (int) ((height - 1) * data.value);
|
||||||
|
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * oneSecondWidth));
|
||||||
|
|
||||||
|
// paint rectangle to indicate data point
|
||||||
|
g.setColor( dataPointColor );
|
||||||
|
g.drawRect( dx - hitOffset, dy - hitOffset, hitOffset * 2, hitOffset * 2 );
|
||||||
|
|
||||||
|
// remember data point for tooltip
|
||||||
|
lastPoints.add( new Point( dx, dy ) );
|
||||||
|
lastDatas.add( data );
|
||||||
|
|
||||||
|
if( data.dot ) {
|
||||||
|
int s1 = (int) Math.round( UIScale.scale( 1 ) * scaleFactor );
|
||||||
|
int s3 = (int) Math.round( UIScale.scale( 3 ) * scaleFactor );
|
||||||
|
g.setColor( chartColor );
|
||||||
|
g.fillRect( dx - s1, dy - s1, s3, s3 );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !newSeq ) {
|
||||||
|
if( isTemporaryValue && i > lastTemporaryValueIndex )
|
||||||
|
isTemporaryValue = false;
|
||||||
|
|
||||||
|
g.setColor( isTemporaryValue ? temporaryValueColor : chartColor );
|
||||||
|
|
||||||
|
// line in sequence
|
||||||
|
g.drawLine( px, py, dx, dy );
|
||||||
|
|
||||||
|
px = dx;
|
||||||
|
pcount++;
|
||||||
|
|
||||||
|
// check next data points for "temporary" value(s)
|
||||||
|
if( !isTemporaryValue ) {
|
||||||
|
// one or two values between two equal values are considered "temporary",
|
||||||
|
// which means that they are the target value for the following scroll animation
|
||||||
|
int stage = 0;
|
||||||
|
for( int j = i + 1; j < size && stage <= 2 && !isTemporaryValue; j++ ) {
|
||||||
|
Data nextData = chartData.get( j );
|
||||||
|
if( nextData.dot )
|
||||||
|
continue; // ignore dots
|
||||||
|
|
||||||
|
// check whether next data point is within 10 milliseconds
|
||||||
|
if( nextData.time > data.time + 10 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( stage >= 1 && stage <= 2 && nextData.value == data.value ) {
|
||||||
|
isTemporaryValue = true;
|
||||||
|
lastTemporaryValueIndex = j;
|
||||||
|
}
|
||||||
|
stage++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
py = dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int chartWidth() {
|
||||||
|
int width = 0;
|
||||||
|
for( List<Data> chartData : color2dataMap.values() )
|
||||||
|
width = Math.max( width, chartWidth( chartData, null ) );
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int chartWidth( List<Data> chartData, int[] lastSeqX ) {
|
||||||
|
long seqTime = 0;
|
||||||
|
int seqX = 0;
|
||||||
|
long ptime = 0;
|
||||||
|
int px = 0;
|
||||||
|
|
||||||
|
int size = chartData.size();
|
||||||
|
for( int i = 0; i < size; i++ ) {
|
||||||
|
Data data = chartData.get( i );
|
||||||
|
|
||||||
|
if( data.time > ptime + NEW_SEQUENCE_TIME_LAG ) {
|
||||||
|
// start new sequence
|
||||||
|
seqTime = data.time;
|
||||||
|
seqX = (i > 0) ? px + NEW_SEQUENCE_GAP : 0;
|
||||||
|
px = seqX;
|
||||||
|
} else {
|
||||||
|
// line in sequence
|
||||||
|
int dx = (int) (seqX + (((data.time - seqTime) / 1000.) * UIScale.scale( oneSecondWidth )));
|
||||||
|
px = dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptime = data.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( lastSeqX != null )
|
||||||
|
lastSeqX[0] = seqX;
|
||||||
|
|
||||||
|
return px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return new Dimension( chartWidth(), 200 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredScrollableViewportSize() {
|
||||||
|
return new Dimension( chartWidth(), 200 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScrollableUnitIncrement( Rectangle visibleRect, int orientation, int direction ) {
|
||||||
|
return UIScale.scale( oneSecondWidth );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getScrollableBlockIncrement( Rectangle visibleRect, int orientation, int direction ) {
|
||||||
|
JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass( JViewport.class, this );
|
||||||
|
return (viewport != null) ? viewport.getWidth() : 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getScrollableTracksViewportWidth() {
|
||||||
|
JViewport viewport = (JViewport) SwingUtilities.getAncestorOfClass( JViewport.class, this );
|
||||||
|
return (viewport != null) ? viewport.getWidth() > chartWidth() : true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getScrollableTracksViewportHeight() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getToolTipText( MouseEvent e ) {
|
||||||
|
int x = (int) Math.round( e.getX() * lastSystemScaleFactor );
|
||||||
|
int y = (int) Math.round( e.getY() * lastSystemScaleFactor );
|
||||||
|
int hitOffset = (int) Math.round( UIScale.scale( HIT_OFFSET ) * lastSystemScaleFactor );
|
||||||
|
StringBuilder buf = null;
|
||||||
|
|
||||||
|
int pointsCount = lastPoints.size();
|
||||||
|
for( int i = 0; i < pointsCount; i++ ) {
|
||||||
|
Point pt = lastPoints.get( i );
|
||||||
|
|
||||||
|
// check X/Y coordinates
|
||||||
|
if( x < pt.x - hitOffset || x > pt.x + hitOffset ||
|
||||||
|
y < pt.y - hitOffset || y > pt.y + hitOffset )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( buf == null ) {
|
||||||
|
buf = new StringBuilder( 5000 );
|
||||||
|
buf.append( "<html>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
Data data = lastDatas.get( i );
|
||||||
|
buf.append( "<h2>" );
|
||||||
|
if( data.dot )
|
||||||
|
buf.append( "DOT: " );
|
||||||
|
buf.append( data.name ).append( ' ' ).append( data.ivalue ).append( "</h2>" );
|
||||||
|
|
||||||
|
StackTraceElement[] stackTrace = data.stack.getStackTrace();
|
||||||
|
for( int j = 0; j < stackTrace.length; j++ ) {
|
||||||
|
StackTraceElement stackElement = stackTrace[j];
|
||||||
|
String className = stackElement.getClassName();
|
||||||
|
String methodName = stackElement.getMethodName();
|
||||||
|
|
||||||
|
// ignore methods from this class
|
||||||
|
if( className.startsWith( LineChartPanel.class.getName() ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int repeatCount = 0;
|
||||||
|
for( int k = j + 1; k < stackTrace.length; k++ ) {
|
||||||
|
if( !stackElement.equals( stackTrace[k] ) )
|
||||||
|
break;
|
||||||
|
repeatCount++;
|
||||||
|
}
|
||||||
|
j += repeatCount;
|
||||||
|
|
||||||
|
// append method
|
||||||
|
buf.append( className )
|
||||||
|
.append( ".<b>" )
|
||||||
|
.append( methodName )
|
||||||
|
.append( "</b> <span color=\"#888888\">" );
|
||||||
|
if( stackElement.getFileName() != null ) {
|
||||||
|
buf.append( '(' );
|
||||||
|
buf.append( stackElement.getFileName() );
|
||||||
|
if( stackElement.getLineNumber() >= 0 )
|
||||||
|
buf.append( ':' ).append( stackElement.getLineNumber() );
|
||||||
|
buf.append( ')' );
|
||||||
|
} else
|
||||||
|
buf.append( "(Unknown Source)" );
|
||||||
|
buf.append( "</span>" );
|
||||||
|
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" )) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.append( "..." );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( buf == null )
|
||||||
|
return null;
|
||||||
|
|
||||||
|
buf.append( "<html>" );
|
||||||
|
String toolTip = buf.toString();
|
||||||
|
|
||||||
|
// print to console
|
||||||
|
if( !Objects.equals( toolTip, lastToolTipPrinted ) ) {
|
||||||
|
lastToolTipPrinted = toolTip;
|
||||||
|
|
||||||
|
System.out.println( toolTip
|
||||||
|
.replace( "<br>", "\n" )
|
||||||
|
.replace( "<h2>", "\n---- " )
|
||||||
|
.replace( "</h2>", " ----\n" )
|
||||||
|
.replaceAll( "<[^>]+>", "" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
|
||||||
|
|
||||||
|
new FormModel {
|
||||||
|
contentType: "form/swing"
|
||||||
|
root: new FormRoot {
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "hidemode 3"
|
||||||
|
"$columnConstraints": "[grow,fill]"
|
||||||
|
"$rowConstraints": "[100:300,grow,fill][]"
|
||||||
|
} ) {
|
||||||
|
name: "this"
|
||||||
|
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||||
|
name: "lineChartScrollPane"
|
||||||
|
add( new FormComponent( "com.formdev.flatlaf.testing.LineChartPanel$LineChart" ) {
|
||||||
|
name: "lineChart"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||||
|
"$layoutConstraints": "insets 0,hidemode 3,gapy 0"
|
||||||
|
"$columnConstraints": "[fill]para[fill]"
|
||||||
|
"$rowConstraints": "[][]"
|
||||||
|
} ) {
|
||||||
|
name: "legendPanel"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": true
|
||||||
|
}
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "xLabel"
|
||||||
|
"text": "X: time ({0}ms per line)"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "legend1Label"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "yLabel"
|
||||||
|
"text": "Y: "
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": true
|
||||||
|
}
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,gapx 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "yValueLabel"
|
||||||
|
"text": "value"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,gapx 0 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "yLabel2"
|
||||||
|
"text": " (10% per line)"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": true
|
||||||
|
}
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,gapx 0 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 1,growx"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "legend2Label"
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 1 1"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||||
|
name: "oneSecondWidthLabel"
|
||||||
|
"text": "Scale X:"
|
||||||
|
"displayedMnemonic": 65
|
||||||
|
"labelFor": new FormReference( "oneSecondWidthSlider" )
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": true
|
||||||
|
}
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx right,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JSlider" ) {
|
||||||
|
name: "oneSecondWidthSlider"
|
||||||
|
"minimum": 1000
|
||||||
|
"maximum": 10000
|
||||||
|
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "oneSecondWidthChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx right,growx 0,wmax 100"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
|
name: "updateChartDelayedCheckBox"
|
||||||
|
"text": "Update chart delayed"
|
||||||
|
"mnemonic": 80
|
||||||
|
"selected": true
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "updateChartDelayedChanged", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx right,growx 0"
|
||||||
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "clearChartButton"
|
||||||
|
"text": "Clear Chart"
|
||||||
|
"mnemonic": 67
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "clearChart", false ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 0 1,alignx right,growx 0"
|
||||||
|
} )
|
||||||
|
}, new FormLayoutConstraints( null ) {
|
||||||
|
"location": new java.awt.Point( 0, 0 )
|
||||||
|
"size": new java.awt.Dimension( 880, 300 )
|
||||||
|
} )
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user