我的Java应用程序中有一个包含JPanel
的JFrame,其中我在运行时创建了一些绘图对象。问题是当滚动JFrame
大数字时滚动速度变慢并且滚动条不能平滑移动。请注意我正在使用Graphics 2D
对象并在滚动操作上执行repaint
。
有没有办法平滑JFrame
的滚动动作。
以下是代码的一部分
public class DiagramPanel implements MouseListener{
int click=0;
Point p1;
Point p2;
private Dimension panelDimension;
.... // variables
public void go() {
p1 = new Point();
p2 = new Point();
JFrame f = new JFrame();
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setSize(1200,500);
panelx = new DiaPanel();
panelx.setOpaque(true);
panelx.setBackground(Color.white);
panelx.setAutoscrolls(true);
panelx.addMouseListener(this);
JScrollPane scrollPane = new JScrollPane();
// scrollPane.add(panelx);
ClassRectangle tempRect = null;
for (ClassRectangle rect : this.classRectangles) {
tempRect = rect;
}
Rectangle rect = new Rectangle();
rect.setBounds(tempRect.getW() - 100, 0, 1000,
tempLife.getEndpointY() * 500);
panelDimension = new Dimension(0,0);
for (ClassRectangle rectx : classRectangles){
panelDimension.width=rectx.getW()+300;
}
for (LifeLine life : lifeLines) {
panelDimension.height=life.getEndpointY()+300;
}
scrollPane.setViewportView(panelx);
panelx.computeVisibleRect(rect);
JScrollPane scrollPane1 = new JScrollPane(panelx);
panelx.setPreferredSize(panelDimension);
panelx.repaint();
panelx.revalidate();
p1.x=0;
p1.y=0;
p2.y=panelDimension.height;
p2.x=panelDimension.width;
f.add( scrollPane1);
scrollPane.revalidate();
f.setBackground(Color.white);
}
public DiagramPanel(ArrayList<Rectangle> classRectangles,
ArrayList<Pair> pairs, ArrayList<Line> lines,
ArrayList<Life> meth) {
// constructing obj of DrawingPanel Here
}
public class SeqDiaPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.setColor(Color.orange);
//grid
for (int i = 0; i < panelDimension.height; i++) {
g2d2.drawLine(0, 0 + i * 5, panelDimension.width+1000, 0 + i * 5);
}
for (int i = 0; i < panelDimension.width; i++) {
g2d2.drawLine(0 + i * 5, 0, 0 + i *5,panelDimension.height+300);
}
g2d2.setColor(Color.black);
// objects
.......... some objects here
}
}
// draw Lines
Stroke drawingStroke = new BasicStroke(2, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_BEVEL, 0, new float[] { 5 }, 0);
// Stroke drawingStroke = new BasicStroke();
Graphics2D g2d = (Graphics2D) g;
g2d.setStroke(drawingStroke);
for (Line life : lines) {
g2d.drawLine(life.getStartpointX(), life.getStartpointY(),
life.getEndpointX(), life.getEndpointY());
panelDimension.height=life.getEndpointY()+300;
}
// draw methodLfe
for (Object2 ml1 : Obj2) {
g2d2.fill3DRect(ml1.StartX(), ml1.getMethodStartY(),
ml1.getBreadth(), ml1.getEndX(),true);
}
}
}
// tobeused
public int calculateWidth(String name){
Font font = new Font("Serif", Font.BOLD, 12);
FontMetrics metrics = new FontMetrics(font){
/**
*
*/
private static final long serialVersionUID = 1L;};
int tempInt2=SwingUtilities.computeStringWidth( metrics, name);
tempInt2=tempInt2+10;
return tempInt2;
}
/*public class MouseClick implements MouseListener{
Point p = new Point(0,0);
@Override
public void mouseClicked(MouseEvent evnt) {
p.x=evnt.getX();
p.y=evnt.getY();
System.out.println("MouseClicked @"+p.x+":"+p.y);
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}*/
@Override
public void mouseClicked(MouseEvent evnt) {
click++;
if(click==1){
//Point p= new Point();
p1.x=evnt.getX();
p1.y=evnt.getY();
// System.out.println("MouseClicked1 @"+p1.x+":"+p1.y);
}
if(click==2){
p2.x=evnt.getX();
p2.y=evnt.getY();
//System.out.println("MouseClicked2 @"+p2.x+":"+p2.y);
click=0;
if(p1.x<p2.x&&p1.y<p2.y){
panelx.repaint();
}
else{
}
}/*else{
p1.x=0;
p1.y=0;
p2.x=panelDimension.width+500;
p2.y=panelDimension.height+700;
}*/
}
@Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
答案 0 :(得分:11)
这个想法也许可以帮到你
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.*;
public class TilePainter extends JPanel implements Scrollable {
private static final long serialVersionUID = 1L;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Tiles");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(new TilePainter()));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
private final int TILE_SIZE = 50;
private final int TILE_COUNT = 100;
private final int visibleTiles = 10;
private final boolean[][] loaded;
private final boolean[][] loading;
private final Random random;
public TilePainter() {
setPreferredSize(new Dimension(TILE_SIZE * TILE_COUNT, TILE_SIZE * TILE_COUNT));
loaded = new boolean[TILE_COUNT][TILE_COUNT];
loading = new boolean[TILE_COUNT][TILE_COUNT];
random = new Random();
}
public boolean getTile(final int x, final int y) {
boolean canPaint = loaded[x][y];
if (!canPaint && !loading[x][y]) {
loading[x][y] = true;
Timer timer = new Timer(random.nextInt(500),
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loaded[x][y] = true;
repaint(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
}
});
timer.setRepeats(false);
timer.start();
}
return canPaint;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle clip = g.getClipBounds();
int startX = clip.x - (clip.x % TILE_SIZE);
int startY = clip.y - (clip.y % TILE_SIZE);
for (int x = startX; x < clip.x + clip.width; x += TILE_SIZE) {
for (int y = startY; y < clip.y + clip.height; y += TILE_SIZE) {
if (getTile(x / TILE_SIZE, y / TILE_SIZE)) {
g.setColor(Color.GREEN);
} else {
g.setColor(Color.RED);
}
g.fillRect(x, y, TILE_SIZE - 1, TILE_SIZE - 1);
}
}
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(visibleTiles * TILE_SIZE, visibleTiles * TILE_SIZE);
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE * Math.max(1, visibleTiles - 1);
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return TILE_SIZE;
}
}
答案 1 :(得分:6)
为什么不将Graphics2D
绘图放在(大)BufferedImage
中并将其显示在滚动窗格的标签中?像这样的东西(动画,5000x5000px):
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
public class BigScrollImage {
BigScrollImage() {
final int x = 5000;
final int y = 5000;
final BufferedImage bi = new BufferedImage(x,y,BufferedImage.TYPE_INT_RGB);
Graphics2D g1 = bi.createGraphics();
g1.setColor(Color.BLACK);
g1.fillRect(0, 0, x, y);
g1.dispose();
final JLabel label = new JLabel(new ImageIcon(bi));
ActionListener listener = new ActionListener() {
Random rand = new Random();
@Override
public void actionPerformed(ActionEvent ae) {
Graphics2D g2 = bi.createGraphics();
int x1 = rand.nextInt(x);
int x2 = rand.nextInt(x);
int y1 = rand.nextInt(y);
int y2 = rand.nextInt(y);
int r = rand.nextInt(255);
int g = rand.nextInt(255);
int b = rand.nextInt(255);
g2.setColor(new Color(r,g,b));
g2.drawLine(x1,y1,x2,y2);
g2.dispose();
label.repaint();
}
};
Timer t = new Timer(5,listener);
JScrollPane scroll = new JScrollPane(label);
JFrame f = new JFrame("Big Scroll");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.add(scroll);
f.pack();
f.setSize(800, 600);
f.setLocationByPlatform(true);
f.setVisible(true);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run() {
new BigScrollImage();
}
});
}
}
它试图每秒绘制200行,并且似乎在这里平滑滚动。
答案 2 :(得分:2)
感谢他和Gilbert Le Blanc,mKorbel的回答有我的小改编:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.LayoutManager;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.lang.ref.WeakReference;
import java.util.Random;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;
import javax.swing.Timer;
/**
*
* @author leBenj
*/
public class GJPanelBufferedImageTileAdapter extends GJPanelBufferedImageAdapter implements Scrollable
{
protected BufferedImage _image = null;
protected GIPanelListener _parent = null;
private int TILE_SIZE_W = -1;
private int TILE_SIZE_H = -1;
private int TILE_COUNT_W = 32;
private int TILE_COUNT_H = 32;
private int visibleTiles = 10;
private boolean[][] loading;
private WeakReference<BufferedImage>[][] subs;
private final Random random;
public GJPanelBufferedImageTileAdapter( final GIPanelListener parent , LayoutManager layout , boolean isDoubleBuffered )
{
super( parent , layout , isDoubleBuffered );
this._parent = parent;
resetTiling();
random = new Random();
}
public void resetTiling()
{
loading = new boolean[TILE_COUNT_W][TILE_COUNT_H];
subs = new WeakReference[TILE_COUNT_W][TILE_COUNT_H];
}
private BufferedImage getTile( int x , int y )
{
BufferedImage retour = null;
if( x < TILE_COUNT_W )
{
if( y < TILE_COUNT_H )
{
if( subs[x][y] != null )
{
retour = subs[x][y].get();
}
}
}
return retour;
}
private void setTile( BufferedImage sub , int x , int y )
{
subs[x][y] = new WeakReference<BufferedImage>( sub );
}
private boolean loadTile( final int x , final int y )
{
boolean canPaint = ( getTile( x , y ) != null );
if( x < TILE_COUNT_W )
{
if( y < TILE_COUNT_H )
{
if( !canPaint && !loading[x][y] )
{
Timer timer = new Timer( random.nextInt( 500 ) , new ActionListener()
{
@Override
public void actionPerformed( ActionEvent e )
{
BufferedImage sub = _image.getSubimage( x * TILE_SIZE_W , y * TILE_SIZE_H , TILE_SIZE_W , TILE_SIZE_H );
setTile( sub , x , y );
repaint( x * TILE_SIZE_W , y * TILE_SIZE_H , TILE_SIZE_W , TILE_SIZE_H );
}
} );
timer.setRepeats( false );
timer.start();
}
}
}
return canPaint;
}
// using paint(g) instead of paintComponent(g) to start drawing as soon as the panel is ready
@Override
protected void paint( Graphics g )
{
super.paint( g );
Rectangle clip = g.getClipBounds();
int startX = clip.x - ( clip.x % TILE_SIZE_W );
int startY = clip.y - ( clip.y % TILE_SIZE_H );
int endX = clip.x + clip.width /*- TILE_SIZE_W*/;
int endY = clip.y + clip.height /*- TILE_SIZE_H*/;
for( int x = startX ; x < endX ; x += TILE_SIZE_W )
{
for( int y = startY ; y < endY ; y += TILE_SIZE_H )
{
if( loadTile( x / TILE_SIZE_W , y / TILE_SIZE_H ) )
{
BufferedImage tile = getTile( x / TILE_SIZE_W , y / TILE_SIZE_H );
if( tile != null )
{
g.drawImage( subs[x / TILE_SIZE_W][y / TILE_SIZE_H].get() , x , y , this );
}
}
else
{
g.setColor( Color.RED );
g.fillRect( x , y , TILE_SIZE_W - 1 , TILE_SIZE_H - 1 );
}
}
}
g.dispose(); // Without this, the original view area will never be painted
}
/**
* @param image the _image to set
*/
public void setImage( BufferedImage image )
{
this._image = image;
TILE_SIZE_W = _image.getWidth() / TILE_COUNT_W;
TILE_SIZE_H = _image.getHeight() / TILE_COUNT_H;
setPreferredSize( new Dimension( TILE_SIZE_W * TILE_COUNT_W , TILE_SIZE_H * TILE_COUNT_H ) );
}
@Override
public Dimension getPreferredScrollableViewportSize()
{
return new Dimension( visibleTiles * TILE_SIZE_W , visibleTiles * TILE_SIZE_H );
}
@Override
public int getScrollableBlockIncrement( Rectangle visibleRect , int orientation , int direction )
{
if( orientation == SwingConstants.HORIZONTAL )
{
return TILE_SIZE_W * Math.max( 1 , visibleTiles - 1 );
}
else
{
return TILE_SIZE_H * Math.max( 1 , visibleTiles - 1 );
}
}
@Override
public boolean getScrollableTracksViewportHeight()
{
return false;
}
@Override
public boolean getScrollableTracksViewportWidth()
{
return false;
}
@Override
public int getScrollableUnitIncrement( Rectangle visibleRect , int orientation , int direction )
{
if( orientation == SwingConstants.HORIZONTAL )
{
return TILE_SIZE_W;
}
else
{
return TILE_SIZE_H;
}
}
}
解释:
右侧和底部滚动有一点问题:为了避免ArrayOutOfBoundsException,我在x和y上实现了测试。
我将TILE_SIZE
分成两部分,以适应图像比例。
正如我在上一条评论中的链接中所提到的,将磁贴与WeakReference数组耦合可以调节内存使用情况:我将boolean[][] loaded
替换为WeakReference[][]
并将tileGet(x,y)
函数实现为得到瓷砖。
setImage()
方法初始化类字段,例如tile的大小。
this._image
字段继承自超类,并按如下方式实现:
protected BufferedImage _image = null;
我希望这可以帮助别人。