如何使Java GUI仅按需绘制?

如何使Java GUI仅按需绘制?,java,l-systems,Java,L Systems,我的应用程序旨在使用L系统绘制一棵树。我从一个公理开始,为下一代应该用什么取代什么提供一个规则。我将JFrame/JPanel组合用于一个按钮(将来可能会更多)/JComponent用于绘图区域。我编写了一个小海龟图形方法(前进、右转、左转、推动当前变换、弹出变换)。每次单击“生成”按钮时,我都会调用repaint(),而repaint()又会调用turtleDraw() package.com.flak; 导入javax.swing.*; 导入java.awt.*; 导入java.awt.ev

我的应用程序旨在使用L系统绘制一棵树。我从一个公理开始,为下一代应该用什么取代什么提供一个规则。我将JFrame/JPanel组合用于一个按钮(将来可能会更多)/JComponent用于绘图区域。我编写了一个小海龟图形方法(前进、右转、左转、推动当前变换、弹出变换)。每次单击“生成”按钮时,我都会调用repaint(),而repaint()又会调用turtleDraw()

package.com.flak;
导入javax.swing.*;
导入java.awt.*;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.geom.*;
导入java.util.HashMap;
导入java.util.Map;
导入java.util.Stack;
@抑制警告(“串行”)
公共类LSystemTree扩展了JFrame{
按钮生成按钮;
int currentAction=1;
公共静态void main(字符串[]args){
新的LSystemTree();
}
公共LSystemTree(){
这个。设置大小(600600);
本文件的标题为“L-系统树”;
此.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
此参数为.setresizeable(false);
JPanel buttonPanel=新的JPanel();
Box=Box.createHorizontalBox();
generateBut=生成按钮(“生成”,1);
框。添加(generateBut);
按钮面板。添加(框);
映射规则=新建HashMap();
规则。将“F”、“FF+[+F-F-F]-[-F+F+F]”放入;
添加(buttonPanel,BorderLayout.NORTH);
添加(新的树形布局(“F”,22.5,规则),BorderLayout.CENTER);
此.setVisible(true);
}
公共JButton makeButton(字符串文本,final int actionNum){
JButton theBut=新JButton();
theBut.setText(文本);
theBut.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
currentAction=actionNum;
System.out.println(“actionNum:+actionNum”);
重新油漆();
}
});
返回theBut;
}
私有类树拖动扩展了JComponent{
私有字符串公理;
私刑;
私人双角度;
私有地图规则;
私家侦探;
私有堆栈转换堆栈;
公共树绘制(字符串公理、双角度、映射规则){
这个公理=公理;
这个句子=公理;
this.angle=Math.toRadians(角度);
这个。规则=规则;
len=100;
transformStack=新堆栈();
}
public void generate(){
len/=2;
字符串nextContent=“”;
for(int i=0;i<句子长度();i++){
char current=句子charAt(i);
布尔值=false;
if(rules.containsKey(String.valueOf(current))){
发现=真;
nextContent+=rules.get(String.valueOf(current));
}
如果(!找到){
下一个内容+=当前;
}
}
句子=下一个内容;
}
私人空心套头衫(Graphics2D g2d){
translate(getWidth()/2,getHeight());
for(int i=0;i<句子长度();i++){
char current=句子charAt(i);
如果(当前='F'){
g2d.绘制线(0,0,0,-len);
翻译(0,-len);
}else if(当前=='+'){
g2d.旋转(角度);
}否则如果(当前=='-'){
g2d.旋转(-角度);
}else if(当前=='['){
push(g2d.getTransform());
}else if(当前==']'){
setTransform(transformStack.pop());
}
}
生成();
System.out.println(句子);
}
@凌驾
公共组件(图形g){
Graphics2D g2d=(Graphics2D)g;
g2d.setRenderingHint(renderingHits.KEY\u抗锯齿,renderingHits.VALUE\u抗锯齿\u开启);
套头衫(g2d);
g2d.dispose();
}
}
}

我遇到的第一个问题是paint()调用paintComponent()(我想)在我运行应用程序时已经被调用了两次。这已经很烦人了。我将setResizeable()设置为false,因为这样会再次重新绘制窗口。有没有办法解决这个问题,只有在我单击“生成”时才画线?从我发现的情况来看,当应用程序“需要执行”时,没有实际的方法阻止调用paint(),因此可能有另一种方法来调整代码。

您需要将线条的绘制与API的刷新行为解耦

不过,与此同时,一个简单的方法是通过缓存完全绘制图像的图像,然后将图像设置为null以强制重画,从而手动管理重画行为

private Image turtleImage = null;
private void turtleDraw(Graphics2D g2d) {
    if(turtleImage == null) { //Anywhere else, set turtleImage to null to force a redraw
        turtleImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = turtleImage.createGraphics();
        graphics.translate(getWidth() / 2, getHeight());
        for(int i = 0; i < sentence.length(); i++) {
            char current = sentence.charAt(i);
            if(current == 'F') {
                graphics.drawLine(0, 0, 0, -len);
                graphics.translate(0, -len);
            } else if(current == '+') {
                graphics.rotate(angle);
            } else if(current == '-') {
                graphics.rotate(-angle);
            } else if(current == '[') {
                transformStack.push(graphics.getTransform());
            } else if(current == ']') {
                graphics.setTransform(transformStack.pop());
            }
        }
        generate();
        System.out.println(sentence);
    }
    g2d.drawImage(turtleImage, 0, 0, null, null);
}
私有图像turtleImage=null;
私人空心套头衫(Graphics2D g2d){
如果(turtleImage==null){//在其他任何地方,请将turtleImage设置为null以强制重画
turtleImage=新的BuffereImage(getWidth(),getHeight(),BuffereImage.TYPE_INT_ARGB);
Graphics2D graphics=turtleImage.createGraphics();
graphics.translate(getWidth()/2,getHeight());
for(int i=0;i<句子长度();i++){
char current=句子charAt(i);
如果(当前='F'){
图形.绘制线(0,0,0,-len);
图形转换(0,-len);
}else if(当前=='+'){
图形。旋转(角度);
}否则如果(当前=='-'){
图形。旋转(-角度);
}else if(当前=='['){
push(graphics.getTransform());
}else if(当前==']'){
图形学
private Image turtleImage = null;
private void turtleDraw(Graphics2D g2d) {
    if(turtleImage == null) { //Anywhere else, set turtleImage to null to force a redraw
        turtleImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D graphics = turtleImage.createGraphics();
        graphics.translate(getWidth() / 2, getHeight());
        for(int i = 0; i < sentence.length(); i++) {
            char current = sentence.charAt(i);
            if(current == 'F') {
                graphics.drawLine(0, 0, 0, -len);
                graphics.translate(0, -len);
            } else if(current == '+') {
                graphics.rotate(angle);
            } else if(current == '-') {
                graphics.rotate(-angle);
            } else if(current == '[') {
                transformStack.push(graphics.getTransform());
            } else if(current == ']') {
                graphics.setTransform(transformStack.pop());
            }
        }
        generate();
        System.out.println(sentence);
    }
    g2d.drawImage(turtleImage, 0, 0, null, null);
}
@Override
public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    turtleDraw(g2d);
    //g2d.dispose();
}