2011-02-06 18 views
1


私はJavaのスキルを向上させるためのゲームプロジェクトに取り組んでいます。私は今日、援助で解決できないような問題に遭遇しましたインターネットのこの問題の大半は解決されましたが、この最後の少しはまだ反抗的なままです!JScrollPaneのキャンバスは、スクロールバーが最も極端な点にあるときにのみ再描画します

キャンバスを拡張して表示するマップを作成するオブジェクトがあります。このCanvasをJPanelに追加しました。このJPanelは、JScrollPane(ゲームのJFrameに追加される)のビューポートに追加されます。 ChangeListenerがJScrollPaneのビューポートに追加され、JFrameのvalidateメソッドとビューポートのrepaintメソッドが実行されます。
JFrame自体にはJMenuBarがあります。メニュー構造内には、新しいCanvasオブジェクトを作成し、古いものを置き換えて(validateメソッドを使用して)再ペイントするための 'New Game'オプション(まだ実装されていないJMenuItemの中でも) JScrollPane

結果は、新しいゲームJMenuItemを押すと、私のscollpaneに新しいマップが引き出されます。 Scollbarsが表示され、マップ(Canvas Object)が正しく表示されます。メニューはキャンバスとスクロールペインの上にありますが、それは正しいです。
しかし、バーやバーのボタンを使ってスクロールバーの位置(水平または垂直)を少し変更すると、キャンバスオブジェクトがJFrame全体に翻訳されます。つまり、表示されていないCanvasオブジェクトの部分が表示されていない状態で、可能であればScollbarと重なることになります(メニューバーのすぐ上に描画されます)。スクロールバーが実際にヒットしたときに限り、それは極端な点です(それ以上は行けません)、それは必要に応じてシーン全体を再ペイントし、検証します。しかし、明らかに、私はスクロールバーやそれに類するものだけを振っているときにもこれをやりたい。

私の質問は次のとおりです。どうすればこの作業を意図した通りにすることができますか?
私はChangeListenerで何かする必要があると思いますが、自分で解決策を見つけることができません。

私はあなたたちのほとんどはソースコードを求める気づいたように、私はあなたのためにこれを提供してきました:

 
package otherFiles;

import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList;

import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JScrollPane;

public class ProblemDemonstrator { private static JScrollPane dispArea = null; private static JPanel mapPanel = null; private static JFrame thisFrame = null;

private static final int FRAME_WIDTH = 300; private static final int FRAME_HEIGTH = 300; private static boolean mode = false; public static void main(String[] args){ JFrame mainMenu = myMenuFrame(); mainMenu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainMenu.setVisible(true); } public static JFrame myMenuFrame(){ thisFrame = new JFrame("Problem Demonstrator"); thisFrame.setSize(FRAME_WIDTH, FRAME_HEIGTH); thisFrame.setLayout(new BorderLayout()); //Create the menu bar and corresponding menu's. JMenuBar menuBar = new JMenuBar(); thisFrame.setJMenuBar(menuBar); menuBar.add(createFileMenu(),BorderLayout.NORTH); //Create a scroll-able game display area dispArea = new JScrollPane(); dispArea.setSize(thisFrame.getSize()); thisFrame.getContentPane().add(dispArea, BorderLayout.CENTER); return thisFrame; } private static JMenu createFileMenu() { JMenu menu = new JMenu("File"); menu.add(createFile_NewGameItem()); //New game button return menu; } /** * The button for the creation of a new game. * @return The JMenuItem for starting a new game. */ private static JMenuItem createFile_NewGameItem() { JMenuItem item = new JMenuItem("New Game"); class MenuItemListener implements ActionListener { @Override public void actionPerformed(ActionEvent arg0) { System.out.println("actionPerformed - New Game [JMenuItem]"); if(mapPanel == null){ mapPanel = createGameMap(mode); dispArea.setViewportView(mapPanel); }else{ dispArea.getViewport().remove(mapPanel); mapPanel = createGameMap(mode); dispArea.setViewportView(mapPanel); } //'flip' mode if(mode){ mode = false; }else{ mode = true; } thisFrame.pack(); thisFrame.setSize(FRAME_WIDTH, FRAME_HEIGTH); dispArea.repaint(); thisFrame.validate(); } } ActionListener l = new MenuItemListener(); item.addActionListener(l); return item; } /** * This creates the displayable map that has to go in the JScrollPane * @param mode Just a variables to be able to create 'random' maps. * @return The displayable map, a JPanel */ private static JPanel createGameMap(boolean mode){ /** * This is a quick version of the planets I generate for the map. * Normally this is a another class object, using another class called Planet * to set parameters like the location, size and color in it's constructor. * x = the x location on the map (center of the planet!) * y = the y location on the map (also center) * diam = the diameter of the planet */ @SuppressWarnings("serial") class myPlanetComponent extends JComponent{ private int x,y,diam; public myPlanetComponent(int x, int y, int diam){ this.x = x; this.y =y; this.diam = diam; } //Paint a circle on with the centre on (x,y) public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.BLUE); Ellipse2D.Double circle = new Ellipse2D.Double((x-diam/2), (y-diam/2), diam, diam ); g2.fill(circle); g2.setColor(Color.DARK_GRAY); g2.draw(circle); //I want a border around my planet } public int getX(){ return this.x; } public int getY(){ return this.y; } } /** * This is also a quick way version of how I create the map display * I intend to use in my game. It's a collection of planets with lines * between them, on a black background. */ @SuppressWarnings("serial") class myMap extends JPanel{ private boolean modeOne; private int sizeX, sizeY; public myMap(boolean mode){ this.sizeX = 500; this.sizeY = 500; this.modeOne = mode; //JPanel map = new JPanel(); this.setSize(this.sizeX, this.sizeY); } public int getSizeX(){ return this.sizeX; } public int getSizeY(){ return this.sizeY; } public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D) g; //Create the black background plane //this.setBackground(Color.BLACK); //Tried it with this, but won't give any bakcground int heightBG = this.getSizeX(); int widthBG = this.getSizeY(); Rectangle2D.Double SpaceBackGround = new Rectangle2D.Double(0,0, heightBG, widthBG); g2.setColor(Color.BLACK); g2.fill(SpaceBackGround); //Normally, I import this list from somewhere else, but the result //is very similar. ArrayList<myPlanetComponent> planetsList = new ArrayList<myPlanetComponent>(5); //Need to be able to generate at least 2 different maps to demonstrate //the effects of using the New game button. Normally this list is randomly //generated somewhere else, but idea stays the same. if(modeOne){ planetsList.add(new myPlanetComponent(20,20,20)); planetsList.add(new myPlanetComponent(70,30,20)); planetsList.add(new myPlanetComponent(130,210,20)); planetsList.add(new myPlanetComponent(88,400,20)); planetsList.add(new myPlanetComponent(321,123,20)); }else{ planetsList.add(new myPlanetComponent(40,40,20)); planetsList.add(new myPlanetComponent(140,60,20)); planetsList.add(new myPlanetComponent(260,420,20)); planetsList.add(new myPlanetComponent(176,200,20)); planetsList.add(new myPlanetComponent(160,246,20)); } //for all planets for(int i=0; i<planetsList.size()-1; i++){ //planet 1 coordinates myPlanetComponent p1 = planetsList.get(i); if(i == 0){ p1.paintComponent(g2); //Only draw all planets once } //start coordinates of the line int x1 = p1.getX(); int y1 = p1.getY(); //Be smart, and don't do things double! for(int j=i+1; j<planetsList.size(); j++){ myPlanetComponent p2 = planetsList.get(j);; if(i == 0){ p2.paintComponent(g2); //Only Draw all planets once } //planet 2 coordinates, endpoint of the line int x2 = p2.getX(); int y2 = p2.getY(); Line2D.Double tradeRoute = new Line2D.Double(x1, y1, x2, y2); g2.setColor(Color.GREEN); g2.draw(tradeRoute); } } } } return new myMap(mode); }

}

答えて

4

あなたの問題は、あなたがAWTを混合することが可能とSwing(重い重量と軽量)のコンポーネントが同じプログラムに含まれています。これは明確なニーズがあり、何をしているのかを知っている場合を除いて、実行すべきではありません。私は、JScrollPanesがこの種のものをそのままの状態で処理できるように、ChangeListenerが必要であるとは思わない。あなたのクラスがCanvasの代わりにJPanelまたはJComponentを拡張しようとしましたか?

また、コードを投稿する際には、実行可能なコンパイル可能な実行可能プログラムであるSSCCEを作成して投稿することを検討してください。このタイプのコードを作成して投稿すると、まともなソリューションをすぐに手に入れることができます。

編集:CanvasがJScrollPanesに与える影響を確認するためのテストプログラムを作成しました。キャンバスがスクロールバーやその他すべてをカバーしています。このコードをコンパイルして実行し、クリックしてドラッグしてJFrameのサイズを変更してください。キャンバスは青色で、左側はJScrollPaneにあり、JPanelは赤色で、右側のJScrollPaneにあります。

import java.awt.*; 

import javax.swing.*; 

@SuppressWarnings("serial") 
public class CanvasInScrollPane extends JPanel { 
    private static final Dimension CANVAS_SIZE = new Dimension(300, 300); 
    private static final Dimension APP_SIZE = new Dimension(500, 250); 
    Canvas canvas = new Canvas(); 
    JPanel panel = new JPanel(); 

    public CanvasInScrollPane() { 
     canvas.setPreferredSize(CANVAS_SIZE); 
     canvas.setBackground(Color.blue); 

     panel.setPreferredSize(CANVAS_SIZE); 
     panel.setBackground(Color.red); 

     setPreferredSize(APP_SIZE); 
     setLayout(new GridLayout(1, 0, 5, 0)); 
     add(new JScrollPane(canvas)); 
     add(new JScrollPane(panel)); 
    } 

    private static void createAndShowUI() { 
     JFrame frame = new JFrame("CanvasInScrollPane"); 
     frame.getContentPane().add(new CanvasInScrollPane()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     java.awt.EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

すぐにこれを応答いただきありがとうございます。HoverCraft Eels!悲しいことに、私は私の論文で忙しいので、遅くこれに答えることができました。あなたが要求した通りにSSCCEを追加しました。問題の内容を簡単に指摘できれば幸いです。私のゲームマップをどのようにリフレッシュするのかを示しています(それがなぜ動作しないのかの原因の1つかもしれません)。私は今、Canvasの代わりにJPanelを使用してコードを少し変更しました。今問題はスクロールバーが表示されないことです。 – Xilconic

+0

setPreferredSize(new Dimension(...))を呼び出す必要があるときに、コード内でsetSizeを呼び出しています。その理由はpreferredSizeは、レイアウトするコンポーネントのサイズを設定する際に、現在のレイアウトマネージャが尊重しているものです。 –

+0

ああ、それは確かにそのためです!ホバークラフト満月のうなぎをありがとう! – Xilconic

関連する問題