Skip to main content

JPanel & UI

44 replies [Last post]
tdanecito
Offline
Joined: 2005-10-10

Hi All,

Does anyone know if is possible to add the caption bar and associated ui to a JPanel? For example if I wanted to add the JFrame capabilites for UI where I get the caption bar and be able to select the caption bar via the mouse and move it?

Thanks for any hints

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
leouser
Offline
Joined: 2005-12-12

'I agree that it's a good idea to not support composite yet. Perhaps
you can include it but disable it and let developers turn it on when
they want to test it.
- j'

I would concur with this but I haven't proven/written that any code I have would work. Ive seen this behavior so far:
1. Basic query to see if the extension is supported. Ive seen this work. Ive also seen it sit there and spin its wheels forever. Not sure why it worked one moment and not the next.

2. The first step to redirecting the XWindow to an offscreen buffer always results in XOrg crashing. I see the native method return and the java method return and very quickly Ill see the screen become the XWindow and subsequently crash.

The XComposite method in question that always crashes is this:
[code]
void
XCompositeRedirectWindow (Display *dpy, Window window, int update)
{
XCompositeExtDisplayInfo *info = XCompositeFindDisplay (dpy);
xCompositeRedirectWindowReq *req;

XCompositeSimpleCheckExtension (dpy, info);
LockDisplay (dpy);
GetReq (CompositeRedirectWindow, req);
req->reqType = info->codes->major_opcode;
req->compositeReqType = X_CompositeRedirectWindow;
req->window = window;
req->update = update;
UnlockDisplay (dpy);
SyncHandle ();
}
[/code]

Im either doing some API step completely wrong or the XOrg Im using can't really handle this yet. Im leaning towards a naughty XOrg at this moment, Ive been studying xcompmgr and trying to emulate what it does.

leouser

leouser
Offline
Joined: 2005-12-12

Ok, Ive put a zip up of src so far here:
https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?...

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Sorry did not get back to you but had a new update from jdic group I had to get working and finally did a little while ago.

It works really great so far had to change from getcontentpane.add to add in places but easy compared tp what you did.

I did notice two things I have to figure out what to do.

1. JDesktopPane.getAllFrames() returns array of JInternalFrames. Not sure it is an issue since I recast to your class anyway.

2. Each HeavyWeightInternalFrame I add a JScrollPane to for scrolling so when scrolling heavyweight components cover lightweight scrollbar and not sure what to do about that.

3. Finally I have the JDesktopPane in a lightweight splitter so when moving the new frame over it can cover the contents of the left pane of the splitter. Might just try to find a heavy splitter class somewhere.

In summary everything so far is really good!!!!!!

Any thoughts appreciated.

leouser
Offline
Joined: 2005-12-12

Im not certain, but for the JScrollPane problem, there may need to be a heavyweight added behind the scrollbars. Im not sure if Im not seeing them painted or the heavyweight is interacting in a way that the JScrollPane isn't asking for it or it may be that the Heavyweight is being placed over top of them. Just from early investigation it appears that "big" things may be problematic. There may be a need to add another panel behind the JRootPane so that the heavyweight doesn't flow over the border.

I sure wish the resize/flickering problem was solvable. What Im seeing is the background being repainted when resizing occurs and a subsequent flashing as the lightweight code is repainted. From looking at the bug database Im starting to think that it may not be attackable from the Java API level. There were reports of the background being repainted because of some native code. Ive tried "sun.awt.noerasebackground" but this does not seem to put a dent in the problem. Maybe it will be a limitation, a very annoying limitation. :(

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Thanks for the response but you have done great work so far in the area that has needed it for some time.
If you have any other changes for testing I will gladly test them but what you have done so far is outstanding!!

Tonight I hope to finish the changes for my mdi windows for some light user testing. I sure they will have very positive feedback.

Regards,
-Tony

leouser
Offline
Joined: 2005-12-12

yeah, Ill have some updates hopefully before too long. Id like to get the JScrollPane + Heavyweight problem Im observing solved first. That seems like an important piece of the puzzle. :)

leouser

leouser
Offline
Joined: 2005-12-12

Ok,

Ive got an early version of a "HeavyWeightJScrollPane". Im able to put a very large button in it and be able to scroll it with the JScrollPane but without the button overwriting the borders. See if it works ok for you.

[code]
import javax.swing.*;
import java.awt.*;

public class HeavyWeightJScrollPane extends JScrollPane{

boolean ignoreRemove;
JViewportParent jvparent;

HeavyWeightJScrollPane(Component view){
super(view);
}

@Override
public JViewport createViewport(){
jvparent = new JViewportParent();
JViewport jvp = new JViewport(){
public void setBounds(int x, int y, int width, int height){
super.setBounds(x, y, width, height);
jvparent.position();
}
};
return jvp;
}

@Override
public void setLayout(LayoutManager lm){
super.setLayout(new ScrollPaneLayout2());
}

class JViewportParent extends Panel{
boolean validating;
public void doLayout(){}
public void setBounds(int x, int y, int width, int height){
position();
}

public void position(){
if(validating) return;
validating = true;
HeavyWeightJScrollPane.this.validate();
Rectangle vbb = getViewportBorderBounds();
super.setBounds(vbb.x, vbb.y, vbb.width, vbb.height);
validating = false;
}
}

class ScrollPaneLayout2 extends ScrollPaneLayout{
@Override
public void removeLayoutComponent(Component c){
if(ignoreRemove) return;
super.removeLayoutComponent(c);
}
}

@Override
public void setViewport(JViewport viewport) {
super.setViewport(viewport);
ignoreRemove = true;
jvparent.add(viewport);
add(jvparent);
ignoreRemove = false;
}
}
[/code]

leouser

leouser
Offline
Joined: 2005-12-12

ok,

here is the most recent version of the HeavyWeightInternalFrame. Nothing too new, just some minor modifications.
[code]
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import java.lang.reflect.*;

public class HeavyWeightInternalFrame extends JInternalFrame{

Panel hw;
JComponent insulation;
JRootPane jrp;
boolean painting;

HeavyWeightInternalFrame(){
super();
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
}

@Override
public void doLayout(){
super.doLayout();
if(insulation == null){
initialize();
}
insulation.setBounds(0, 0, getWidth(), getHeight());
}

void initialize(){
boolean rpc = isRootPaneCheckingEnabled();

insulation = new InsulationLayer();
hw = new PanelLayer();
jrp = new JRootPane();
Container cpane = jrp.getContentPane();
jrp.setContentPane(new Panel(cpane.getLayout()));

insulation.add(hw);
hw.add(jrp);
add(insulation);

setRootPaneCheckingEnabled(rpc);
}

@Override
public void addImpl(Component comp, Object constraints, int index) {
if(insulation == null){
initialize();
}

if(isRootPaneCheckingEnabled()) {
jrp.getContentPane().add(comp, constraints, index);
}
else if(comp == insulation){
super.addImpl(comp, constraints, index);
}
else{
super.addImpl(comp, constraints, index);
}
}

@Override
public void setSelected(boolean selected) throws PropertyVetoException{
boolean oldSelected = isSelected();
Dimension size = getSize();
if(oldSelected != selected)
setSize(0,0);
super.setSelected(selected);
if(oldSelected != selected){
setSize(size);
hw.repaint();
}
}

class InsulationLayer extends JComponent{
InsulationLayer(){
setLayout(new GridLayout(1,1));
setOpaque(false);
disableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK);
}

@Override
public void paint(Graphics g){
if(painting) return;
super.paint(g);
}

@Override
public void paintComponent(Graphics g){}
@Override
public void paintBorder(Graphics g){}
}

class PanelLayer extends Panel{
Component lastEntered;
Component lastDragged;

public PanelLayer(){
enableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK);
}

@Override
public void processMouseEvent(MouseEvent e){
Component target = getTarget(e.getX(), e.getY());
if(target != HeavyWeightInternalFrame.this){
Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), target);
Component nwtarget = SwingUtilities.getDeepestComponentAt(target, p.x, p.y);
if(nwtarget != null)
target = nwtarget;
}

if(e.getID() == MouseEvent.MOUSE_EXITED && lastEntered != null){
target = lastEntered;
lastEntered = null;
}
else if(e.getID() == MouseEvent.MOUSE_RELEASED && lastDragged != null){
target = lastDragged;
lastDragged = null;
}

MouseEvent e2 = SwingUtilities.convertMouseEvent(this, e, target);
if(e2.getID() == MouseEvent.MOUSE_ENTERED){
lastEntered = target;
}
target.dispatchEvent(e2);
}

@Override
public void processMouseMotionEvent(MouseEvent e){
Component target = HeavyWeightInternalFrame.this;
if(target != HeavyWeightInternalFrame.this){
Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), target);
Component nwtarget = SwingUtilities.getDeepestComponentAt(target, p.x, p.y);
if(nwtarget != null)
target = nwtarget;
}
MouseEvent e2 = SwingUtilities.convertMouseEvent(this, e, target);
if(e2.getID() == MouseEvent.MOUSE_DRAGGED && lastDragged == null){
lastDragged = target;
}
target.dispatchEvent(e2);
}

Component getTarget(int x, int y){
boolean rpcenabled = HeavyWeightInternalFrame.this.isRootPaneCheckingEnabled();
HeavyWeightInternalFrame.this.setRootPaneCheckingEnabled(false);
Component[] children = HeavyWeightInternalFrame.this.getComponents();
for(Component child: children){
if(child == insulation) continue;
Rectangle bounds = child.getBounds();
if(bounds.contains(x, y)){
return child;
}
}
return HeavyWeightInternalFrame.this;
}

@Override
public void doLayout(){
jrp.setBounds(getRootPane().getBounds());
}

@Override
public void paint(Graphics g){
if(painting) return;
painting = true;
Graphics g2 = g.create();
try{
HeavyWeightInternalFrame.this.paint(g2);
} finally{
g2.dispose();
}

Rectangle clip = jrp.getBounds();
Shape oldClip = g.getClip();
g.setClip(clip);
super.paint(g);
g.setClip(oldClip);

painting = false;
}

@Override
public void update(Graphics g){
paint(g);
}

}

public static void main(String ... args){
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
try{
int j = Integer.parseInt(args[0]);
if(j == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(j == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
}catch(Exception x){}
Runnable run = new Runnable(){

public void run(){
JDesktopPane jdp = new JDesktopPane();
jdp.setBackground(Color.white);
for(int j = 0; j < 5; j++){
HeavyWeightInternalFrame jif = new HeavyWeightInternalFrame();
if(j % 2 == 0){
JTextPane b = new JTextPane();
b.setBackground(Color.green);
jif.add(new JScrollPane(b));
}
else{
Button b = new Button("Hi");
b.setPreferredSize(new Dimension(1000,1000));
b.setBackground(Color.red);
final JScrollPane jsp = new HeavyWeightJScrollPane(b);
jif.add(jsp);
}
jif.setMaximizable(true);
jif.setResizable(true);
jif.setIconifiable(true);
jif.setSize(300,300);
jdp.add(jif);
jif.setVisible(true);
}

JFrame jf = new JFrame();
jf.add(jdp);
jf.setSize(500,500);
jf.setVisible(true);
}
};
SwingUtilities.invokeLater(run);
}

}
[/code]

also, note the main/test uses the HeavyWeightJScrollPane code, so you'll need that to test this one out.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

I tried the HeavyWeightJScrollPane & the updated HeavyWeightInternalFrame. My testing indicated:

1. Updated HeavyWeightInternalFrame appears to be fine in my mdi environment.

2. The HeavyWeightJScrollPane seems to not scroll the HeavyWeightInternalFrame even though I move the scrollbar. It also appears the srollbar moves the first time then stops even if I reselect it a second time to move it further. If I go back to a JScrollPane everything seems normal as far as moving the JPanel that was added to the HeavyWeightJScrollPane.

Hope that helps. I am gone tomorrow morning MST but will check around 12:00PM MST for anything further you want me to try.

Good start on the HeavyWeightJScrollPane!

Thanks,
-Tony

leouser
Offline
Joined: 2005-12-12

hmm,

The only test Ive done for the HWJScrollPane is a Button with a large preferred size. I don't consider it a widget to be used with lightweights but is intended for heavy weights. With that said, Im not sure why a JPanel wouldn't work in it. :D Ill have to do some more testing with it.

Another thing that may need to be done is to create a HeavyWeightJDesktop. Im not sure but I suspect if you have the Desktop with lightweights all around it and you move the HWInternalPane outside of the visible bounds of the DTop it will result in the HWInternalPane being painted over the other widgets. Isn't this fun?

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

You are correct about the other lightweight components. I am using the HeavyWeightInternalFrame in a JDesktopPane the is in a lightweight splitter where the left pane of the two pane splitter has a Jpanel with a JTree in it and the right pane of the splitter has the JDesktopPane while above all that is a JToolBar containing JButtons.

If you want I can send an image of it but what is interesting is the lightweight and heavyweight controls so far for me have worked fine.

Regards,
-Tony

leouser
Offline
Joined: 2005-12-12

I think the simplest thing to do will be to do this:
Panel p = new Panel(new GridLayout(1,1));
p.add(JDesktopInstance);

then, when you are going to add the JDesktopPane you add the Panel instead. This cleared up the problem with the HWInternalPanes showing up outside of the bounds of the JDesktopPane.

leouser

leouser
Offline
Joined: 2005-12-12

oh yeah,

can you post some code showing the problem you are experiencing with the HWJScrollPane? Id like to have a malfunctioning test case to observe.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Okay here is the simple example snippet that fails jsut as I described. You just add in your main in the else clause:

Button b = new Button("Hi");
JButton bl = new JButton("light");
b.setBackground(Color.red);
bl.setBackground(Color.blue);
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
p.add(b,"East");
p.add(bl,"West");
p.setPreferredSize(new Dimension(1000,1000));
final JScrollPane sp = new HeavyWeightJScrollPane(p);
jif.add(sp);

leouser
Offline
Joined: 2005-12-12

This is a pretty interesting test case. Its exposed/created these problems:
1. stack trace, as the Panel is cast to a JComponent.
2. Ive seen the scrolling problem once so far.
3. Blocks the resizing via mouse code from operating.

#1 has been dealt with. I can't recreate #2 yet, maybe I fixed it with another change? #3, not sure what the deal is yet. :(

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi Leouser,

If you have a fix for #1 & maybe #2 I am willing to try it out and give feedback. If you want to wait till #3 is resolved that is fine also :)

Thanks,
-Tony

leouser
Offline
Joined: 2005-12-12

ahem, #3 was caused by not having the HeavyWeightInternalFrame set to be resizable. I couldn't fathom how the HWJScrollPane with a more complex content type would block the resizing and I guess that's why. So we may be ok now.

Here is the updated HeavyWeightJScrollPane:
[code]
import javax.swing.*;
import java.awt.*;

public class HeavyWeightJScrollPane extends JScrollPane{

boolean ignoreRemove;
JViewportParent jvparent;

HeavyWeightJScrollPane(Component view){
super(view);
}

@Override
public JViewport createViewport(){
jvparent = new JViewportParent();
return new HWJViewport();
}

@Override
public void setLayout(LayoutManager lm){
super.setLayout(new ScrollPaneLayout2());
}

class HWJViewport extends JViewport{

HWJViewport(){
super.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
}

@Override
public void setBounds(int x, int y, int width, int height){
super.setBounds(x, y, width, height);
jvparent.position();
}

@Override
public void setScrollMode(int mode){}
}

class JViewportParent extends Panel{
boolean validating;
public void doLayout(){}
public void setBounds(int x, int y, int width, int height){
position();
}

public void position(){
if(validating) return;
validating = true;
HeavyWeightJScrollPane.this.validate();
Rectangle vbb = getViewportBorderBounds();
super.setBounds(vbb.x, vbb.y, vbb.width, vbb.height);
validating = false;
}
}

class ScrollPaneLayout2 extends ScrollPaneLayout{
@Override
public void removeLayoutComponent(Component c){
if(ignoreRemove) return;
super.removeLayoutComponent(c);
}
}

@Override
public void setViewport(JViewport viewport) {
super.setViewport(viewport);
ignoreRemove = true;
jvparent.add(viewport);
add(jvparent);
ignoreRemove = false;
}
}
[/code]

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Thanks I will try the code out and let you know by 12:00AM MDT.

When I am done testing I would like to get your ideas about adding custom shaping of windows which would be great fun for the kids/students.

Many Thanks :)
-Tony

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Hey its before Midnight and YES IT WORKS GREAT!!!!!!!

Guess you can see I am happy. I do have just two suggestions.

Should you have the constructor public for HeavyWeightInternalFrame? And the second is should you have a public constructor for passing the caption for HeavyWeightInternalFrame?

Just curious.

Let me know if you want to try custom shaped windows since I am game to do that.

Best Regards,
-Tony

leouser
Offline
Joined: 2005-12-12

yes, those constructors should be public. Actually if these were ever going to code for general use Id probably want to do alot more with the pieces. Ive been more interested in getting a chunk of code together that you could use in your project but it may end up being the kernel of something else.

As to shaping things, thats up to you. :) Im still drawing up a list of things to work on for the next iteration of the ComponentShaper, but that doesn't mean you couldn't use it today.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Hopefully Sun finds use for the hard work you did by putting it in the kernel.

I believe in taking technology to the limit for a good cause. Guess I am old thinking.

Enjoy the picture in your email :)

Best Regards,
-Tony

joshy
Offline
Joined: 2003-07-02

Hi leouser. Where is your current shaping code? Is it part of a JDIC project now? I'd love to try it out.

Thanks,
Josh

leouser
Offline
Joined: 2005-12-12

well,

the code is here, minus the translucency code Ive experimented with on Windows:
https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?...

I should put the source in a zip so folks don't have to play date games on the forum, gathering the pieces. Maybe Ill do that today. If you need any help compiling the native shared library let me know.

I think Im going to add transluceny to the API but only support it on the Windows side. After watching my X session disintegrate everytime I made a simple API call has left me with a bad feeling for the time being. But that does not preclude it from being added at a later date if the Composite extension ever matures to a more stable point.

leouser

Joshua Marinacci

This appears to be just the screenshot.

I agree that it's a good idea to not support composite yet. Perhaps
you can include it but disable it and let developers turn it on when
they want to test it.
- j

On Nov 7, 2006, at 5:24 PM, swing@javadesktop.org wrote:

> well,
>
> the code is here, minus the translucency code Ive experimented with
> on Windows:
> https://jdk-collaboration.dev.java.net/servlets/
> ProjectForumMessageView?forumID=1463&messageID=15814
>
> I should put the source in a zip so folks don't have to play date
> games on the forum, gathering the pieces. Maybe Ill do that
> today. If you need any help compiling the native shared library
> let me know.
>
> I think Im going to add transluceny to the API but only support it
> on the Windows side. After watching my X session disintegrate
> everytime I made a simple API call has left me with a bad feeling
> for the time being. But that does not preclude it from being added
> at a later date if the Composite extension ever matures to a more
> stable point.
>
> leouser
> [Message sent by forum member 'leouser' (leouser)]
>
> http://forums.java.net/jive/thread.jspa?messageID=171262

- Blasting forth in three part harmony!

[att1.html]

leouser
Offline
Joined: 2005-12-12

Hmm, there are 20 other posts in that thread. You must be seeing only the first one. How are you viewing it?

leouser

leouser
Offline
Joined: 2005-12-12

Let me see here, if your doing windows your going to need these pieces:
the ComponentShaper.java from here:
https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?...
the WindowsComponentShaperImpl from here:
https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?...
the org_component_shaper_WindowsComponentShaperImpl.h and
WindowsComponentShaperImpl.cpp
from here:
https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?...
and the org_component_shaper_ComponentShaper.h
from here:
https://jdk-collaboration.dev.java.net/servlets/ProjectForumMessageView?...

I think this needs a zip,
leouser

tdanecito
Offline
Joined: 2005-10-10

Hi All,

The reason I want to know is I am trying to create a JPanel with a AWT or heavyweight type frame inside a JDesktopPane in place of a lightweight JInternalFrame. So in other words a heavyweight JInternalFrame.

Thanks in advance.

leouser
Offline
Joined: 2005-12-12

Well, you might want to study the UI delegates for the JInternalFrame, specifally the BasicInternalFrameTitlePane derivatives. That should give you some ideas how to do a title bar.

Im not sure how having a heavy weight internal frame would solve the other drawing problems you will see with the other lightweight internal frames.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Thanks for the help. The heavyweight frame will help when I am using a Jpanel which works okay so I do not have one caption dissapear behind another. I tried some of the tricks suggested by sun and quite a few other areas but none works.

I am against the wall on a delivery and want to get something to work with a MDI that does not have the issues. Any suggestions that show real hope are appreciated.

Thanks.

leouser
Offline
Joined: 2005-12-12

Hmm,

see if this code does anything for you:
[code]
import java.awt.*;
import javax.swing.*;
import java.beans.*;

public class HeavyWeightInternalFrame extends JInternalFrame{

Panel hw;
HeavyWeightInternalFrame(){
super();
setOpaque(false);
}

public void setSelected(boolean selected) throws PropertyVetoException{
super.setSelected(selected);
hw.repaint();
}

public void setLayer(int layer){
super.setLayer(layer);
hw.repaint();
}

@Override
public void setLayout(LayoutManager lm){
hw.setLayout(lm);
super.setLayout(new BorderLayout(){
@Override
public void layoutContainer(Container c){
hw.setBounds(0, 0, getWidth(), getHeight());
}
});
remove(hw);
add(hw);
revalidate();
}

@Override
protected void addImpl(Component comp, Object constraints, int index) {
if(hw == null){
hw = new Panel(){
public void paint(Graphics g){
super.paint(g);
paintBorder(g);
}

};
add(hw);
}

if(isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else if(comp == hw){
super.addImpl(comp, constraints, index);
}
else{
hw.add(comp, constraints, index);
}
}

public static void main(String ... args){

JDesktopPane jdp = new JDesktopPane();
for(int j = 0; j < 5; j++){
JInternalFrame jif = new HeavyWeightInternalFrame();
if(j % 2 == 0){
JTextPane b = new JTextPane();
b.setBackground(Color.green);
jif.add(b);
}
else{
Button b = new Button("Hi");
b.setBackground(Color.red);
jif.add(b);
}
jif.setSize(300,300);
jdp.add(jif);
jif.setVisible(true);
}

JFrame jf = new JFrame();
jf.add(jdp);
jf.setSize(500,500);
jf.setVisible(true);
}

}
[/code]

what it does is put a heavyweight between the JInternalFrame and the content that is added. This appears, at least with Metal LAF, to allow mixing of heavyweights and lightweights in the internal frames. I can have the JIF with a JTextPane in front of a JIF with a Button and it seems as though the Button does not show throw the JTextPane.

I think if this works it will get rid of your need to develop a heavyweight internal frame from scratch.

leouser

leouser
Offline
Joined: 2005-12-12

hmm,

the negatives Ive seen:
1. Does not work with GTK LAF. There is a method in Metacity that expects all children to be JComponents. Not sure why, its just using the getName() method which is in Component.

2. Motif, the outline drag is obscured by the heavyweights.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

I will take a look at what you so very thoughtfully are doing. I am not so much worried about other look and feels yet.

Youre not Santa in developers role between christmas's are you?

Really appreciate the help.
-Tony

leouser
Offline
Joined: 2005-12-12

Ive evolved it a little:
[code]
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.beans.*;
import java.util.*;

public class HeavyWeightInternalFrame extends JInternalFrame{

Panel hw;
JPanel jp;

HeavyWeightInternalFrame(){
super();
setOpaque(false);
}

@Override
public void setSelected(boolean selected) throws PropertyVetoException{
boolean oldSelected = isSelected();
super.setSelected(selected);
if(oldSelected != selected)
hw.repaint();
}

@Override
public void setBorder(Border b){
super.setBorder(b);
jp.setBorder(b);
}

@Override
public Border getBorder(){
return jp.getBorder();
}

@Override
public void setLayout(LayoutManager lm){
jp.setLayout(lm);
super.setLayout(new BorderLayout(){
public void layoutContainer(Container c){
hw.setBounds(0, 0, getWidth(), getHeight());
}
});
revalidate();
}

@Override
protected void addImpl(Component comp, Object constraints, int index) {
if(hw == null){
hw = new Panel();
hw.setLayout(new GridLayout(1,1));
jp = new JPanel();
jp.setBorder(getBorder());
jp.setLayout(getLayout());
hw.add(jp);
add(hw);
}

if(isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else if(comp == hw){
super.addImpl(comp, constraints, index);
}
else{
jp.add(comp, constraints, index);
}
}

public static void main(String ... args){
try{
int j = Integer.parseInt(args[0]);
if(j == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(j == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
}catch(Exception x){}

Runnable run = new Runnable(){

public void run(){
JDesktopPane jdp = new JDesktopPane();
jdp.setBackground(Color.white);
for(int j = 0; j < 5; j++){
JInternalFrame jif = new HeavyWeightInternalFrame();
if(j % 2 == 0){
JTextPane b = new JTextPane();
b.setBackground(Color.green);
jif.add(b);
}
else{
Button b = new Button("Hi");
b.setBackground(Color.red);
jif.add(b);
}
jif.setMaximizable(true);
jif.setResizable(true);
jif.setIconifiable(true);
jif.setSize(300,300);
jdp.add(jif);
jif.setVisible(true);
}

JFrame jf = new JFrame();
jf.add(jdp);
jf.setSize(500,500);
jf.setVisible(true);
}
};
SwingUtilities.invokeLater(run);
}

}
[/code]

Outside of the 2 problems I mentioned, it appears resizing may be damaged--> as in the JIF does not show the resize cursor.

leouser

leouser
Offline
Joined: 2005-12-12

Ive got resizing working for the most part. Some problems:
1. Occasionally the UI appears to get confused and will drag instead of resizing.
2. There is an awful flicker in the lightweights as the resizing is occuring.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Many thanks. I will look at this tonight by then knowing you will have solved the problem and maybe the national debt at the same time.

I look forward to giving it a real interesting test tonight. I may be using mostly heavyweight components since I am building the app and my customers do not know the difference between the two. Still never hurts to support both and I have the feeling some people over at JDIC will be very thankfull you solved a very big headache for them and thier users.

Regards,
-Tony

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Seems that the code does not quite run for me. It compiles but at runtime the setLayout is called before addImpl so jp is null.
I am using Mustang b102.

Must be something simple I am missing. I did take the code and break apart the HeavyWeightInternalFrame such that main() was in another class so maybe that caused the calling order of setLayout vs addImpl to be different than what worked for you.

Thanks for the answer to this mystery.

tdanecito
Offline
Joined: 2005-10-10

Okay as I thought I my error I still had another class that conflicted.

Does the resize capability of the child frame work for you?

It looks awesome dude!! Keep tuning to your hearts delight!!!!!

leouser
Offline
Joined: 2005-12-12

on my work machine yup. I haven't posted that code yet. Im looking at some different options as well. You can resize it but it really hurts the eyes as it happens. Im not sure what is causing it, maybe something outside of the drawing process.

I had this nutty idea about making the peer of the JInternalFrame be a heavy weight instead of a light weight and I did some experiments "stealing" a Panels peer and giving it to the JInternalFrame. It looked like it painted the frame but was totally unresponsive to mouse, key and focus events.

Id really like to get it to the point where it would work out of the box with all the shipped UIs. The real monkey wrench is that the GTK title bar expects its parent to be a JComponent. If you get past that, there is code that expects the parent to be a JInternalFrame.

Im not certain, but I think any popups may end up having to still be configured to be heavyweights. Ill have to test this out some.

Of course, the best solution would be that lightweights and heavyweights could intermix freely. But Im not sure when that ability will start showing up in the code. That doesn't help the here and now too much.

leouser

tdanecito
Offline
Joined: 2005-10-10

Thanks I was able to get resize to work and the jdic WebBrowser now displays so much better. For the resize I found the upper right area of the frame for metal look and feel worked but only if you were really carefull to watch when the cursor changed.

In general it worked quite well for me the clipping was so nice to have working and I did not see any of the painting issues you described. I even created a mdi app with the JDIC web browser and it WORKED GREAT!!

Now I am down to getting it to work in my own app but getting some strange error about pdata being null but that component has always been finicky for me. The error is below. By the way what was the reason your example was using SwingUtilities? Maybe there is something I should do to use that also?

I need to get some sleep but I am so close to getting the code to work from JDIC in my app except for the error.

Any thoughts appreciated.

-Tony

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: null pData
at sun.awt.windows.WComponentPeer.reshape(Native Method)
at sun.awt.windows.WComponentPeer.setBounds(Unknown Source)
at java.awt.Component$NativeInLightFixer.componentMoved(Unknown Source)
at java.awt.Component$NativeInLightFixer.install(Unknown Source)
at java.awt.Component$NativeInLightFixer.(Unknown Source)
at java.awt.Component.addNotify(Unknown Source)
at java.awt.Canvas.addNotify(Unknown Source)
at org.jdesktop.jdic.browser.WebBrowser.addNotify(Unknown Source)

leouser
Offline
Joined: 2005-12-12

yeah, the paint distortion I saw was when a JComponent was the main component and I was resizing the frame. If the center component was a heavy weight then it was ok.

I call SwingUtilities because Im using it to start the example on the EDT. Your supposed to start your swing apps always on the EDT. I believe that recommendation has changed from what it used to be in the past.

Im not sure what the problem is with that stack trace. It looks like the "pData", which is the probably a pointer to the native widget isn't pointing to a native widget. So when the component is first being shown or its being added to a visable hierarchy it doesn't have the native window component.

leouser

tdanecito
Offline
Joined: 2005-10-10

Hi leouser,

Thanks for the update. I have a working example that does not throw that error and I am now getting my program to match that example and hopefully the problem will go away.

In general the heavyweightinternalframe works much better than what I had before without it.

If there are any additional updates you want me to check out please let me know and I will do that.

Many Thanks

tdanecito
Offline
Joined: 2005-10-10

Oh yeah, I will look into the EDT you mentioned and make corrections.

Thanks

leouser
Offline
Joined: 2005-12-12

Ok here is the latest version.
[code]
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;

public class HeavyWeightInternalFrame extends JInternalFrame{

Panel hw;
JPanel insulation;
JRootPane jrp;
boolean painting;

HeavyWeightInternalFrame(){
super();
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
}

@Override
public void doLayout(){
super.doLayout();
if(insulation == null){
initialize();
}
insulation.setBounds(0, 0, getWidth(), getHeight());
}

void initialize(){
boolean rpc = isRootPaneCheckingEnabled();

insulation = new JPanelLayer();
hw = new PanelLayer();
jrp = new JRootPane();

insulation.add(hw);
hw.add(jrp);
add(insulation);

setRootPaneCheckingEnabled(rpc);
}

@Override
public void addImpl(Component comp, Object constraints, int index) {
if(insulation == null){
initialize();
}

if(isRootPaneCheckingEnabled()) {
jrp.getContentPane().add(comp, constraints, index);
}
else if(comp == insulation){
super.addImpl(comp, constraints, index);
}
else{
super.addImpl(comp, constraints, index);
}
}

@Override
public void setSelected(boolean selected) throws PropertyVetoException{
boolean oldSelected = isSelected();
super.setSelected(selected);
if(oldSelected != selected)
hw.repaint();
}

class JPanelLayer extends JPanel{
JPanelLayer(){
setLayout(new GridLayout(1,1));
setOpaque(false);
disableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK);
}

@Override
public void paint(Graphics g){
if(painting) return;
super.paint(g);
}
}

class PanelLayer extends Panel{
Component lastEntered;
Component lastDragged;

public PanelLayer(){
enableEvents(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK);
}

@Override
public void processMouseEvent(MouseEvent e){
Component target = getTarget(e.getX(), e.getY());
if(target != HeavyWeightInternalFrame.this){
Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), target);
Component nwtarget = SwingUtilities.getDeepestComponentAt(target, p.x, p.y);
if(nwtarget != null)
target = nwtarget;
}

if(e.getID() == MouseEvent.MOUSE_EXITED && lastEntered != null){
target = lastEntered;
lastEntered = null;
}
else if(e.getID() == MouseEvent.MOUSE_RELEASED && lastDragged != null){
target = lastDragged;
lastDragged = null;
}

MouseEvent e2 = SwingUtilities.convertMouseEvent(this, e, target);
if(e2.getID() == MouseEvent.MOUSE_ENTERED){
lastEntered = target;
}
target.dispatchEvent(e2);
}

@Override
public void processMouseMotionEvent(MouseEvent e){
Component target = HeavyWeightInternalFrame.this;
if(target != HeavyWeightInternalFrame.this){
Point p = SwingUtilities.convertPoint(this, e.getX(), e.getY(), target);
Component nwtarget = SwingUtilities.getDeepestComponentAt(target, p.x, p.y);
if(nwtarget != null)
target = nwtarget;
}
MouseEvent e2 = SwingUtilities.convertMouseEvent(this, e, target);
if(e2.getID() == MouseEvent.MOUSE_DRAGGED && lastDragged == null){
lastDragged = target;
}
target.dispatchEvent(e2);
}

Component getTarget(int x, int y){
boolean rpcenabled = HeavyWeightInternalFrame.this.isRootPaneCheckingEnabled();
HeavyWeightInternalFrame.this.setRootPaneCheckingEnabled(false);
Component[] children = HeavyWeightInternalFrame.this.getComponents();
for(Component child: children){
if(child == insulation) continue;
Rectangle bounds = child.getBounds();
if(bounds.contains(x, y)){
return child;
}
}
return HeavyWeightInternalFrame.this;
}

@Override
public void doLayout(){
jrp.setBounds(getRootPane().getBounds());
}

@Override
public void paint(Graphics g){
if(painting) return;
painting = true;
Graphics g2 = g.create();
try{
HeavyWeightInternalFrame.this.paint(g2);
} finally{
g2.dispose();
}

Rectangle clip = jrp.getBounds();
Shape oldClip = g.getClip();
g.setClip(clip);
super.paint(g);
g.setClip(oldClip);
painting = false;
}
}

public static void main(String ... args){
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
try{
int j = Integer.parseInt(args[0]);
if(j == 0) UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
else if(j == 1) UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
}catch(Exception x){}

Runnable run = new Runnable(){

public void run(){
JDesktopPane jdp = new JDesktopPane();
jdp.setBackground(Color.white);
for(int j = 0; j < 5; j++){
HeavyWeightInternalFrame jif = new HeavyWeightInternalFrame();
if(j % 2 == 0){
JTextPane b = new JTextPane();
b.setBackground(Color.green);
jif.add(new JScrollPane(b));
}
else{
Button b = new Button("Hi");
b.setBackground(Color.red);
jif.add(b);
}
jif.setMaximizable(true);
jif.setResizable(true);
jif.setIconifiable(true);
jif.setSize(300,300);
jdp.add(jif);
jif.setVisible(true);
}

JFrame jf = new JFrame();
jf.add(jdp);
jf.setSize(500,500);
jf.setVisible(true);
}
};
SwingUtilities.invokeLater(run);
}

}
[/code]

this one improves on the earlier version in that it will work with GTK Laf.

leouser

tdanecito
Offline
Joined: 2005-10-10

Thanks for the latest updates I will make sure I am using them. I will get back to you no later than 12:00AM MST.

I am using other mdi windows that are mainly lightweight and will get back to you also about that tonight hopefully I will get past that peer problem you diagnosed.

Keep up the great work!!