Я пытаюсь реализовать простое приложение с алгоритмом заполнения границ в java, и каждый раз, когда я получаю ошибку stackoverflow, и я не знаю почему.Boundary fill java вызывает stackOverflow
от сообщения, которое я видел, я считаю, что это из-за робота.
здесь код
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
@SuppressWarnings("serial")
public class drawfill extends JPanel implements MouseListener,MouseMotionListener {
public static JFrame shell;
public static Dimension shellSize = new Dimension(500, 500);
public Graphics2D G;
public Color boundaryColor = Color.black;
public Color fillColor = Color.yellow;
public int xInit;
public int yInit;
public int xFinal;
public int yFinal;
public boolean fill = false;
public Robot rb;
BufferedImage img;
Graphics2D gimg;
public static void main(String[] args) throws AWTException {
shell = new JFrame("Draw");
shell.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
shell.setLayout(new BorderLayout());
shell.setMinimumSize(shellSize);
shell.setResizable(false);
drawfill dpanel = new drawfill();
RadioPanelClass radio = dpanel.new RadioPanelClass();
shell.add(radio,BorderLayout.NORTH);
shell.add(dpanel,BorderLayout.CENTER);
shell.setVisible(true);
shell.setLocationRelativeTo(null);
}
public drawfill() throws AWTException{
rb = new Robot();
super.setBackground(Color.white);
changeCursor(true);
super.addMouseMotionListener(this);
super.addMouseListener(this);
}
public void paint(Graphics g){
G = (Graphics2D)g;
super.paint(G);
G.setColor(boundaryColor);
G.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
G.drawRect(xInit, yInit, xFinal - xInit, yFinal - yInit);
}
public void changeCursor(boolean b){
//true for draw
//flase for fill
if (b)
super.setCursor(Cursor.getPredefinedCursor (Cursor.CROSSHAIR_CURSOR));
else
super.setCursor(Cursor.getPredefinedCursor (Cursor.HAND_CURSOR));
}
public Color getPixel(int x,int y){
return rb.getPixelColor(x,y);
}
public void setPixel(int x,int y,Color color){
G.setColor(color);
G.fillOval(x, y, 1, 1);
}
public void boundaryFill(int x, int y, Color fill,Color boundary) {
Color interior = getPixel(x,y);
//System.out.println(interior.toString());
if (interior != boundary && interior != fill){
setPixel(x,y,fill);
boundaryFill(x+1,y,fill,boundary);
boundaryFill(x-1,y,fill,boundary);
boundaryFill(x,y+1,fill,boundary);
boundaryFill(x,y-1,fill,boundary);
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (fill){
int x = e.getX();
int y = e.getY();
boundaryFill(x,y,fillColor,boundaryColor);
}
}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
@Override
public void mousePressed(MouseEvent e) {
if (!fill){
xInit = e.getX();
yInit = e.getY();
}
}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseDragged(MouseEvent e) {
if (!fill){
xFinal = e.getX();
yFinal = e.getY();
repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {}
class RadioPanelClass extends JPanel implements ActionListener {
RadioPanelClass(){
JRadioButton draw = new JRadioButton("draw");
draw.setActionCommand("draw");
draw.setSelected(true);
JRadioButton fill = new JRadioButton("fill");
fill.setActionCommand("fill");
super.add(draw);
super.add(fill);
ButtonGroup TypeRadio = new ButtonGroup();
TypeRadio.add(draw);
TypeRadio.add(fill);
// Register a listener for the radio buttons.
draw.addActionListener(this);
fill.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
if (actionCommand == "draw") {
changeCursor(true);
}
else if (actionCommand == "fill"){
changeCursor(false);
fill = true;
}
}
}
}
Ошибка:
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at sun.nio.cs.SingleByte.withResult(Unknown Source)
at sun.nio.cs.SingleByte.access$000(Unknown Source)
at sun.nio.cs.SingleByte$Encoder.encodeArrayLoop(Unknown Source)
at sun.nio.cs.SingleByte$Encoder.encodeLoop(Unknown Source)
at java.nio.charset.CharsetEncoder.encode(Unknown Source)
at sun.nio.cs.StreamEncoder.implWrite(Unknown Source)
at sun.nio.cs.StreamEncoder.write(Unknown Source)
at java.io.OutputStreamWriter.write(Unknown Source)
at java.io.BufferedWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at test.drawfill.boundaryFill(drawfill.java:99)
at test.drawfill.boundaryFill(drawfill.java:102)
at test.drawfill.boundaryFill(drawfill.java:102)
UPDATE:
я пытался изменить код и использовать BufferedImage
, но вместо этого я и до сих пор получаю тот же stackOverFlow
ошибку здесь обновленный код:
public void paintComponent(Graphics g){
G = (Graphics2D)g;
super.paintComponent(G);
super.setBackground(Color.white);
bi = new BufferedImage(super.getWidth(),super.getHeight(),BufferedImage.TYPE_INT_RGB);
gbi = bi.createGraphics();
gbi.setBackground(Color.WHITE);
gbi.clearRect(0,0,super.getWidth(),super.getHeight());
gbi.setColor(boundaryColor);
gbi.drawRect(xInit, yInit, xFinal - xInit, yFinal - yInit);
G.drawImage(bi, 0,0,null);
gbi.dispose();
}
public Color getPixel(int x,int y){
return new Color(bi.getRGB(x, y));
}
public void setPixel(int x,int y,Color color){
bi.setRGB(x, y, color.getRGB());
repaint();
}
public void boundaryFill(int x, int y, Color fill,Color boundary) {
if ((x>= xInit && x<= xFinal) && (y>= yInit && y<=yFinal)){
Color interior = getPixel(x,y);
//System.out.println(interior.toString());
if (interior != boundary && interior != fill){
setPixel(x,y,fill);
boundaryFill(x+1,y,fill,boundary);
boundaryFill(x-1,y,fill,boundary);
boundaryFill(x,y+1,fill,boundary);
boundaryFill(x,y-1,fill,boundary);
}
else
return;
}
else
return;
}
Я не у меня есть время копать глубже, но я предполагаю, что это вызвано бесконечным рекурсивным циклом. Я подозреваю, что 'borderFill' бесконечно вызывает себя, не достигнув условия завершения, которое позволяет ему выйти. В конечном итоге это вызовет запуск стека вне пространства, и вы получите StackOverflowError, который вы видите. – Bobulous
Почему 'getPixel' доступа' rb', но 'setPixel' управляет' G'? –
@ScottHunter есть ли другой способ перенести эту операцию? – Tarounen