Solved

JComboBox problems

Posted on 1998-07-21
9
999 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
Industry Leaders: 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

MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
hibernate example issues from command prompt 10 85
maven disable workspace resolution 1 77
collection output issue 9 91
Java array sort 10 62
Introduction This article is the first of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article explains our test automation goals. Then rationale is given for the tools we use to a…
Introduction This article is the last of three articles that explain why and how the Experts Exchange QA Team does test automation for our web site. This article covers our test design approach and then goes through a simple test case example, how …
Video by: Michael
Viewers learn about how to reduce the potential repetitiveness of coding in main by developing methods to perform specific tasks for their program. Additionally, objects are introduced for the purpose of learning how to call methods in Java. Define …
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.
Suggested Courses

734 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