Solved

JComboBox problems

Posted on 1998-07-21
9
966 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
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
 

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
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 

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

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Java had always been an easily readable and understandable language.  Some relatively recent changes in the language seem to be changing this pretty fast, and anyone that had not seen any Java code for the last 5 years will possibly have issues unde…
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…
Viewers will learn about the different types of variables in Java and how to declare them. Decide the type of variable desired: Put the keyword corresponding to the type of variable in front of the variable name: Use the equal sign to assign a v…
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:

759 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now