Skip to content

Commit 6dfc204

Browse files
committed
SmoothScrollingTest added (from #683 (comment))
1 parent 542e7d5 commit 6dfc204

File tree

1 file changed

+305
-0
lines changed

1 file changed

+305
-0
lines changed
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
package com.formdev.flatlaf.testing.contrib;
2+
3+
import java.awt.BorderLayout;
4+
import java.awt.Component;
5+
import java.awt.Dimension;
6+
import java.awt.FlowLayout;
7+
import java.awt.GridLayout;
8+
import java.awt.Point;
9+
import java.awt.Rectangle;
10+
import java.awt.event.ItemEvent;
11+
12+
import javax.swing.BorderFactory;
13+
import javax.swing.Box;
14+
import javax.swing.JButton;
15+
import javax.swing.JCheckBox;
16+
import javax.swing.JComboBox;
17+
import javax.swing.JFrame;
18+
import javax.swing.JLayeredPane;
19+
import javax.swing.JList;
20+
import javax.swing.JPanel;
21+
import javax.swing.JPopupMenu;
22+
import javax.swing.JRootPane;
23+
import javax.swing.JScrollPane;
24+
import javax.swing.JTable;
25+
import javax.swing.JTree;
26+
import javax.swing.JViewport;
27+
import javax.swing.ListCellRenderer;
28+
import javax.swing.Scrollable;
29+
import javax.swing.SwingConstants;
30+
import javax.swing.SwingUtilities;
31+
import javax.swing.ToolTipManager;
32+
import javax.swing.UIManager;
33+
import javax.swing.table.AbstractTableModel;
34+
import javax.swing.table.TableModel;
35+
import javax.swing.tree.DefaultMutableTreeNode;
36+
import javax.swing.tree.DefaultTreeModel;
37+
import javax.swing.tree.TreeModel;
38+
39+
import com.formdev.flatlaf.FlatClientProperties;
40+
import com.formdev.flatlaf.FlatLightLaf;
41+
42+
/**
43+
* from https://github.com/JFormDesigner/FlatLaf/pull/683#issuecomment-1585667066
44+
*
45+
* @author Chrriis
46+
*/
47+
public class SmoothScrollingTest {
48+
49+
private static class CustomTree extends JTree {
50+
51+
public CustomTree() {
52+
super(getDefaultTreeModel());
53+
}
54+
55+
protected static TreeModel getDefaultTreeModel() {
56+
DefaultMutableTreeNode root = new DefaultMutableTreeNode("JTree");
57+
for(int i=0; i<1000; i++) {
58+
DefaultMutableTreeNode parent;
59+
parent = new DefaultMutableTreeNode("colors-" + i);
60+
root.add(parent);
61+
parent.add(new DefaultMutableTreeNode("blue"));
62+
parent.add(new DefaultMutableTreeNode("violet"));
63+
parent.add(new DefaultMutableTreeNode("red"));
64+
parent.add(new DefaultMutableTreeNode("yellow"));
65+
parent = new DefaultMutableTreeNode("sports-" + i);
66+
root.add(parent);
67+
parent.add(new DefaultMutableTreeNode("basketball"));
68+
parent.add(new DefaultMutableTreeNode("soccer"));
69+
parent.add(new DefaultMutableTreeNode("football"));
70+
parent.add(new DefaultMutableTreeNode("hockey"));
71+
parent = new DefaultMutableTreeNode("food-" + i);
72+
root.add(parent);
73+
parent.add(new DefaultMutableTreeNode("hot dogs"));
74+
parent.add(new DefaultMutableTreeNode("pizza"));
75+
parent.add(new DefaultMutableTreeNode("ravioli"));
76+
parent.add(new DefaultMutableTreeNode("bananas"));
77+
}
78+
return new DefaultTreeModel(root);
79+
}
80+
}
81+
82+
private static class CustomTable extends JTable {
83+
public CustomTable() {
84+
super(createDefaultTableModel());
85+
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
86+
setCellSelectionEnabled(true);
87+
}
88+
private static TableModel createDefaultTableModel() {
89+
int columnChunkCount = 90;
90+
Object[][] data = new Object[1000][3 * columnChunkCount];
91+
String[] prefixes = {"", " ", " ", " "};
92+
String[] titles = new String[columnChunkCount * 3];
93+
for(int j=0; j<columnChunkCount; j++) {
94+
titles[j * 3] = "Column" + j * 3 + 1;
95+
titles[j * 3 + 1] = "Column" + j * 3 + 2;
96+
titles[j * 3 + 2] = "Column" + j * 3 + 3;
97+
for(int i=0; i<data.length; i++) {
98+
data[i][j * 3] = (prefixes[i % prefixes.length]) + "Cell " + (i + 1) + "/" + (j + 1);
99+
data[i][j * 3 + 1] = "Cell " + (i + 1) + "/" + (j + 2);
100+
data[i][j * 3 + 2] = Boolean.valueOf(i%5 == 0);
101+
}
102+
}
103+
AbstractTableModel tableModel = new AbstractTableModel() {
104+
@Override
105+
public Object getValueAt(int rowIndex, int columnIndex) {
106+
return data[rowIndex][columnIndex];
107+
}
108+
@Override
109+
public int getRowCount() {
110+
return data.length;
111+
}
112+
@Override
113+
public int getColumnCount() {
114+
return titles.length;
115+
}
116+
@Override
117+
public String getColumnName(int column) {
118+
return titles[column];
119+
}
120+
@Override
121+
public Class<?> getColumnClass(int columnIndex) {
122+
return columnIndex % 3 == 2 ? Boolean.class : String.class;
123+
}
124+
};
125+
return tableModel;
126+
}
127+
}
128+
129+
private static class ScrollableCustomPane extends JPanel implements Scrollable {
130+
public ScrollableCustomPane() {
131+
super(new GridLayout(100, 0));
132+
for(int i=0; i<10000; i++) {
133+
add(new JButton("Button " + (i + 1)));
134+
}
135+
}
136+
@Override
137+
public Dimension getPreferredScrollableViewportSize() {
138+
return getPreferredSize();
139+
}
140+
@Override
141+
public boolean getScrollableTracksViewportWidth() {
142+
return false;
143+
}
144+
@Override
145+
public boolean getScrollableTracksViewportHeight() {
146+
return false;
147+
}
148+
@Override
149+
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
150+
Dimension referenceSize = getComponent(0).getSize();
151+
switch(orientation) {
152+
case SwingConstants.VERTICAL: return referenceSize.height;
153+
case SwingConstants.HORIZONTAL: return referenceSize.width;
154+
}
155+
return 20;
156+
}
157+
@Override
158+
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
159+
Dimension referenceSize = getComponent(0).getSize();
160+
switch(orientation) {
161+
case SwingConstants.VERTICAL: return referenceSize.height * 10;
162+
case SwingConstants.HORIZONTAL: return referenceSize.width * 5;
163+
}
164+
return 100;
165+
}
166+
}
167+
168+
public static void main(String[] args) throws Exception {
169+
UIManager.setLookAndFeel(new FlatLightLaf());
170+
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
171+
UIManager.getDefaults().put("ScrollBar.showButtons", true);
172+
ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
173+
JFrame frame = new JFrame();
174+
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
175+
JPanel contentPane = new JPanel(new BorderLayout());
176+
contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
177+
JCheckBox smoothCheckBox = new JCheckBox("Smooth", true);
178+
JComboBox<Integer> scrollModeComboBox = new JComboBox<>(new Integer[] {JViewport.BLIT_SCROLL_MODE, JViewport.BACKINGSTORE_SCROLL_MODE, JViewport.SIMPLE_SCROLL_MODE});
179+
JCheckBox blitBlockCheckBox = new JCheckBox("Prevent Blit");
180+
@SuppressWarnings( "rawtypes" )
181+
ListCellRenderer defaultComboRenderer = scrollModeComboBox.getRenderer();
182+
scrollModeComboBox.setRenderer(new ListCellRenderer<Integer>() {
183+
@SuppressWarnings( "unchecked" )
184+
@Override
185+
public Component getListCellRendererComponent(JList<? extends Integer> list, Integer value, int index, boolean isSelected, boolean cellHasFocus) {
186+
String sValue = null;
187+
switch(value) {
188+
case JViewport.BLIT_SCROLL_MODE: sValue = "Blit"; break;
189+
case JViewport.BACKINGSTORE_SCROLL_MODE: sValue = "Backing Store"; break;
190+
case JViewport.SIMPLE_SCROLL_MODE: sValue = "Simple"; break;
191+
}
192+
return defaultComboRenderer.getListCellRendererComponent(list, sValue, index, isSelected, cellHasFocus);
193+
}
194+
});
195+
JPanel northBar = new JPanel();
196+
JButton lightPopupButton = new JButton("Light Popup");
197+
lightPopupButton.addActionListener(e -> {
198+
JPopupMenu popupMenu = new JPopupMenu();
199+
popupMenu.setLightWeightPopupEnabled(true);
200+
popupMenu.putClientProperty(FlatClientProperties.POPUP_BORDER_CORNER_RADIUS, 0);
201+
JTable table = new CustomTable();
202+
table.setColumnSelectionInterval(1, 1);
203+
table.setRowSelectionInterval(28, 28);
204+
JScrollPane tableScrollPane = new JScrollPane(table);
205+
tableScrollPane.setPreferredSize(new Dimension(400, 600));
206+
tableScrollPane.putClientProperty(FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING, !smoothCheckBox.isSelected()? Boolean.FALSE: null);
207+
tableScrollPane.getViewport().setScrollMode((Integer)scrollModeComboBox.getSelectedItem());
208+
JRootPane popupRootPane = new JRootPane();
209+
popupRootPane.getContentPane().add(tableScrollPane);
210+
popupMenu.add(popupRootPane);
211+
popupMenu.show(lightPopupButton, 0, lightPopupButton.getHeight());
212+
});
213+
northBar.add(lightPopupButton);
214+
JButton heavyPopupButton = new JButton("Heavy Popup");
215+
heavyPopupButton.addActionListener(e -> {
216+
JPopupMenu popupMenu = new JPopupMenu();
217+
popupMenu.setLightWeightPopupEnabled(false);
218+
JTable table = new CustomTable();
219+
table.setColumnSelectionInterval(1, 1);
220+
table.setRowSelectionInterval(28, 28);
221+
JScrollPane tableScrollPane = new JScrollPane(table);
222+
tableScrollPane.setPreferredSize(new Dimension(400, 600));
223+
tableScrollPane.putClientProperty(FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING, !smoothCheckBox.isSelected()? Boolean.FALSE: null);
224+
tableScrollPane.getViewport().setScrollMode((Integer)scrollModeComboBox.getSelectedItem());
225+
JRootPane popupRootPane = new JRootPane();
226+
popupRootPane.getContentPane().add(tableScrollPane);
227+
popupMenu.add(popupRootPane);
228+
popupMenu.show(heavyPopupButton, 0, heavyPopupButton.getHeight());
229+
});
230+
northBar.add(heavyPopupButton);
231+
contentPane.add(northBar, BorderLayout.NORTH);
232+
JPanel centerPane = new JPanel(new GridLayout(1, 0));
233+
JTree tree = new CustomTree();
234+
JScrollPane treeScrollPane = new JScrollPane(tree);
235+
centerPane.add(treeScrollPane);
236+
for(int i=tree.getRowCount()-1; i>=0; i--) {
237+
tree.expandRow(i);
238+
}
239+
tree.setSelectionRow(28);
240+
JTable table = new CustomTable();
241+
table.setColumnSelectionInterval(1, 1);
242+
table.setRowSelectionInterval(28, 28);
243+
JScrollPane tableScrollPane = new JScrollPane(table);
244+
centerPane.add(tableScrollPane);
245+
ScrollableCustomPane scrollableCustomPane = new ScrollableCustomPane();
246+
JScrollPane customPaneScrollPane = new JScrollPane(scrollableCustomPane);
247+
centerPane.add(customPaneScrollPane);
248+
contentPane.add(centerPane, BorderLayout.CENTER);
249+
JPanel southBar = new JPanel(new FlowLayout());
250+
smoothCheckBox.addItemListener(e -> {
251+
boolean isSmooth = e.getStateChange() == ItemEvent.SELECTED;
252+
treeScrollPane.putClientProperty(FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING, !isSmooth? Boolean.FALSE: null);
253+
tableScrollPane.putClientProperty(FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING, !isSmooth? Boolean.FALSE: null);
254+
customPaneScrollPane.putClientProperty(FlatClientProperties.SCROLL_PANE_SMOOTH_SCROLLING, !isSmooth? Boolean.FALSE: null);
255+
});
256+
southBar.add(smoothCheckBox);
257+
southBar.add(Box.createHorizontalStrut(30));
258+
JButton scrollButton = new JButton("Scroll rect");
259+
scrollButton.addActionListener(e -> {
260+
treeScrollPane.getViewport().setViewPosition(new Point(9, Integer.MAX_VALUE / 2));
261+
tableScrollPane.getViewport().setViewPosition(new Point(9, Integer.MAX_VALUE / 2));
262+
customPaneScrollPane.getViewport().setViewPosition(new Point(9, Integer.MAX_VALUE / 2));
263+
});
264+
southBar.add(scrollButton);
265+
southBar.add(Box.createHorizontalStrut(30));
266+
scrollModeComboBox.addItemListener(e -> {
267+
SwingUtilities.invokeLater(() -> {
268+
int scrollMode = (Integer)scrollModeComboBox.getSelectedItem();
269+
treeScrollPane.getViewport().setScrollMode(scrollMode);
270+
tableScrollPane.getViewport().setScrollMode(scrollMode);
271+
customPaneScrollPane.getViewport().setScrollMode(scrollMode);
272+
});
273+
});
274+
southBar.add(scrollModeComboBox);
275+
southBar.add(Box.createHorizontalStrut(30));
276+
JButton xButton1 = new JButton("Blit Blocker");
277+
xButton1.setBounds(20, 400, xButton1.getPreferredSize().width, xButton1.getPreferredSize().height);
278+
JButton xButton2 = new JButton("Blit Blocker");
279+
xButton2.setBounds(600, 400, xButton2.getPreferredSize().width, xButton2.getPreferredSize().height);
280+
JButton xButton3 = new JButton("Blit Blocker");
281+
xButton3.setBounds(800, 400, xButton3.getPreferredSize().width, xButton3.getPreferredSize().height);
282+
blitBlockCheckBox.addItemListener(e -> {
283+
boolean isBlockingBlit = e.getStateChange() == ItemEvent.SELECTED;
284+
JLayeredPane layeredPane = frame.getLayeredPane();
285+
if(isBlockingBlit) {
286+
layeredPane.add(xButton1);
287+
layeredPane.add(xButton2);
288+
layeredPane.add(xButton3);
289+
} else {
290+
layeredPane.remove(xButton1);
291+
layeredPane.remove(xButton2);
292+
layeredPane.remove(xButton3);
293+
}
294+
layeredPane.revalidate();
295+
layeredPane.repaint();
296+
});
297+
southBar.add(blitBlockCheckBox);
298+
contentPane.add(southBar, BorderLayout.SOUTH);
299+
frame.getContentPane().add(contentPane);
300+
frame.setSize(1200, 800);
301+
frame.setLocationByPlatform(true);
302+
frame.setVisible(true);
303+
}
304+
305+
}

0 commit comments

Comments
 (0)