简体   繁体   中英

Mysterious one time Casting Exception

I am trying to use the PropertyChangeSupport of JComponent class. But when I am executing the following code, Clicking on the menu button first time gives Runtime casting Exception, but then it runs fine always.

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);
    }
    */
}

But If i use my own PropertyChangeSupport (remove the comments in FontSource.java), then it's working perfectly. I tried my best, but not getting this. Thnx in advance :--)

If you implement PropertyListener , you will receive all of the property changes for the component(s) with which you register. There can be many types, whose values will be determined by the type of property change.

The implementation of Component method of setFont will fire a property change with the name of "font" . If you test for that name, you should be fine:

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);
    }
}

My guess...

The property change listening is not distinguishing by property name. Since you are listening to all of the properties of FontSource then you will undoubtedly see things that are not a Font.

In propertyChange() you can print the property name in the event to be sure that's the problem.

Solution is to register for just the property in which you are interested or to check the property name in the propertyChange() method.

Finally i got it.

The answer is displayed, when u compile and execute the following files.

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) ;
    }    
}

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(){
        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();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM