Недавно я купил книгу Filthy Rich Clients и нашел ее действительно полезной и интересной. Основываясь на одном примере из книги, я попытался реализовать пользовательскую панель прокрутки, которая отображает «тень» в нижней части своего представления над отображаемым компонентом. Я закончил с кодом ниже. Он работает, но не идеально. В частности, когда я прокручиваю панель, перетаскивая полосу прокрутки, все работает нормально, и рисование действительно гладкое. Но когда я прокручиваю мышью, тень мерцает, и я понятия не имею, почему. Может кто-нибудь помочь мне?
EDIT: то же самое происходит с любым компонентом в области прокрутки. Отредактировал код для отображения двух кадров, чтобы увидеть проблему.
РЕДАКТИРОВАТЬ 2. Я выделил проблему, связанную с тем, как панель прокрутки обрабатывает событие колесика мыши. При прокрутке панель прокрутки копирует содержимое окна просмотра немного вверх или вниз в зависимости от ориентации прокрутки, а затем рисует область, которая попадает в поле зрения. Мой код делает весь компонент «грязным», но это происходит после того, как компонент сместил содержимое. Таким образом, на мгновение вы видите градиент «тени» не на своем месте, пока не будет выполнено перерисовывание. Есть идеи, как отключить эту функцию?
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.RepaintManager;
public class Test {
public static void main(String[] args) {
JFrame f = new JFrame("Table");
JFrame f1 = new JFrame("Text Area");
Object[] names = new Object[] { "Title", "Artist", "Album" };
String[][] data = new String[][] {
{ "Los Angeles", "Sugarcult", "Lights Out" },
{ "Do It Alone", "Sugarcult", "Lights Out" },
{ "Made a Mistake", "Sugarcult", "Lights Out" },
{ "Kiss You Better", "Maximo Park", "A Certain Trigger" },
{ "All Over the Shop", "Maximo Park", "A Certain Trigger" },
{ "Los Angeles", "Sugarcult", "Lights Out" },
{ "Do It Alone", "Sugarcult", "Lights Out" },
{ "Made a Mistake", "Sugarcult", "Lights Out" },
{ "Kiss You Better", "Maximo Park", "A Certain Trigger" },
{ "All Over the Shop", "Maximo Park", "A Certain Trigger" },
{ "Los Angeles", "Sugarcult", "Lights Out" },
{ "Do It Alone", "Sugarcult", "Lights Out" },
{ "Made a Mistake", "Sugarcult", "Lights Out" },
{ "Kiss You Better", "Maximo Park", "A Certain Trigger" },
{ "All Over the Shop", "Maximo Park", "A Certain Trigger" },
{ "Los Angeles", "Sugarcult", "Lights Out" },
{ "Do It Alone", "Sugarcult", "Lights Out" },
{ "Made a Mistake", "Sugarcult", "Lights Out" },
{ "Kiss You Better", "Maximo Park", "A Certain Trigger" },
{ "All Over the Shop", "Maximo Park", "A Certain Trigger" },
{ "Los Angeles", "Sugarcult", "Lights Out" },
{ "Do It Alone", "Sugarcult", "Lights Out" },
{ "Made a Mistake", "Sugarcult", "Lights Out" },
{ "Kiss You Better", "Maximo Park", "A Certain Trigger" },
{ "All Over the Shop", "Maximo Park", "A Certain Trigger" },
{ "Going Missing", "Maximo Park", "A Certain Trigger" } };
JTable table = new JTable(data, names);
f.getContentPane().add(new ShadowScrollPane(table));
f1.getContentPane().add(new ShadowScrollPane(new JTextArea(20, 50)));
RepaintManager.setCurrentManager(new RepaintManager(){
@Override
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
Container con = c.getParent();
while (con instanceof JComponent) {
if (!con.isVisible()) {
return;
}
if (con instanceof ShadowScrollPane ) {
c = (JComponent)con;
x = 0;
y = 0;
w = con.getWidth();
h = con.getHeight();
}
con = con.getParent();
}
super.addDirtyRegion(c, x, y, w, h);
}
});
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f1.pack();
f1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f1.setVisible(true);
}
}
@SuppressWarnings("serial")
class ShadowScrollPane extends JScrollPane {
private final int h = 50;
private BufferedImage img = null;
private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);
public ShadowScrollPane(JComponent com) {
super(com);
Graphics2D g2 = shadow.createGraphics();
g2.setPaint(new Color(50, 50, 50));
g2.fillRect(0, 0, 1, h);
g2.setComposite(AlphaComposite.DstIn);
g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h, new Color(1, 1, 1, 0.6f)));
g2.fillRect(0, 0, 1, h);
g2.dispose();
}
@Override
public void paint(Graphics g) {
if (img == null || img.getWidth()!=getWidth() || img.getHeight() != getHeight()) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2 = img.createGraphics();
super.paint(g2);
Rectangle bounds = getViewport().getVisibleRect();
g2.scale(bounds.getWidth(), -1);
int y = (getColumnHeader()==null)?0:getColumnHeader().getHeight();
g2.drawImage(shadow, bounds.x, -bounds.y - y-h, null);
g2.scale(1,-1);
g2.drawImage(shadow, bounds.x, bounds.y + bounds.height-h+y, null);
g2.dispose();
g.drawImage(img, 0, 0, null);
}
}