java frame 画图有时候会越出窗口

时间:2023-02-04 17:24:06
不明白是什么原理,棋盘的竖线有时会越过顶部边界,有时可以正确显示。



import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class Panel2 extends Frame {
    private final int margin_left = 10;
    private final int margin_top = 10;
    private final int block_size = 20;
    private final int board_dim = 15;
    
    public Panel2() {
        setTitle("五子棋游戏");
        setVisible(true);
        setLayout(null);
        setBounds(0, 0, 600, 600);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        setBackground(Color.YELLOW);
    }

    public void paint(Graphics g) {
        int i;
        for (i = 0; i < board_dim; i++) {
            // 横线 15*15的棋盘 
            int x1 = margin_left;
            int y1 = margin_top + i * block_size;
            int x2 = margin_left + block_size*(board_dim-1);
            int y2 = y1;
            g.drawLine(x1, y1, x2, y2);
        }
        for (i = 0; i < board_dim; i++) {
            // 竖线 15*15的棋盘 
            int x1 = margin_left + i * block_size;
            int y1 = margin_top;
            int x2 = x1;
            int y2 = margin_top + block_size*(board_dim-1);
            g.drawLine(x1, y1, x2, y2);
        }
        int radius = 3;
        int x1 = margin_left + board_dim/2*block_size;
        int y1 = margin_top + board_dim/2*block_size;
        g.fillOval(x1 - radius, y1 - radius, radius*2, radius*2);// 画点
        int shift = (board_dim/4+1)*block_size;
        g.fillOval(x1- shift - radius, y1 -shift - radius, radius*2, radius*2);
        g.fillOval(x1-shift - radius, y1 +shift - radius, radius*2, radius*2);
        g.fillOval(x1+shift - radius, y1 -shift - radius, radius*2, radius*2);
        g.fillOval(x1+shift - radius, y1 +shift - radius, radius*2, radius*2);
       
    }
    
    public static void main(String[] args) {
        Panel2 p = new Panel2();
    }
}


请大家帮忙分析一下,啥原因呢

8 个解决方案

#1


 setBounds(0, 0, 600, 600);   这个组建的600*600是整体大小,包含了边框

 private final int margin_top = 50; 设置大一些就可以了

#2


这是正确的情况
java frame 画图有时候会越出窗口
这是有问题的情况
java frame 画图有时候会越出窗口

同样的代码,执行的结果不一样,可能是一些渲染线程的问题,但我不知道如何去找

#3


引用 1 楼 lonrence 的回复:
 setBounds(0, 0, 600, 600);   这个组建的600*600是整体大小,包含了边框

 private final int margin_top = 50; 设置大一些就可以了


谢谢你的回答,然而,
并不是这样的问题,横线从来没有越过边界。

#4


帮你改造了下
先是Frame

package test;

import java.awt.Color;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class WuziFrame extends JFrame {
private static final long serialVersionUID = 1L;

public WuziFrame() {
        setTitle("五子棋游戏");
        
        setLayout(null);
        setBounds(0, 0, 600, 600);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        setBackground(Color.YELLOW);
        Panel1 panel1 = new Panel1();
        
        this.setContentPane(panel1);
    }
   
    public static void main(String[] args) {
     WuziFrame p = new WuziFrame();
        p.setVisible(true);
    }
}

下面是面板Panel1

package test;
import java.awt.Graphics;

import javax.swing.JPanel;

public class Panel1 extends JPanel {
private static final long serialVersionUID = 1L;
private final int margin_left = 10;
    private final int margin_top = 10;
    private final int block_size = 20;
    private final int board_dim = 15;
public void paint(Graphics g) {
        int i;
        for (i = 0; i < board_dim; i++) {
            // 横线 15*15的棋盘 
            int x1 = margin_left;
            int y1 = margin_top + i * block_size;
            int x2 = margin_left + block_size*(board_dim-1);
            int y2 = y1;
            g.drawLine(x1, y1, x2, y2);
            System.out.println(x1+","+y1);
        }
        for (i = 0; i < board_dim; i++) {
            // 竖线 15*15的棋盘 
            int x1 = margin_left + i * block_size;
            int y1 = margin_top;
            int x2 = x1;
            int y2 = margin_top + block_size*(board_dim-1);
            g.drawLine(x1, y1, x2, y2);
        }
        int radius = 3;
        int x1 = margin_left + board_dim/2*block_size;
        int y1 = margin_top + board_dim/2*block_size;
        g.fillOval(x1 - radius, y1 - radius, radius*2, radius*2);// 画点
        int shift = (board_dim/4+1)*block_size;
        g.fillOval(x1- shift - radius, y1 -shift - radius, radius*2, radius*2);
        g.fillOval(x1-shift - radius, y1 +shift - radius, radius*2, radius*2);
        g.fillOval(x1+shift - radius, y1 -shift - radius, radius*2, radius*2);
        g.fillOval(x1+shift - radius, y1 +shift - radius, radius*2, radius*2);

    }
}

#5


另外,awt里的Frame的边界是从标题栏算起,而swing中的JFrame是从内容面板算,这就是导致你画出来的表格显示不完整的原因,你用awt的Frame的话,就要把top上的距离设大一点

#6


这个问题的解决方案是在setVisible方法后面(只有在此方法之后调用才有效)添加一些代码(需要把这些变量的final修饰符去掉):

setVisible(true);
Insets i = getInsets();
margin_left += i.left;
margin_top += i.top;
repaint();


原理如楼上所讲,paint中的graphics绘图原点在窗体的左上角(也算标题栏,在关闭按钮的左上边那个角)
其度量方法就是获得窗体的Insets,表示上下左右边界的宽度。
调用完以上方法后repaint()重绘窗体,使修改生效。

最好的办法是不要直接在frame中绘图,而是extends某个componet,如panel等,重写它们的paint和update方法。它们的左上角一定会在窗体的里面的,而且易于通过布局控制大小和位置。

另,现在不再推荐使用Frame,而是使用JFrame。

#7


说实话,这个swing属于native的方案,将来趋势是html5建议使用html5来做界面啦。。方便有跨平台。

#8


JFrame只是一个外框,里面有一个内容面板,你的JPanel添加到这个内容面板上,所以绘制的时候所有的内容不是画在JFrame上,而是画在JPanel上,你要用JPanel的大小作为边界条件。

参考四楼的代码,虽然我没仔细看,但是大概是那个意思

#1


 setBounds(0, 0, 600, 600);   这个组建的600*600是整体大小,包含了边框

 private final int margin_top = 50; 设置大一些就可以了

#2


这是正确的情况
java frame 画图有时候会越出窗口
这是有问题的情况
java frame 画图有时候会越出窗口

同样的代码,执行的结果不一样,可能是一些渲染线程的问题,但我不知道如何去找

#3


引用 1 楼 lonrence 的回复:
 setBounds(0, 0, 600, 600);   这个组建的600*600是整体大小,包含了边框

 private final int margin_top = 50; 设置大一些就可以了


谢谢你的回答,然而,
并不是这样的问题,横线从来没有越过边界。

#4


帮你改造了下
先是Frame

package test;

import java.awt.Color;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class WuziFrame extends JFrame {
private static final long serialVersionUID = 1L;

public WuziFrame() {
        setTitle("五子棋游戏");
        
        setLayout(null);
        setBounds(0, 0, 600, 600);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        setBackground(Color.YELLOW);
        Panel1 panel1 = new Panel1();
        
        this.setContentPane(panel1);
    }
   
    public static void main(String[] args) {
     WuziFrame p = new WuziFrame();
        p.setVisible(true);
    }
}

下面是面板Panel1

package test;
import java.awt.Graphics;

import javax.swing.JPanel;

public class Panel1 extends JPanel {
private static final long serialVersionUID = 1L;
private final int margin_left = 10;
    private final int margin_top = 10;
    private final int block_size = 20;
    private final int board_dim = 15;
public void paint(Graphics g) {
        int i;
        for (i = 0; i < board_dim; i++) {
            // 横线 15*15的棋盘 
            int x1 = margin_left;
            int y1 = margin_top + i * block_size;
            int x2 = margin_left + block_size*(board_dim-1);
            int y2 = y1;
            g.drawLine(x1, y1, x2, y2);
            System.out.println(x1+","+y1);
        }
        for (i = 0; i < board_dim; i++) {
            // 竖线 15*15的棋盘 
            int x1 = margin_left + i * block_size;
            int y1 = margin_top;
            int x2 = x1;
            int y2 = margin_top + block_size*(board_dim-1);
            g.drawLine(x1, y1, x2, y2);
        }
        int radius = 3;
        int x1 = margin_left + board_dim/2*block_size;
        int y1 = margin_top + board_dim/2*block_size;
        g.fillOval(x1 - radius, y1 - radius, radius*2, radius*2);// 画点
        int shift = (board_dim/4+1)*block_size;
        g.fillOval(x1- shift - radius, y1 -shift - radius, radius*2, radius*2);
        g.fillOval(x1-shift - radius, y1 +shift - radius, radius*2, radius*2);
        g.fillOval(x1+shift - radius, y1 -shift - radius, radius*2, radius*2);
        g.fillOval(x1+shift - radius, y1 +shift - radius, radius*2, radius*2);

    }
}

#5


另外,awt里的Frame的边界是从标题栏算起,而swing中的JFrame是从内容面板算,这就是导致你画出来的表格显示不完整的原因,你用awt的Frame的话,就要把top上的距离设大一点

#6


这个问题的解决方案是在setVisible方法后面(只有在此方法之后调用才有效)添加一些代码(需要把这些变量的final修饰符去掉):

setVisible(true);
Insets i = getInsets();
margin_left += i.left;
margin_top += i.top;
repaint();


原理如楼上所讲,paint中的graphics绘图原点在窗体的左上角(也算标题栏,在关闭按钮的左上边那个角)
其度量方法就是获得窗体的Insets,表示上下左右边界的宽度。
调用完以上方法后repaint()重绘窗体,使修改生效。

最好的办法是不要直接在frame中绘图,而是extends某个componet,如panel等,重写它们的paint和update方法。它们的左上角一定会在窗体的里面的,而且易于通过布局控制大小和位置。

另,现在不再推荐使用Frame,而是使用JFrame。

#7


说实话,这个swing属于native的方案,将来趋势是html5建议使用html5来做界面啦。。方便有跨平台。

#8


JFrame只是一个外框,里面有一个内容面板,你的JPanel添加到这个内容面板上,所以绘制的时候所有的内容不是画在JFrame上,而是画在JPanel上,你要用JPanel的大小作为边界条件。

参考四楼的代码,虽然我没仔细看,但是大概是那个意思