2012-08-08 79 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