Solved

JComboBox problems

Posted on 1998-07-21
9
991 Views
Last Modified: 2012-08-14
After some unsuccessful digging I decided to post my two JComboBox related problems here hoping that someone would  tell me what I'm doing wrong.

1. When I add an action listener to my JComboBox, the second and all following selections do not generate popups, they generate an error message instead. The message reads: "java.lang.Error:convertScreenLocationToParent: no window ancestor found".

2. Using setLightWeightPopupEnabled(false) produces a quick flash of the popup's background in a random location of the screen before the popup is displayed.

Any hints will be highly appreciated.

Kris
musial@gale.com
0
Comment
Question by:musial
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 5

Expert Comment

by:fontaine
ID: 1227344
Could you post some sample code reproducing the problem?
0
 

Author Comment

by:musial
ID: 1227345
Certainly.
I developed a very small application demonstrating the two problems that I had posted.
The aplication consists of four classes: ParentFrame (main class), ChildFrame, Combo, and EditListener.

ParentFrame has a New button. When the button is clicked, the ChildFrame (JInternalFrame) is shown with the Combo (JComboBox) and a Close button in it.

The ChildFrame can be closed by either making a selection from the Combo, or by clicking the Close button.

Problem 1:

When the frame is closed by making a selection from the Combo, the next selection (in a new frame) will not generate a popup, instead the message 'convertScreenLocationToParent' is displayed.
When the frame is closed by clicking the button, it's OK.
The simple solution would be to construct the Combo each time the ChildFrame is constructed (instead of constructing it only once at the beginning and storing it in a static variable), but this solution is unacceptable, because the potential lists are long, selections frequent, and the application is slow already.

Problem 2:

Disabling the lightweight popup for the Combo using setLightWeightPopupEnabled(false) produces a quick flash of the popup's background in the top left corner of the ParentFrame.

The same problems occurred when the application was developed using JDK 1.1.5 and VisualCafe, although the flash for VisualCafe is much shorter.


The classes:

//---------------------------------------------------------------
// ParentFrame

import com.sun.java.swing.*;
import java.awt.event.*;
import java.awt.*;


public class ParentFrame extends JFrame implements ActionListener
  {
  static JDesktopPane desktop;
  static ChildFrame child = null;
  static Combo combo;


  public ParentFrame(String title)
    {
    super(title);

    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());
    getContentPane().add(panel);

    desktop = new JDesktopPane();
    panel.add(desktop, BorderLayout.CENTER);
   
    combo = new Combo();

    JButton button = new JButton("New");
    button.addActionListener(this);
    panel.add(button, BorderLayout.NORTH);


    setSize(600, 500);
    setVisible(true);

    addWindowListener(new WindowAdapter()
      {
      public void windowClosing(WindowEvent e)
        {
        System.exit(0);
        }
      });
    }


  public void actionPerformed (ActionEvent event)
    {
    if (child == null)
      {
      child = new ChildFrame("ChildFrame");
      desktop.add(child, 0);
      }
    }

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


//---------------------------------------------------------------
// ChildFrame

import com.sun.java.swing.*;
import java.awt.*;


public class ChildFrame extends JInternalFrame
  {
  public ChildFrame(String title)
    {
    super(title);

    Container pane = getContentPane();
    pane.setLayout(new BorderLayout());
    pane.add(ParentFrame.combo, BorderLayout.NORTH);

    JButton close = new JButton("Close");
    close.addActionListener(new EditListener());
    pane.add(close, BorderLayout.SOUTH);
 
    setSize(300, 200);
    setLocation(100, 100);
    }
  }
 

//---------------------------------------------------------------
// Combo

import com.sun.java.swing.*;
import java.awt.*;


public class Combo extends JComboBox
  {
  static private String[] cntList = {"String", "Number", "Date", "Text", "Controlled"};

  public Combo()
    {
    super(cntList);
    setLightWeightPopupEnabled(false);
    addActionListener(new EditListener());
    }
  }


//---------------------------------------------------------------
// EditListener

import java.awt.event.*;


public class EditListener implements ActionListener
  {
  public void actionPerformed (ActionEvent event)
    {
    if (ParentFrame.child != null)
      {
      ParentFrame.desktop.remove(ParentFrame.child);
      ParentFrame.child = null;
      ParentFrame.desktop.repaint();
      }
    }
  }







0
 
LVL 4

Expert Comment

by:evijay
ID: 1227346
replace


      ParentFrame.desktop.remove(ParentFrame.child);
      ParentFrame.child = null;
      ParentFrame.desktop.repaint();

with

  ParentFrame.child.setVisible(false);
  ParentFrame.child.dispose();
  ParentFrame.combo=null;
  ParentFrame.child = null;
  ParentFrame.desktop.repaint();

-------------------------
Replace

    pane.add(ParentFrame.combo, BorderLayout.NORTH);

with

    if (ParentFrame.combo == null)
          ParentFrame.combo=new Combo();
    pane.add(ParentFrame.combo, BorderLayout.NORTH);


and try it
 
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:musial
ID: 1227347
evijay

The reasons why the answer is not acceptable:

1. The proposed solution addresses only problem 1 and in the way I wanted to avoid for the reason explained in the problem clarification, which stated:

"The simple solution would be to construct the Combo each time the ChildFrame is constructed (instead of constructing it only once at the beginning and storing it in a static variable), but this solution is unacceptable, because the potential lists are long, selections frequent, and the application is slow already."

BTW: the same effect can be obtained by inserting only one line:
"ParentFrame.combo=new Combo();" in ChildFrame before adding combo to the frame, instead of proposed two replacements.

2. Problem 2 was not addressed.

P.S.
I apologize for submitting two problems at the same time but they were related and they could have been illustrated by the same simple application.

Kris

0
 

Author Comment

by:musial
ID: 1227348
Adjusted points to 130
0
 
LVL 3

Accepted Solution

by:
mjenkins earned 130 total points
ID: 1227349
This will work correctly, explanation to follow in comment:

// ParentFrame
//----------------------------
import com.sun.java.swing.*;
import java.awt.event.*;
import java.awt.*;
 
public class ParentFrame
        extends JFrame
{
        static Combo combo;
 
        private JDesktopPane desktop;
        private ChildFrame child = null;
 
        public ParentFrame(String title)
        {
                super(title);
 
                JPanel panel = new JPanel();
                panel.setLayout(new BorderLayout());
                getContentPane().add(panel);
 
                desktop = new JDesktopPane();
                panel.add(desktop, BorderLayout.CENTER);
           
                combo = new Combo();
 
                JButton button = new JButton("New");
                button.addActionListener(
                        new ActionListener()
                        {
                                public void actionPerformed (ActionEvent event)
                                {
                                        addChildFrame();
                                }
                        }
                );
                panel.add(button, BorderLayout.NORTH);
 
                setSize(600, 500);
                setVisible(true);
 
                addWindowListener(
                        new WindowAdapter()
                        {
                                public void windowClosing(WindowEvent e)
                                {
                                        System.exit(0);
                                }
                        }
                );
        }
 
        public void addChildFrame()
        {
                if (child == null)
                {
                        child = new ChildFrame(this, "ChildFrame");
                        desktop.add(child, 0);
                }
        }
 
        public void removeChildFrame()
        {
                if( child != null )
                {
                        desktop.remove(child);
                        desktop.repaint();
                        child = null;
                }
        }
        public ChildFrame getChildFrame()
        {
                return child;
        }
 
        public JDesktopPane getDesktop()
        {
                return desktop;
        }
 
        public static void main(String argv[])
        {
                new ParentFrame("ParentFrame");
        }
}

// ChildFrame
//------------------------
import com.sun.java.swing.*;
import java.awt.event.*;
import java.awt.*;
 
 
public class ChildFrame
        extends JInternalFrame
{
        private ParentFrame parentFrame;
        private Combo combo;
        private JButton close;
 
        public ChildFrame(ParentFrame parent, String title)
        {
                super(title);
                parentFrame = parent;
 
                ActionListener al = new ActionListener()
                {
                        public void actionPerformed (ActionEvent event)
                        {
                                combo.removeActionListener( this );
                                close.removeActionListener( this );
                                parentFrame.removeChildFrame();
                        }
                };
 
                Container pane = getContentPane();
                pane.setLayout(new BorderLayout());
                combo = new Combo();
                combo.addActionListener( al );
                pane.add(combo, BorderLayout.NORTH);
 
                close = new JButton("Close");
                close.addActionListener( al );
                pane.add(close, BorderLayout.SOUTH);
       
                setSize(300, 200);
                setLocation(100, 100);
        }
 
        public ParentFrame getParentFrame()
        {
                return parentFrame;
        }
}

// Combo
//-------------
 
import com.sun.java.swing.*;
import java.awt.*;
 
 
public class Combo
        extends JComboBox
{
        static private String[] cntList = {"String", "Number", "Date", "Text", "Controlled"};
        static ComboBoxModel cBoxModel = null;
 
        static
        {
                cBoxModel = new JComboBox( cntList ).getModel();
        }
 
        public Combo()
        {
                super(cBoxModel);
                setLightWeightPopupEnabled(true);
        }
}

0
 
LVL 3

Expert Comment

by:mjenkins
ID: 1227350
I took the liberty of cleaning up your code quite a bit. The use of statics was inappropriate and somewhat dangerous. I hope you don't mind. I also did away with EditListener altogether because I felt that this functionality really needed to be implemented within ChildFrame (you could argue that it belongs in ParentFrame, but I made a design decision).

The big problem that you were running into is the fact that all Java components (light and heavy) are designed to be added to a parent only once. Your re-use of the static Combo breaks this rule. Before you react, wait just a moment. Your argument about not wanting to recreate the Combo for each child is really an agument about the Combo DATA. By using a static MODEL for the Combo, you can reuse the DATA without the overhead of RELOADING it. The JComboBox itself is really just a view of the Model. The view is trivial to build and allows multiple models to work with it/on it at the same time.

Does this solve your problems? I can clarify further if you need.
0
 

Author Comment

by:musial
ID: 1227351
Excellent answer. No need for further clarification. Thanks for comments regarding the design, too. However, it addressed only one of the two problems that I posted. The quick flash still occurrs (in the top left corner of the main frame) when setLightWeightPopupEnabled is set to false.
0
 
LVL 3

Expert Comment

by:mjenkins
ID: 1227352
Well, unfortunately the answer is: because there is a bug in the AWT that is exposed by the JPopupMenu class. There is a call to setLocation in the setVisible method that doesn't work properly. As long as you use a lightWeight popup this bug does not rear its ugly head. Actually there is also a medium weight popup implemented as a panel -- but I digress. You will also notice that the "flash" popup is a) empty and b) smaller than the actual popup. This is because a) it happens during the setLocation call and b) it actually appears partially underneath the parent Frame's title bar (it appears with the ULHC at 0,0 in respect to the Frame's window - not its client area ). For some reason, the Window object that is the popup flashes on BEFORE changing locations to line up with the combo box.

So the reason you haven't recieved a solution to problem 2 is that the fix needs to come from JavaSoft (Sun).
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to convert from xls to xlsx using java 7 87
Glassfish admin console not working 1 56
dao vs facade design patterns 2 33
Netbeans and org.apache.commons.lang3 issue 3 24
For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Viewers will learn about if statements in Java and their use The if statement: The condition required to create an if statement: Variations of if statements: An example using if statements:

756 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question