Я работаю над игровым проектом для себя, чтобы улучшить свои навыки Java, и сегодня я столкнулся с проблемой, которую не могу решить с помощью Интернета.Большая часть этой проблемы была решена, но этот последний маленький кусочек все еще остается вызывающим!
У меня есть Объект, который расширяет Canvas и создает карту, которую я хочу отобразить.Я добавил этот холст в JPanel, который затем добавляется в область просмотра JScrollPane (которая добавляется в JFrame игры).ChangeListener добавлен в область просмотра JScrollPane, которая будет выполнять метод validate для JFrame и метод repaint для области просмотра.
Сам JFrame имеет JMenuBar, где в структуре меню есть опция «Новая игра» (средидругие, еще не реализованные JMenuItems), которые создают новый объект Canvas, заменяют старый и проверяют (используя методы validate), перерисовывают JScrollPane.
В результате при нажатии кнопки New Game JMenuItem появляется новыйкарта нарисована в моей платформе.Он отображает карту (объект холста) правильно, с полосами прокрутки, показывая вверх.Это меню сверху Canvas и полосы прокрутки, что правильно.
Но когда я немного изменяю положение полосы прокрутки (горизонтальной или вертикальной, используя панель или кнопки на панели), это приводит к тому, что объект Canvas становитсяпереведено через JFrame.Это означает, что он может перекрывать полосу прокрутки, меню (а также сразу рисуется поверх открытого меню), при этом часть объекта Canvas из поля зрения не отображается.Только когда полоса прокрутки действительно достигает своих крайних точек (не может идти дальше), она перерисовывает и проверяет всю сцену так, как должна.Но, очевидно, я хочу, чтобы это делалось и тогда, когда я только подталкивал полосу прокрутки или что-то подобное.
Мой вопрос: как я могу сделать эту работу, как задумано?
Я думаю, что мне нужно сделатьчто-то с ChangeListener, но я не могу найти решение самостоятельно.
Как я заметил, большинство из вас, ребята, просят исходный код, я предоставил это для вас:
package otherFiles;</p>
<p>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;</p>
<p>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;</p>
<p>public class ProblemDemonstrator {
private static JScrollPane dispArea = null;
private static JPanel mapPanel = null;
private static JFrame thisFrame = null;</p>
<code>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);
}
</code>
}