2012-08-08 54 views
4

我正在使用的项目是用于玩桌面游戏的计算机间实用程序,其中的关键部分是交互式网格/地图。那么我已经建立了自定义地图创建功能,并希望屏幕能够显示非常大的地图,以及非常小的地图。为此,我创建了一系列可以显示任意大小的网格的类。然而,我想要做的就是将JPanel与JScrollPane合并到一起,从而为地图创造无限空间。当我尝试这样做时,完全脱离JScrollPane的地图完全不会绘制。我怀疑它与Graphics上下文有关,但迄今一直无法找到解决方案。在JScrollPane中重绘一个JPanel

在以下代码中,重新标记滚动行并在初始化中切换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; 
     } 
    } 
} 

}

我一直在这一段时间,一直没能找到和问题相似,足以雷找到修复。有什么建议?谢谢,麻烦您了。

+1

摇摆的第1章,永远,永远,永远不要画什么为一个好地方做的'事件调度Thread'外的UI,永远 – MadProgrammer 2012-08-08 05:58:33

回答

7

1.don't使用空布局的JScrollPan E,使用一些标准LayoutManager的,

2.不使用getGraphics(),此方法用于打印到打印机或用于保存GUI作为快照到文件的图像

3。有没有必要使用draw(),前后画里面的一切paintComponent()

4.most的例子是太旧了,基于Thread准备所有Objects,不要使用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; 
    } 
} 
+2

非常感谢您查看我的代码和示例代码,我一定会在早上实施一些代码。老实说,我一直在使用一些古老的教程示例,并且不太了解swing的内部工作原理,或者一般的java。我认为这是目前最好的答案。 – bluesawdust 2012-08-08 07:08:07

+0

+1不错的一个.. :) – 2012-08-08 07:21:16

+0

超级简单实用的例子,很好!我在“第一场秀”中缺乏重新粉刷的努力,在定时器内部重绘(...)的内部呼吁解决了这个问题。谢谢 ! – Benj 2013-05-26 00:20:09

5

您确定吗?

public void paintComponents(Graphics g) 

你从外面Event Dispatching Thread执行NEVER更新到UI的意思,而不是

public void paintComponent(Graphics g) 
+3

+1! – MadProgrammer 2012-08-08 06:09:10

4

除此之外,我还建议如下:

确保Grid窗格调用super.paintComponent(...)这很重要,你真的,真的不得不有一个很好的理由不要。

如果希望面板透明,请改用setOpaque(false)

我也建议你熟悉Graphics.drawLine方法。我认为它会更有效率

你要记住,你不要有控制油漆过程。只要接受它。您可以向要更新的图形管道提供请求(invalidaterevalidaterepaint),但就是这样。其余的由操作系统和重绘经理决定。

this.setLayout(null);是一个非常糟糕的主意,它可能只是我的观点,但这真的是一个坏主意。如果不出意外结识GridBagLayout或使用复方面板和布局管理器,它只会为你节省很多麻烦

+0

谢谢你的建议,我很抱歉我的坏技术,但我还没有任何正式的Java类。我仅仅从教程中知道自己掌握的尽可能多的Java,并且经常尝试将我的C#体验与Java混合使用。我会尽力实施你所建议的。 – bluesawdust 2012-08-08 07:05:08

+0

+1伟大的建议 – 2012-08-08 07:23:01

+0

@bluesawdust不要道歉有勇气寻求建议;)。结帐http://docs.oracle.com/javase/tutorial/uiswing/它有一个关于自定义绘画的部分,您可能还想看看http://docs.oracle.com/javase/tutorial/2d/index。 html – MadProgrammer 2012-08-08 07:27:45

4

嗯,的确这表明重画一个JPanel这是在包裹我自己的小例子a JScrollPane

该面板有一个自定义方法setScrollPane(JSCrollPane jsp),将在面板和JScrollPane有蜂后调用ñ初始化这将使JPanel来呼吁scrollPanes repaint()例如:

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

+3

+1在你将'util.Timer'改为'Swing定时器... – mKorbel 2012-08-08 07:25:55

+0

@mKorbel谢谢你,帮助我快速学习新的摇摆定时器,从现在开始使用生病:) – 2012-08-08 08:47:25

+0

previous up_voted – mKorbel 2012-08-08 08:51:22