Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4450832
Votes 0
Synopsis JTextPane gives the wrong number of inside components
Category java:classes_swing
Reported Against 1.3
Release Fixed
State 11-Closed, duplicate of 4353673, bug
Priority: 3-Medium
Related Bugs 4353673
Submit Date 26-APR-2001
Description




java version "1.3.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0_01)
Java HotSpot(TM) Client VM (build 1.3.0_01, mixed mode)

I am using JTextPane to allow user to type char or add JButton inside.

The problem is I always get the wrong number of components in a JTextPane:

import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.border.*;
import java.awt.event.*;
import java.util.*;

//*********************************************************************
//
// demo application
//
//*********************************************************************

public class JTextPaneBugDemo extends javax.swing.JFrame implements ActionListener, KeyListener 
{
	final int cWidth = 488;
	final int cHeigh = 350;
	final int cInset = 15;
	final int cFaqHeigh = cHeigh - 80;
	final int cFaqWidth = cWidth - 100;
		
	
	JTextPane mTxtFaq = new JTextPane();
				
	public JTextPaneBugDemo()
	{
		setTitle("JFC Application");
		getContentPane().setLayout (new FlowLayout (FlowLayout.LEFT));
		setSize(cWidth,cHeigh);
		setVisible(true);
	    	    
	    getContentPane().add(getFaqPanel());
	    	    	    	   
	}
	
	
	private void loadData()
	{
        JOptionPane.showMessageDialog(this, "You will get exceptions after this message if you are running version 1.3.0 or 1.3.0_01.", "JTextPane Bugs", JOptionPane.WARNING_MESSAGE);
	    
	    Document doc = mTxtFaq.getDocument();
	    
	    mTxtFaq.setText("");
	    
	    for (int i =0; i < 20; i++)
	    {
	        try
	        {
	            int nEndPos = doc.getEndPosition().getOffset()-1;
	            if (i == 0) 
	            {
	                doc.insertString(nEndPos, "For version 1.3.0 and 1.3.0_01, the component can't be inserted correctly. In the case that components can be inserted properly, the vertical scrollbar doesn't show in version 1.3.0 or 1.3.0_01. So where is the problem ???", null);
	            }
	            else
	            {
	                doc.insertString(nEndPos, "Line " + i + "**********************", null);
	            }

	        }
	        catch (Exception ex) {}  // bad position

	        if (i < 5) 
	        {
	            JButton button = new JButton("JButton");
                insertButton(mTxtFaq,button);
            }
	    }
	    
	}
	
	
	private JPanel getFaqPanel()
	{
	    JPanel faqPanel = new JPanel();
	    
        Dimension d = new Dimension(cWidth - cInset * 3,cFaqHeigh);
        faqPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
        faqPanel.setPreferredSize(d);
        faqPanel.setBorder( new CompoundBorder(new TitledBorder(new EtchedBorder(),"Faq:"),
        new EmptyBorder(0,0,0,0)));
        
                
        // Faq text area
	    JScrollPane faqPane = new JScrollPane(mTxtFaq); 
	    faqPane.setPreferredSize(new Dimension(cFaqWidth,160));
	    
	    mTxtFaq.addKeyListener(this);
	    try
	    {
	        mTxtFaq.getDocument().insertString(0, "After you type in and add several JButtons inside this JtextPane, select one of these JButton and press delete button.", null);
	    }
	    catch (Exception ex) {}
	    
	    faqPanel.add(faqPane);
	    
	    	    
        faqPanel.add(getButtonsPanel());
                
        return faqPanel;
	}
	
	
	
	protected JPanel getButtonsPanel()
	{
	    JButton addButton = new JButton("Add JButton");
        addButton.addActionListener(this);
        		
		JButton clearButton = new JButton("Clear JTextPane");
        clearButton.addActionListener(this);
        
        JButton loadButton =new JButton("Load Data");
        loadButton.addActionListener(this);
        
        JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        Dimension d5 = new Dimension(cFaqWidth-50,40);
        btnPanel.setPreferredSize(d5);
        btnPanel.add(addButton);
        btnPanel.add(clearButton);
        btnPanel.add(loadButton);
        return btnPanel;
	}
	
	
	public void actionPerformed(ActionEvent e) 
    {
        if (e.getActionCommand().trim().equals("Add JButton"))
        {
            JButton button = new JButton(" JButton ");
            insertButton(mTxtFaq,button);
        }
        else if (e.getActionCommand().trim().equals("Clear JTextPane"))
        {
            mTxtFaq.setText("");
        }
        else 
        {
            loadData();
        }
    }
    
    private void insertButton(JTextPane txtPane, JButton button)
    {
        button.setBackground(Color.white);
        button.setBorder(new EmptyBorder(0,0,0,0));
        button.setForeground(Color.blue);
        button.setAlignmentY(0.8f);
        button.addKeyListener(this);
        txtPane.insertComponent(button);
    }
    
	public void keyTyped(KeyEvent e)
	{
		// nothing
	}
	
	public void keyPressed(KeyEvent e) 
	{
		if (e.getKeyCode() == KeyEvent.VK_DELETE )
        {
            deleteButtonFrom(mTxtFaq,e);
        }
	}
	
	private void deleteButtonFrom(JTextPane txtPane, KeyEvent e)
	{
        int nCount = txtPane.getComponentCount();
        for (int i = 0; i < nCount; i++)
        {
            JOptionPane.showMessageDialog(this, "There are " + nCount + " JButtons in this JTextPane. The number showing here is probably wrong if you are running 1.3.0 or 1.3.0_01.\n You will get an exception after this message if you are running version 1.3.0 or 1.3.0_01.", "JTextPane Bugs", JOptionPane.WARNING_MESSAGE);
            Component b1 = e.getComponent();
            Component b2 = txtPane.getComponent(i+1);
            
            // Why I can't use remove method to remove a component from JTextPane  ????
            // txtPane.remove(b2);
            // txtPane.repaint();
            // return;
                
            Component b3 = ((Container)b2).getComponent(0);
            if (b1.equals(b3))
            {                        
                int nStart = txtPane.viewToModel(new Point(b2.getX(),b2.getY()));
                txtPane.select(nStart, nStart + 1);
                
                txtPane.replaceSelection(null); 
                return;
            } 
        }
	}
	    
	public void keyReleased(KeyEvent e)
	{
        // nothing
	}
	

	static public void main(String args[])
	{
		try {
			(new JTextPaneBugDemo()).setVisible(true);
		} 
		catch (Throwable t) {
			t.printStackTrace();
			System.exit(0);
		}
	}

}

With 1.2.2, the application is working fine and showing the correct number of 
components in JTextPane, but when deleting the very first component from
the JTextPane , it throws the following exception.

Exception occurred during event dispatching:
java.lang.ArrayIndexOutOfBoundsException: No such child: 4
        at java.awt.Container.getComponent(Container.java, Compiled Code)
        at JTextPaneBugDemo.deleteButtonFrom(JTextPaneBugDemo.java, Compiled Code)
        at JTextPaneBugDemo.keyPressed(JTextPaneBugDemo.java:161)
        at java.awt.Component.processKeyEvent(Component.java:3127)
        at javax.swing.JComponent.processKeyEvent(JComponent.java:1582)
        at java.awt.Component.processEvent(Component.java, Compiled Code)
        at java.awt.Container.processEvent(Container.java, Compiled Code)
        at java.awt.Component.dispatchEventImpl(Component.java, Compiled Code)
        at java.awt.Container.dispatchEventImpl(Container.java, Compiled Code)
        at java.awt.Component.dispatchEvent(Component.java, Compiled Code)
        at java.awt.LightweightDispatcher.processKeyEvent(Container.java:1791)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java, Compiled Code)
        at java.awt.Container.dispatchEventImpl(Container.java, Compiled Code)
        at java.awt.Window.dispatchEventImpl(Window.java, Compiled Code)
        at java.awt.Component.dispatchEvent(Component.java, Compiled Code)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java, Compiled Code)
        at java.awt.EventDispatchThread.pumpOneEventForComponent(EventDispatchThread.java, CompiledCode)
        at java.awt.EventDispatchThread.pumpEventsForComponent(EventDispatchThread.java:95)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:90)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
(Review ID: 114601) 
======================================================================
Work Around
N/A
Evaluation
There are two separate problems described in this bug report that I will address separately. One is an actual bug that is already fixed in merlin. The other is a user error.

The user is correct that the JTextPane can return an incorrect number of components in 1.3. This is an issue that is fixed in bug 4353673 for merlin.

The second part is where the user describes that an exception is thrown when deleting a component. This is due to a user error. Notice that in the code for deleteButton(JTextPane, KeyEvent), the user gets the number of components in the JTextPane and then loops through them to determine which one to remove. At one point they attempt to get a reference to a component with Component b2 = txtPane.getComponent(i+1). The components are indexed starting with 0, thus the "i+1" should be simply "i".

Since the synopsis for this bug has to do with JTextPane returning the wrong count of components, which has been fixed, I will close this as a duplicate rather than user error.
  xxxxx@xxxxx   2001-05-04
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang