但是为什么swing不会绘制我的组件?

时间:2015-08-27 22:00:06

标签: java swing user-interface

我有一个最简单的java gui的工作版本,带有一个按钮和一个圆圈,工作正常:

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
//a gui element shares its events only with classes that implement Actionlistener interface
public class SimpleGui1 implements ActionListener {    
   JButton button;
   JFrame frame;
   ppanel mypanel;

public static void main (String[] args) {
    SimpleGui1 mywindow = new SimpleGui1();
    mywindow.renderWindow();
}  
public void renderWindow(){
    frame = new JFrame();
    button = new JButton("click me");
    mypanel = new ppanel();

    //register my interest to catch button events
    button.addActionListener(this);

    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, mypanel);

    frame.setSize(300,300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
}   
//button will call this method when clicked (its the callback)
public void actionPerformed(ActionEvent event)
{       
    frame.repaint();
    button.setText("Clicked!!");
}
}
//i need this to override paintComponent
public class ppanel extends JPanel  {   
    //draw something silly
    public void paintComponent(Graphics g) {
    //super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    int red = (int) (Math.random() * 255);
    int green = (int) (Math.random() * 255);
    int blue = (int) (Math.random() * 255);

    Color startColor = new Color(red, green, blue);
    red = (int) (Math.random() * 255);
    green = (int) (Math.random() * 255);
    blue = (int) (Math.random() * 255);
    Color endColor = new Color(red, green, blue);
    GradientPaint gradient =  new GradientPaint(70,70,startColor, 150,150, endColor);
    g2d.setPaint(gradient);
    g2d.fillOval(70,70,100,100);
}
}

然后,为了好玩,我试图将这两个类聚合成一个这样的类:

public class SimpleGui1 extends JPanel implements ActionListener {    
private JButton button;
private JFrame frame;
private JPanel mypanel;


public static void main (String[] args) {
    SimpleGui1 mywindow = new SimpleGui1();
    mywindow.renderWindow();
}

public void renderWindow(){
    frame = new JFrame();
    button = new JButton("click me");
    mypanel = new JPanel();

    frame.setSize(300,300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    // register my interest to catch button events
    button.addActionListener(this);

    frame.getContentPane().add(BorderLayout.SOUTH, button);
    frame.getContentPane().add(BorderLayout.CENTER, mypanel);

    //without this i see only the button
    //frame.add(this);

}
//button will call this method when clicked (its the callback)
public void actionPerformed(ActionEvent event)
{
    frame.repaint();
    button.setText("Clicked!!");
}

public void paintComponent(Graphics g) {
   //super.paintComponent(g);

    Graphics2D g2d = (Graphics2D) g;
    int red = (int) (Math.random() * 255);
    int green = (int) (Math.random() * 255);
    int blue = (int) (Math.random() * 255);

    Color startColor = new Color(red, green, blue);
    red = (int) (Math.random() * 255);
    green = (int) (Math.random() * 255);
    blue = (int) (Math.random() * 255);
    Color endColor = new Color(red, green, blue);
    GradientPaint gradient =  new GradientPaint(70,70,startColor, 150,150, endColor);
    g2d.setPaint(gradient);
    g2d.fillOval(70,70,100,100);
}
}

新类成功编译,但在运行时它只绘制按钮。由于某种原因,不调用paintComponent,并且正确工作的唯一方法是在renderwindow()中添加以下内容:

 frame.add(this);

我的问题是为什么这种行为......为什么我必须明确添加 我的框架的对象,以使此版本正常工作?

几乎到处尝试重绘()和验证()。变化不大
我也知道我不应该在EDT上绘制内容,而内部类的版本也可以缓解问题

2 个答案:

答案 0 :(得分:4)

实际上,您必须将此对象显式添加到内容窗格。我编译并测试了以下内容:

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
//a gui element shares its events only with classes that implement Actionlistener interface
public class SimpleGui1 extends JPanel implements ActionListener {    
       JButton button;
       JFrame frame;
       ppanel mypanel;

    public void paintComponent(Graphics g) 
    {
        //super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);

        Color startColor = new Color(red, green, blue);
        red = (int) (Math.random() * 255);
        green = (int) (Math.random() * 255);
        blue = (int) (Math.random() * 255);
        Color endColor = new Color(red, green, blue);
        GradientPaint gradient =  new GradientPaint(70,70,startColor, 150,150, endColor);
        g2d.setPaint(gradient);
        g2d.fillOval(70,70,100,100);
    }

    public static void main (String[] args) {
        SimpleGui1 mywindow = new SimpleGui1();
        mywindow.renderWindow();
    }  
    public void renderWindow(){
        frame = new JFrame();
        button = new JButton("click me");

        //register my interest to catch button events
        button.addActionListener(this);

        frame.getContentPane().add(BorderLayout.SOUTH, button);
        frame.getContentPane().add(BorderLayout.CENTER, this);

        frame.setSize(300,300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }   
    //button will call this method when clicked (its the callback)
    public void actionPerformed(ActionEvent event)
    {       
        frame.repaint();
        button.setText("Clicked!!");
    }
}

你需要明确地添加组件才能绘制它,组件就是对象本身并不重要!

答案 1 :(得分:3)

这可能是你的问题:

public void renderWindow(){
     //where everything is the same except ofcourse:
     mypanel = new JPanel();
   }  

因为mypanel是JPanel类型,所以你要在框架中添加一个通用面板而不是覆盖的对象。

尝试:

public void renderWindow(){
 //where everything is the same except ofcourse:
 mypanel = new SimpleGui1();  // or possibly 'this'
}  

这样,您的SimpleGui1类将被添加到框架中,并且可以参与Swing消息队列。

要回答关于“为什么”的问题,这是因为当您将面板附加到框架时,面板必须具有处理消息和覆盖的代码。当您包含JPanel对象时,您不会获得任何自定义行为。要告诉框架它应该向你的班级发送消息,你必须告诉框架,基本上用框架注册它。