我的工作在该项目是玩桌面游戏的计算机间实用,而且其中的关键部分是一个互动的网格/地图。 嗯,我已经内置了对自定义地图创建功能,并希望屏幕能够显示非常大的地图,以及非常小的地图。 为此我已经创建了一系列与我可以显示任意大小的网格类。 不过我会想要做的是把此与实现成一个JScrollPane,从而对地图的无限空间的JPanel。 当我尝试这样做,显示出完美的一个JScrollPane的完全不画地图。 我怀疑它与图形方面的事,但迄今未能找到解决方案。
在下面的代码,备注滚动线和开关在初始化grid.draw方法调用看到我想什么样子。
完整的代码如下:
package pac;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
public class MainScreen extends JFrame
{
int width, height, x, y;
Grid grid;
public static void main(String[] args)
{
MainScreen mainScreen = new MainScreen();
mainScreen.setVisible(true);
}
public MainScreen()
{
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
float factor = 1.25f;
width = (int)(dim.width / factor);
height = (int)(dim.height / factor);
x = (int)(dim.width / (factor * 8));
y = (int)(dim.height / (factor * 8));
setBounds(x,y,width,height);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("DnD Main Screen");
setVisible(true);
grid = new Grid();
JScrollPane scrollPane = new JScrollPane(grid);
scrollPane.setBounds(212,0,650,500);
scrollPane.setViewportView(grid);
add(scrollPane);
this.setLayout(null);
Thread draw = new Thread()
{
public void run()
{
while(true)
{
Graphics g = getGraphics();
grid.repaint();
//grid.paintComponents(getGraphics());
g.setColor(Color.blue);
g.fillRect(0 + 8, 0 + 30, 212, 200);
g.fillRect(863 + 8, 0 + 30, 212, 200);
g.setColor(Color.red);
g.fillRect(0 + 8, 200 + 30, 212, 375);
g.fillRect(863 + 8, 200 + 30, 212, 375);
try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}
Thread.yield();
}
}
};
draw.start();
}
public class Grid extends JPanel
{
Tile[][] tiles;
public int x, y, across, down;
public int topBar = 30;
public int skinnyBar = 8;
public Grid()
{
this.setPreferredSize(new Dimension(600,600));
x=212 + skinnyBar;
y=0+topBar;
across = 13;
down = 9;
tiles = new Tile[across][down];
for(int i = 0; i<across; i++)
for(int j = 0; j<down; j++)
{
tiles[i][j] = new Tile(x+(i*50),y+(j*50),50);
}
this.setVisible(true);
}
public void paintComponents(Graphics g)
{
//super.paintComponents(g);
draw(g);
}
public void draw(Graphics g)
{
for(int i = 0; i<across; i++)
for(int j = 0; j<down; j++)
{
g.setColor(Color.black);
for(int k =0; k< 5; k++)
g.drawRect(tiles[i][j].x+k, tiles[i][j].y+k, tiles[i][j].side-k*2, tiles[i][j].side-2*k);
}
}
private class Tile
{
int x, y, side;
public Tile(int inX, int inY, int inSide)
{
x=inX;
y=inY;
side=inSide;
}
}
}
}
我一直在这一段时间,一直没能找到和问题相似,足以雷找到修复。 有什么建议? 谢谢,麻烦您了。
Answer 1:
1.don't使用空布局JScrollPan
E,使用一些标准的LayoutManager
,
2.不要使用getGraphics()
这种方法是用于打印的打印机或用于保存GUI作为快照文件的图像
人们进去理由使用draw()
准备所有Objects
前,内画一切paintComponent()
的例子4.most太旧,基于Thread
,不使用Thread
,使用Swing Timer
来代替
5.easiest可能方式
JFrame
- > JScrollPane
- > JPanel
- >通过使用GridLayout
放有所需的量JPanels
具有期望Color
,把这些JPanels
到一些类型的数组,并通过使用Swing Timer
拾起JPanel
从阵列和改变其Backgroung
例如,必须添加Swing Timer
用于paiting上期
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;
}
}
Answer 2:
你确定吗?
public void paintComponents(Graphics g)
你的意思,而不是
public void paintComponent(Graphics g)
Answer 3:
除了外界从未进行更新到UI Event Dispatching Thread
,我也建议如下:
确保Grid
窗格调用super.paintComponent(...)
这是很重要的,你真的,真的,真的必须有一个很好的理由不这样做。
如果您希望面板是透明的,使用setOpaque(false)
来代替。
我也建议你熟悉Graphics.drawLine
方法。 我认为这将是更有效
你要记住,你不必在涂料工艺控制。 只要接受它。 您可以提供请求,要更新(图形流水线invalidate
, revalidate
, repaint
),但仅此而已。 剩下的就是对操作系统和重绘管理器来决定。
this.setLayout(null);
是一个非常,非常糟糕的主意,它可能只是我的意见,但是这确实是一个坏主意。 如果不出意外结识GridBagLayout
或使用复方面板和布局管理器,它只会为你节省很多麻烦
Answer 4:
嗯,的确这表明重画一个我自己的小例子JPanel
它被包裹在JScrollPane
:
面板上有一个自定义的方法setScrollPane(JSCrollPane jsp)
后面板将被称为JScrollPane
已被初始化,这将允许JPanel
调用repaint()
的scrollPanes实例:
PanelPaintTest.java:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class PanelPaintTest extends JFrame {
public PanelPaintTest() {
createUI();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new PanelPaintTest().setVisible(true);
}
});
}
private void createUI() {
//create frame
setTitle("JPanel and JScrollPane Paint Test");
setSize(500, 500);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//create custom panel
Panel panel = new Panel(500, 500);
//create scrollpane to hold JPanel
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(panel);
panel.setScrollPane(scrollPane);
//custom method to set the panels JScrollPane which will be repainted when ever the panel is
getContentPane().add(scrollPane);//add scrollpane to the frame
}
}
Panel.java
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
class Panel extends JPanel {
private int width, height, across, down, x = 0, y = 0;
;
private Panel.Tile[][] tiles;
private Color color = Color.black;
private JScrollPane scrollPane;
public Panel(int width, int height) {
this.setPreferredSize(new Dimension(width * 2, height * 2));//simple to make the scrollbars visible
this.width = width * 2;
this.height = height * 2;
createTiles();
changePanelColorTimer();//just something to do to check if its repaints fine
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int i = 0; i < across; i++) {
for (int j = 0; j < down; j++) {
g.setColor(color);
for (int k = 0; k < 5; k++) {
g.drawRect(tiles[i][j].x + k, tiles[i][j].y + k, tiles[i][j].side - k * 2, tiles[i][j].side - 2 * k);
}
}
}
updateScrollPane();//refresh the pane after every paint
}
//calls repaint on the scrollPane instance
private void updateScrollPane() {
scrollPane.repaint();
}
void setScrollPane(JScrollPane scrollPane) {
this.scrollPane = scrollPane;
}
private void createTiles() {
across = 13;
down = 9;
tiles = new Panel.Tile[across][down];
for (int i = 0; i < across; i++) {
for (int j = 0; j < down; j++) {
tiles[i][j] = new Panel.Tile(x + (i * 50), y + (j * 50), 50);//took out x and y values didnt know what
}
}
}
//change the color of the grid lines from black to red and vice versa every 2s
private void changePanelColorTimer() {
Timer timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (color == Color.black) {
color = Color.red;
} else {
color = Color.black;
}
}
});
timer.setInitialDelay(2000);
timer.start();
}
private class Tile {
int x, y, side;
public Tile(int inX, int inY, int inSide) {
x = inX;
y = inY;
side = inSide;
}
}
}
该小组将吸引你表现出的瓷砖,他们会闪烁红色或黑色的每2秒。
HTH
文章来源: Repainting a JPanel in a JScrollPane