Java 神秘的一次性施法例外

Java 神秘的一次性施法例外,java,Java,我正在尝试使用JComponent类的PropertyChangeSupport。 但是当我执行下面的代码时,第一次单击菜单按钮会出现运行时强制转换异常,但它总是运行良好 FrameListener.java import javax.swing.*; import java.beans.*; import java.awt.*; import java.awt.event.*; public class FrameListener extends JFrame implements Acti

我正在尝试使用JComponent类的PropertyChangeSupport。 但是当我执行下面的代码时,第一次单击菜单按钮会出现运行时强制转换异常,但它总是运行良好

FrameListener.java

import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;

public class FrameListener extends JFrame implements ActionListener, PropertyChangeListener
{

    JLabel lblMessage;
    JMenuItem changeFont;
    FontSource fe = new FontSource(this,"Font Editor");

    public FrameListener(){

        super("Hello World");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) ;
        increaseReadability() ;

        changeFont.addActionListener(this);

        fe.addPropertyChangeListener(this);

        setSize(400,200);
        setVisible(true);
    }

    private void increaseReadability(){
        JPanel panel = new JPanel();
        Font f = new Font("Times New Roman",Font.BOLD,24);
        lblMessage = new JLabel("HELLO WORLD",SwingConstants.CENTER);
        lblMessage.setFont(f);
        panel.add(lblMessage);


        JMenuBar actionBar = new JMenuBar();    
        JMenu edit = new JMenu("Edit");
        changeFont = new JMenuItem("Font");

        actionBar.add(edit);
        edit.add(changeFont);
        add(actionBar,BorderLayout.NORTH);
        add(panel,BorderLayout.CENTER);
    }

    public void propertyChange(PropertyChangeEvent pcevent){
        Object obj = pcevent.getNewValue() ;
        System.out.println(obj.getClass()) ;

        //Statement occuring problem 1st time
        Font newFt = (Font)obj;

        lblMessage.setFont(newFt);
    }

    public void actionPerformed(ActionEvent evt){
        fe.setVisible(true);
    }

    public static void main(String argv[]) {
        new FrameListener();
    }
}
FontSource.java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.beans.*;


public class FontSource extends JDialog implements ActionListener {

    private Font newFont = new Font("Times New Roman",Font.BOLD,12);

    JComboBox cbfType,cbfStyle,cbfSize;
    JButton btnOk,btnCancel;

    //protected PropertyChangeSupport changes = new PropertyChangeSupport(this);

    public Font getNewFont(){
        return newFont;
    }

    public void setNewFont(Font f){
        Font old = newFont;

        try{

            //this statement calls the propertyChange() of FrameListener
                        //if u are removing comments, replace the following statement with
                       // changes.firePropertyChange("Font Changed",old,f);
            firePropertyChange("Font Changed",old,f);

            newFont = f;
        }
        catch(Exception e){
            System.out.println(e);
        }
    }

    public FontSource(Frame fr,String title){

        super(fr,title);
        // getting font family from the graphics environment.
        GraphicsEnvironment gf = GraphicsEnvironment.getLocalGraphicsEnvironment();
        String myfont[] = gf.getAvailableFontFamilyNames();
        cbfType = new JComboBox(myfont);
        add(cbfType);

        String fontStyle[] = {"PLAIN","ITALIC","BOLD",};
        cbfStyle = new JComboBox(fontStyle);
        add(cbfStyle);

        String fontSize[] = {"10","12","14","16","18","20","24","26","28","36","48","72"};
        cbfSize = new JComboBox(fontSize);
        add(cbfSize);

        btnOk =new JButton("OK");
        btnCancel =new JButton("Cancel");

        add(btnOk);
        add(btnCancel);

        // adding action listener
        btnOk.addActionListener(this);
        btnCancel.addActionListener(this);

        // setting layout and size for the dialog
        setLayout(new FlowLayout());
        setSize(170,170);
    }

    public void actionPerformed(ActionEvent ae){

        if(ae.getSource()==btnOk){
            String type = (String) cbfType.getSelectedItem();
            String style = (String)cbfStyle.getSelectedItem();
            int s = 0;
            int size = Integer.parseInt((String)cbfSize.getSelectedItem());
            if(style=="PLAIN")
                s= Font.PLAIN;
            else {
                if(style =="BOLD")
                    s= Font.BOLD;
                else
                    s= Font.ITALIC;
            }

            Font f = new Font(type,s,size);

            setNewFont(f);
        }
        else{
            this.setVisible(false);
        }
    }

    /*
    public void addPropertyChangeListener(PropertyChangeListener l){
        System.out.println("attachement done...");
        changes.addPropertyChangeListener(l);
    }

    public void removePropertyChangeListener(PropertyChangeListener l){
        changes.removePropertyChangeListener(l);
    }
    */
}
但是如果我使用我自己的PropertyChangeSupport(删除FontSource.java中的注释),那么它工作得很好。 我尽了最大的努力,但没有得到这个。 提前通知:——)

我猜

侦听的属性更改未按属性名称区分。既然您正在收听FontSource的所有属性,那么毫无疑问,您将看到一些不是字体的东西

在propertyChange()中,您可以在事件中打印属性名称,以确保这就是问题所在

解决方案是只注册您感兴趣的属性,或者在propertyChange()方法中检查属性名称。

我猜

侦听的属性更改未按属性名称区分。既然您正在收听FontSource的所有属性,那么毫无疑问,您将看到一些不是字体的东西

在propertyChange()中,您可以在事件中打印属性名称,以确保这就是问题所在


解决方案是只注册您感兴趣的属性,或者在propertyChange()方法中检查属性名称。

如果实现
PropertyListener
,您将收到注册组件的所有属性更改。可以有许多类型,其值将由属性更改的类型决定

setFont
Component
方法的实现将触发名为
“font”
的属性更改。如果您测试该名称,您应该可以:

public void propertyChange(PropertyChangeEvent pcevent){
    Object obj = pcevent.getNewValue() ;
    System.out.println(obj.getClass()) ;

    //Problem should not occur with this call.
    if (pcevent.getPropertyName().equals("font")){
       Font newFt = (Font)obj;

       lblMessage.setFont(newFt);
    }
}

如果您实现了
PropertyListener
,您将收到注册组件的所有属性更改。可以有许多类型,其值将由属性更改的类型决定

setFont
Component
方法的实现将触发名为
“font”
的属性更改。如果您测试该名称,您应该可以:

public void propertyChange(PropertyChangeEvent pcevent){
    Object obj = pcevent.getNewValue() ;
    System.out.println(obj.getClass()) ;

    //Problem should not occur with this call.
    if (pcevent.getPropertyName().equals("font")){
       Font newFt = (Font)obj;

       lblMessage.setFont(newFt);
    }
}
我终于明白了

当您编译并执行以下文件时,将显示答案

FontSource.java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.beans.*;


public class FontSource extends JDialog{

    public FontSource(Frame fr,String title){

        super(fr,title);
        setSize(600, 400) ;
        JTextArea area = new JTextArea() ;
        area.setEditable(false) ;
        add(new JScrollPane(area)) ;

        String str = "If u look at the command prompt, then it is very clear," + "\n" +
                     "that, only on your first click on JMenuItem (font)," + "\n" +
                     "u get an output on cmd, for next future clicks on JMenuItem (font), u get no output on cmd." + "\n\n" +
                     "Reason : On first click, ActionListener attached to JMenuItem (font) invokes," + "\n" +
                     "fe.setVisible(true), which internally calls setBackground method of Component class only once." + "\n" +
                     "Now, setBackground method calls firePropertyChange(\"background\", oldValue, newValue),"  + "\n" +
                     "which in turn also gets executed once." + "\n\n" +
                     "Now, solution to this is clearly mentioned in the reply" + "\n" +
                     "provided by akf for my question asked on stackoverflow. cheers :-)" ;

        area.setText(str) ;
    }    
}
import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;

public class FrameListener extends JFrame implements ActionListener, PropertyChangeListener
{

    JLabel lblMessage;
    JMenuItem changeFont;
    FontSource fe = new FontSource(this,"Font Editor");

    public FrameListener(){

        super("Hello World");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) ;
        increaseReadability() ;

        changeFont.addActionListener(this);

        fe.addPropertyChangeListener(this);

        setSize(400,200);
        setVisible(true);
    }

    private void increaseReadability(){
        JMenuBar actionBar = new JMenuBar();    
        JMenu edit = new JMenu("Edit");
        changeFont = new JMenuItem("Font");
        actionBar.add(edit);
        edit.add(changeFont);
        add(actionBar,BorderLayout.NORTH);
    }

    public void propertyChange(PropertyChangeEvent pcevent){
        Object obj = pcevent.getNewValue() ;
        System.out.println(obj.getClass() + ", " + pcevent.getPropertyName()) ;
    }

    public void actionPerformed(ActionEvent evt){
        fe.setVisible(true);
    }

    public static void main(String argv[]) {
        new FrameListener();
    }
}
FrameListener.java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.beans.*;


public class FontSource extends JDialog{

    public FontSource(Frame fr,String title){

        super(fr,title);
        setSize(600, 400) ;
        JTextArea area = new JTextArea() ;
        area.setEditable(false) ;
        add(new JScrollPane(area)) ;

        String str = "If u look at the command prompt, then it is very clear," + "\n" +
                     "that, only on your first click on JMenuItem (font)," + "\n" +
                     "u get an output on cmd, for next future clicks on JMenuItem (font), u get no output on cmd." + "\n\n" +
                     "Reason : On first click, ActionListener attached to JMenuItem (font) invokes," + "\n" +
                     "fe.setVisible(true), which internally calls setBackground method of Component class only once." + "\n" +
                     "Now, setBackground method calls firePropertyChange(\"background\", oldValue, newValue),"  + "\n" +
                     "which in turn also gets executed once." + "\n\n" +
                     "Now, solution to this is clearly mentioned in the reply" + "\n" +
                     "provided by akf for my question asked on stackoverflow. cheers :-)" ;

        area.setText(str) ;
    }    
}
import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;

public class FrameListener extends JFrame implements ActionListener, PropertyChangeListener
{

    JLabel lblMessage;
    JMenuItem changeFont;
    FontSource fe = new FontSource(this,"Font Editor");

    public FrameListener(){

        super("Hello World");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) ;
        increaseReadability() ;

        changeFont.addActionListener(this);

        fe.addPropertyChangeListener(this);

        setSize(400,200);
        setVisible(true);
    }

    private void increaseReadability(){
        JMenuBar actionBar = new JMenuBar();    
        JMenu edit = new JMenu("Edit");
        changeFont = new JMenuItem("Font");
        actionBar.add(edit);
        edit.add(changeFont);
        add(actionBar,BorderLayout.NORTH);
    }

    public void propertyChange(PropertyChangeEvent pcevent){
        Object obj = pcevent.getNewValue() ;
        System.out.println(obj.getClass() + ", " + pcevent.getPropertyName()) ;
    }

    public void actionPerformed(ActionEvent evt){
        fe.setVisible(true);
    }

    public static void main(String argv[]) {
        new FrameListener();
    }
}
我终于明白了

当您编译并执行以下文件时,将显示答案

FontSource.java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.beans.*;


public class FontSource extends JDialog{

    public FontSource(Frame fr,String title){

        super(fr,title);
        setSize(600, 400) ;
        JTextArea area = new JTextArea() ;
        area.setEditable(false) ;
        add(new JScrollPane(area)) ;

        String str = "If u look at the command prompt, then it is very clear," + "\n" +
                     "that, only on your first click on JMenuItem (font)," + "\n" +
                     "u get an output on cmd, for next future clicks on JMenuItem (font), u get no output on cmd." + "\n\n" +
                     "Reason : On first click, ActionListener attached to JMenuItem (font) invokes," + "\n" +
                     "fe.setVisible(true), which internally calls setBackground method of Component class only once." + "\n" +
                     "Now, setBackground method calls firePropertyChange(\"background\", oldValue, newValue),"  + "\n" +
                     "which in turn also gets executed once." + "\n\n" +
                     "Now, solution to this is clearly mentioned in the reply" + "\n" +
                     "provided by akf for my question asked on stackoverflow. cheers :-)" ;

        area.setText(str) ;
    }    
}
import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;

public class FrameListener extends JFrame implements ActionListener, PropertyChangeListener
{

    JLabel lblMessage;
    JMenuItem changeFont;
    FontSource fe = new FontSource(this,"Font Editor");

    public FrameListener(){

        super("Hello World");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) ;
        increaseReadability() ;

        changeFont.addActionListener(this);

        fe.addPropertyChangeListener(this);

        setSize(400,200);
        setVisible(true);
    }

    private void increaseReadability(){
        JMenuBar actionBar = new JMenuBar();    
        JMenu edit = new JMenu("Edit");
        changeFont = new JMenuItem("Font");
        actionBar.add(edit);
        edit.add(changeFont);
        add(actionBar,BorderLayout.NORTH);
    }

    public void propertyChange(PropertyChangeEvent pcevent){
        Object obj = pcevent.getNewValue() ;
        System.out.println(obj.getClass() + ", " + pcevent.getPropertyName()) ;
    }

    public void actionPerformed(ActionEvent evt){
        fe.setVisible(true);
    }

    public static void main(String argv[]) {
        new FrameListener();
    }
}
FrameListener.java

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.beans.*;


public class FontSource extends JDialog{

    public FontSource(Frame fr,String title){

        super(fr,title);
        setSize(600, 400) ;
        JTextArea area = new JTextArea() ;
        area.setEditable(false) ;
        add(new JScrollPane(area)) ;

        String str = "If u look at the command prompt, then it is very clear," + "\n" +
                     "that, only on your first click on JMenuItem (font)," + "\n" +
                     "u get an output on cmd, for next future clicks on JMenuItem (font), u get no output on cmd." + "\n\n" +
                     "Reason : On first click, ActionListener attached to JMenuItem (font) invokes," + "\n" +
                     "fe.setVisible(true), which internally calls setBackground method of Component class only once." + "\n" +
                     "Now, setBackground method calls firePropertyChange(\"background\", oldValue, newValue),"  + "\n" +
                     "which in turn also gets executed once." + "\n\n" +
                     "Now, solution to this is clearly mentioned in the reply" + "\n" +
                     "provided by akf for my question asked on stackoverflow. cheers :-)" ;

        area.setText(str) ;
    }    
}
import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.awt.event.*;

public class FrameListener extends JFrame implements ActionListener, PropertyChangeListener
{

    JLabel lblMessage;
    JMenuItem changeFont;
    FontSource fe = new FontSource(this,"Font Editor");

    public FrameListener(){

        super("Hello World");
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) ;
        increaseReadability() ;

        changeFont.addActionListener(this);

        fe.addPropertyChangeListener(this);

        setSize(400,200);
        setVisible(true);
    }

    private void increaseReadability(){
        JMenuBar actionBar = new JMenuBar();    
        JMenu edit = new JMenu("Edit");
        changeFont = new JMenuItem("Font");
        actionBar.add(edit);
        edit.add(changeFont);
        add(actionBar,BorderLayout.NORTH);
    }

    public void propertyChange(PropertyChangeEvent pcevent){
        Object obj = pcevent.getNewValue() ;
        System.out.println(obj.getClass() + ", " + pcevent.getPropertyName()) ;
    }

    public void actionPerformed(ActionEvent evt){
        fe.setVisible(true);
    }

    public static void main(String argv[]) {
        new FrameListener();
    }
}

异常堆栈跟踪会很有帮助,为什么不看看pcevent.getNewValue()第一次返回的是什么?这将非常明确地告诉您发生异常的原因。它第一次返回java.awt.SystemColor???异常堆栈跟踪将非常有用。您为什么不看看pcevent.getNewValue()第一次返回的是什么?这将非常明确地告诉您发生异常的原因。它第一次返回java.awt.SystemColor???