JInternalFrame GlassPane behavior between Java 5 and Java 6

I have an application that has JDesktopPane in which Several JInternalFrame subclasses are added.

The JInternalFrame subclass installs a GlassPane thusly:

setGlassPane(new Component(){

publicvoid setVisible(boolean b){

super.setVisible(false);

}

});

Under Java 5 this would prevent the JInternalFrame from

being raised when the mouse was clicked in the content

area of the internal frame. Our application had several

integrated features that rely on the internal frame not being

raised during user interaction. But would be raised when

the user clicks on the title bar of the internal frame.

The behavior that we are emulating is similar to the X

windows feature of the focus following the mouse but with

out the internal frame gaining focus or raising when the

mouse enters the internal frame or is clicked on the

content area.

Below is an example program

When executed under Java 5 clicking on the button in the

internal frame invokes the button but does not raise the

frame.

When executed under Java 6. The frame is always raised.

The desired behavior is that the frame is raised only when

the title bar or frame handles are clicked.

Does anyone have any ideas on this one.

Cheers,

David

/*

* DeskTopTest.java

*

* Created on February 16, 2007, 8:06 AM

*/

package com.rolands.framework.test;

import java.awt.Component;

import javax.swing.JInternalFrame;

/**

*

* @author David J. Ward

*/

publicclass DeskTopTestextends javax.swing.JFrame{

/** Creates new form DeskTopTest */

public DeskTopTest(){

initComponents();

jInternalFrame1.setGlassPane(new Component(){

publicvoid setVisible(boolean b){

super.setVisible(false);

}

});

jInternalFrame2.setGlassPane(new Component(){

publicvoid setVisible(boolean b){

super.setVisible(false);

}

});

}

/** This method is called from within the constructor to

* initialize the form.

* WARNING: Do NOT modify this code. The content of this method is

* always regenerated by the Form Editor.

*/

// <editor-fold defaultstate="collapsed" desc=" Generated Code ">

privatevoid initComponents(){

desktop =new javax.swing.JDesktopPane();

jInternalFrame1 =new javax.swing.JInternalFrame();

jButton1 =new javax.swing.JButton();

jInternalFrame2 =new javax.swing.JInternalFrame();

jButton2 =new javax.swing.JButton();

getContentPane().setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.X_AXIS));

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

desktop.setPreferredSize(new java.awt.Dimension(300, 400));

jInternalFrame1.setVisible(true);

jButton1.setText("jButton1");

jInternalFrame1.getContentPane().add(jButton1, java.awt.BorderLayout.CENTER);

jInternalFrame1.setBounds(50, 40, 130, 100);

desktop.add(jInternalFrame1, javax.swing.JLayeredPane.DEFAULT_LAYER);

jInternalFrame2.setVisible(true);

jButton2.setText("jButton2");

jInternalFrame2.getContentPane().add(jButton2, java.awt.BorderLayout.CENTER);

jInternalFrame2.setBounds(140, 90, 130, 130);

desktop.add(jInternalFrame2, javax.swing.JLayeredPane.DEFAULT_LAYER);

getContentPane().add(desktop);

pack();

}

// </editor-fold>

/**

* @param args the command line arguments

*/

publicstaticvoid main(String args[]){

java.awt.EventQueue.invokeLater(new Runnable(){

publicvoid run(){

new DeskTopTest().setVisible(true);

}

});

}

// Variables declaration - do not modify

private javax.swing.JDesktopPane desktop;

private javax.swing.JButton jButton1;

private javax.swing.JButton jButton2;

private javax.swing.JInternalFrame jInternalFrame1;

private javax.swing.JInternalFrame jInternalFrame2;

// End of variables declaration

}

[6682 byte] By [davidjwarda] at [2007-11-26 18:39:37]
# 1

VetoableChangeListener vcl = new VetoableChangeListener() {

public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {

if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY) &&

evt.getNewValue().equals(Boolean.TRUE)) {

throw new PropertyVetoException("no!", evt);

}

}

};

jInternalFrame1.addVetoableChangeListener(vcl);

jInternalFrame2.addVetoableChangeListener(vcl);

Sorry, that prevents frame selection regardless of where you click. Didn't read that part until just now.

Message was edited by:

Jaspre

Jasprea at 2007-7-9 6:13:39 > top of Java-index,Desktop,Core GUI APIs...
# 2

I'm not sure if what i'm about to suggest is the easiest solution, but it will probably work.

Try making your glass pane visible, and setOpaque(true) and setBackground(Color.RED). Then you can see exactly where the glass pane covers the internal frame.

I'm guessing you will have to manually implement:

- When the JInternalFrame is deactivated then only allow mouse clicks on the title bar.

- Implement this by setting a visible "blocking" glass pane on the JInternalFrame. Make sure the glass pane covers the whole JInternalFrame except for the title bar.

- A blocking glass pane has mouse and keyboard listeners that consume those events. There are examples of this in the Java top-level windows turtorial under using root panes /glass panes or something like that.

- When the JInternalFrame is activated, make its blocking glass pane no longer visible.

That should get things working again.

The big caveat is that since JInternalFrame is not a top-level window, the way its glass panes will work may be quite different from the way dialog/frame glass panes behave. What I described is something that would work on real dialog/frame, but maybe has issues with JInternalFrame (?).

jvaudrya at 2007-7-9 6:13:39 > top of Java-index,Desktop,Core GUI APIs...
# 3

I like jvaudry's solution but you would lose the ability to perform actions on inactive frames. You could combine our two solutions so that when your glasspane detects a mouse event, it adds the VetoableChangeListener to the internal frame. The VCL could then remove itself after blocking one event.

Or, you can use this modified VCL, which is a hack also because it relies on the mouse position:

VetoableChangeListener vcl = new VetoableChangeListener() {

public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {

if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY) &&

evt.getNewValue().equals(Boolean.TRUE)) {

Point p = MouseInfo.getPointerInfo().getLocation();

JInternalFrame f = (JInternalFrame)evt.getSource();

SwingUtilities.convertPointFromScreen(p, f.getContentPane());

if (f.getContentPane().contains(p)) {

throw new PropertyVetoException("no!", evt);

}

}

}

};

Jasprea at 2007-7-9 6:13:39 > top of Java-index,Desktop,Core GUI APIs...
# 4
Thanks Jaspre. You last code snipet works flawlessly.I was pulling my hair out on this one. Interesting how subtle swing changes can affect stable four year old code and turn it on its ear.Duke stars for everybody!!Cheers,David
davidjwarda at 2007-7-9 6:13:39 > top of Java-index,Desktop,Core GUI APIs...