How to make JInternalFrame(s) in JDesktopPane non-overlapping - java

I have multiple JInternalFrame(s) inside a JDesktopPane. All the JInternalFrame(s) are undecorated and I manage the dragging using mouse listeners. However, I want the internal frames to be non overlapping, i.e., one internal frame should not intersect with another.
Till now, I can check if two internal frames are overlapping by using getBounds().intersects() method. However, I am clueless as to what should I do next.
I tried Google but got no satisfactory answer. Please suggest a solution.
Thank you !

Two answers:
If you want to set which internal frame overlaps the other, use the setComponentZOrder(Component comp, int index) function.
e.g.
JDesktopPane desktopPane = new JDesktopPane();
contentPane.add(desktopPane);
JInternalFrame internalFrame = new JInternalFrame("New JInternalFrame");
desktopPane.add(internalFrame);
desktopPane.setComponentZOrder(internalFrame, 0);
Place the setComponentZOrder function in the JInternalFrame component listener.
internalFrame.addComponentListener(new ComponentAdapter() {
#Override
public void componentMoved(ComponentEvent e) {
desktopPane.setComponentZOrder(internalFrame, 0);
}
});
2. If you want them to strictly not overlap, place them in separate jframes.

Related

Resize code does not correspond with mouse movement

I have some code to resize a chatpanel dynamically, but it does not move according to the mouse. What happens is the mouse moves at a faster rate than the panel gets resized. For example, how I want it to be, is in any application, when you click on the border between two windows, and drag it, the mouse stays along with the piece you are clicking on, and currently this is not happening. here is my code. please let me know if you need more
public void mouseDragged(MouseEvent e) {
if(getCursor().getType() == Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR).getType()) {
owner.adjust((int)MouseInfo.getPointerInfo().getLocation().getY());
System.out.println("vertpanel: "+(int)MouseInfo.getPointerInfo().getLocation().getY());
}
}
public void adjust(int adjustment) {
int height = this.getHeight();
System.out.println((((double)(adjustment))/height)+":"+(((double)(height-adjustment))/height));
output.setHeightPercent((((double)(adjustment))/height));
output.componentResized(new ComponentEvent(this, 1));
input.setHeightPercent((((double)(height-adjustment))/height));
input.componentResized(new ComponentEvent(this, 2));
}
there is one main panel, a chatpanel, and within it, there are two smaller panels, a chat input and a chat output
Can't tell exactly what you are doing based on your code.
I would suggest that you should NOT be manually setting the dimensions of the output and input coponents. You should let the layout manager determine how to resize each component as the parent container is resized.
So in your resize code you would need to invoke revalidate() on the parent container as it is resized.
Check out Resizing Components. You should be able to use the ComponentResizer class as long as you use setAutoLayout(true).

Invisible JFrame/JTable how much faster?

I have a swing app. with a jframe with lots of internal frames containing large JTable.
Those jtables get updated continuously so there is lots of repainting going on.
in some circumstances I can simply keep the JFrame invisible. (frame.setVisible(false))
I was wondering if anybody knows if I will gain something in terms of performance
(something considerable or not)
such as 50% gain or you would only get 2% gain...
and maybe some sort of explaination on what to expect.
thanks
p.s.
Another way to rephrase the question is:
Are swing components clever enough not to repaint/reflow theirselves if not visible ???
Take a look at the Swing Painting Guidelines which have some useful tips on painting efficiency. For example:
On components with complex output,
repaint() should be invoked with
arguments which define only the
rectangle that needs updating, rather
than the no-arg version, which causes
the entire component to be repainted.
Components which render complex output
should make smart use of the clip
rectangle to narrow the drawing
operations to those which intersect
with the clip area.
It's also quite easy to prove that non-visible components are not painted. The following code hides a panel and prints out if paint is called.
public static void main(String args[]) throws Exception {
JFrame f = new JFrame();
final JPanel p = new JPanel(){
public void paint(Graphics g){
super.paint(g);
System.out.println("IN PAINT");
g.fillRect(10, 10, 20, 20);
}
};
f.setLayout(new BorderLayout());
f.add(p, BorderLayout.CENTER);
JButton b = new JButton("OK");
b.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("PRESSED");
p.setVisible(!p.isVisible());
}
});
f.add(b, BorderLayout.SOUTH);
f.setSize(100,100);
f.setVisible(true);
}
I believe you should temporarily disconnect the TableModel from the JTable while you are not displaying the JTable.
The biggest problem you face is that the JTable reacts to model change events and continuously repaints itself.
It is also possible that the JTable is intelligent enough to not repaint itself while not visible (but has model changes) but I wouldn't put my money on this.
The best way to solve this question is to test both. If you profile both options and see no gain then you try a different route like sola suggested. Just make sure you are not optimizing the wrong part of your application.
I can't give you any numbers on how much performance gain you will see, this depends on too many factors and is best left up to your own profiling. However, if your component is not visible, then the paintComponent() (or repaint()) method won't be called either as far as I know.
If your JTable is in a JScrollPane it seems it will repaint at each line adition (and call to fireTableRowsInserted of your model). Thus because the scrollpane will update it scollbars and then its contained component (JTable). If your table is not in a scrollpane then it will redraw only the shown lines. Therefore if your lines are not shown you will not trigger a repaint... Stupide. I'm looking for a way to avoid this.

How would you make a frame visible if the mouse is inside it and invisible when it's not in Java?

So if I was writing pseudo code:
if(mouseInsideFrame==true)
frame.setVisible(true);
else
frame.setVisible(false);
What method would I use for the mouseInsideFrame in the if statement?
Thanks
I came across a post on java.net that covers visibility options, including this one using a private AWT API.
public class TransparentFrame {
private static final float OPAQUE = 1.0f;
private static final float TRANSLUCENT = 0.1f;
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
com.sun.awt.AWTUtilities.setWindowOpacity(frame, OPAQUE);
}
#Override
public void mouseExited(MouseEvent e) {
com.sun.awt.AWTUtilities.setWindowOpacity(frame, TRANSLUCENT);
}
});
frame.setVisible(true);
}
}
This is OK for toy code, but obviously I wouldn't use a private com.sun class for portable production code.
Update: Same method as before, but with more explicit step-by-step explanation.
Other respondents wonder what you want to achieve with this and question the design behind an app that unexpectedly jumps up at the user. I guess it's a matter of how dead set you are to implement this functionality exactly as you described. The technique itself may be useful for other purposes too, which is my main motivation for my new, improved revision of this answer.
As far as I know, a frame that's not visible can't capture mouse events. So it won't know if the mouse is inside it or not.
There's a loophole around this problem: If you make your frame visible but borderless and fully transparent, it will be visible in the technical sense but invisible to the user for practical purposes.
The borderless part is easy: setUndecorated(true).
It would be great if JFrame had a method like setOpaque() or setTranslucent() where you could make it fully transparent, but alas, it doesn't.
Another answer mentions a solution based on a Sun private class which does permit you to make the window transparent. This will work for current and probably near-future Sun JREs but is far from guaranteed to work with other and future JREs, so I can't recommend it. Sun expliticly advises against using their private classes this way.
There's an alternate, somewhat hacky alternative: The frame is left fully visible but it displays the image of a screenshot of the screen behind it. Because this means we're effectively looking through the frame, it's effectively invisible. This solution is described here: http://onjava.com/pub/a/onjava/excerpt/swinghks_hack41/index.html?CMP=OTC-FP2116136014 . The author and I both admit to this being a a bit clumsy; it also involves a lot more code than should be necessary. But it's based on standard Java coding and should be supported unchanged in many Java environments upward of about version 1.4 or so.
The tip describes how to create a Component that displays the screen background. That's fine for when you want the frame to be invisible, but what happens when you want it to be normally visible?
The thing to do is to give the JFrame's ContentPane a CardLayout and add both the TransparentBackground component and your intended main visible component (likely a JPanel) to it. With that set up, switching between "invisible" and visible involves simply:
setUndecorated(false) // (true)
cardLayout.last() // (first)
This switching, of course, will be controlled by a MouseListener you can add to the JFrame.
Out of the top of my head, there is a fairly easy way to get the position of the mouse on the screen (I think it has something to do with Toolkit). Now, if you can combine that with a way to find out your frame's position on the screen (if you don't already know), you have your solution.
I'm curious what you're trying to do though.
Given what you are trying to do, I would say you need two frames (or perhaps just JPanels and frame that does a lot of changing. One is to capture the mouse moving over it (make it transparent, undecorated or otherwise acceptably out of the way) and when the mouse moves over it, show the new frame (or panel) and then hide that when the mouse moves out of it.
The other answers here give you the basics on how to capture the mouse events and set the frame undecorated and transparent.
Normally you could use listeners. Specifically:
frame.addMouseListener(new MouseListener() {
public void mouseEntered(MouseEvent evt) {
frame.setVisible(true);
}
public void mouseExited(MouseEvent evt) {
frame.setVisible(false);
}
});
But the problem is that since your JFrame is not visible, there is no way to listen to mouse events!!!! At least, from what I know....

Problem with mouseListener on JPanel

I have problem with mouseListener in JPanel.
I add JLabel which contain image(size 600 x 600) on JPanel, and I add mouseListener for the JPanel.
Everytimes I click on the image, the image should change to another image, and this is working fine. However, the problem is that, only if I click on the right side or at the center of the image, then the image will change to another image. The image doesn't change when I click on the top or on the left side. This make me confused. I want the image to change to another image when I click everywhere within the image display.
private final int SECOND= 1;
private final int FIRST = 0;
int imageCounter = 0;
JLabel picture;
JPanel panel;
...
private mainLayout () {
GridBagLayout m = new GridBagLayout();
Container c = (Container)getContentPane();
GridBagConstraints con;
c.setLayout (m);
picture = new JLabel();
picture.setIcon(getImages(myImage.get(imageCounter).get(FIRST))); //first Image
panel = new JPanel();
con = new GridBagConstraints();
con.anchor=GridBagConstraints.CENTER;
con.gridy = 1; con.gridx = 0;
m.setConstraints(panel, con);
c.add(panel);
panel.add(picture); //add the pictures
panel.addMouseListener(l);
....
}
MouseListener l = new MouseAdapter(){
public void mouseClicked (MouseEvent e)
{
Point p = e.getPoint();
if((panel.getBounds().contains(p))
picture.setIcon(getImages(myImage.get(imageCounter).get(SECOND)));
}
};
The problem looks as if it might be in this unnecessary code:
Point p = e.getPoint();
if((panel.getBounds().contains(p))
The mouse listener is on the panel, so the mouse coordinates will be relative to the panel top left. panel.getBounds() gets the bounds of the panel relative to whatever its parent container is.
It's worth noting the mouse event behave very strangely. They "bubble up" until they hit a component with a mouse listener attached. So, adding a mouse listener actually changes the behaviour of a component. Adding the listener to a parent will potentially miss events depending upon the exact way the component is set up (which may change arbitrarily). There are a number of ways around this, none of them good.
The likely problem you have is the same I have encountered, that your event is getting gobbled up in your hierarchy as a previous poster implied. In reference to camickr's reply, it really doesn't matter if you extend JPanel or JLabel as long as you're aware of the consequences. JPanel offers you a lot more capability and has many useful things already built into it. But let's take the simple example where you have the following:
A JFrame that contains a JPanel, call it's JParent. JParent has a set of mouse listeners dedicated to it.
JParent contains a child JPanel that's added to its components, called JChild. JChild also has its own set of mouse listeners.
What happened when you click on an area that is not occupied by JChild? You get the response of JParent's listeners. If you click in an area with JChild visible, only JChild's mouse events will fire.
So be very careful in debugging as Java's swing may have different behavior than you may be used to from other implementations of drawing simple forms/GUIs. Events are basically one-shot and the lowest level component gets first dibs. If you try to fire the parent's events anyway, your x/y coords will be based on the child and not the parent. I'm still trying to come up with a good work around myself because I need access specifically to the parent to move an object elsewhere.
The best I can think of that isn't a mess to debug/think about are these two ideas:
a) have each of your individual components contain their own exclusive set of events and try to prevent the 'bubbling up' effect from coming into play.
b) handle all events on the parent
I'd prefer a as it avoids nasty things such as checking component classes just to figure out what kind of reaction you want (i.e. things like what kind of right-click menu to show).
Edit: So you can handle this either way I've discovered. You can use the dispatchEvent message to forward the events back upward the chain. In my case I have to gobble up the first event (or alter it) and send the x-y positions as if they are relative to the parent (using offsets). I'd say the better way to do it is through forwarding because then all your individual components can be encapsulated.
Are you positive that you are actually clicking? The mouse click event only fires if the mouse is pressed and released in the exact same spot. If your mouse is moving even minimally while you are clicking, the event won't be fired.
Out of curiosity, why are you using a JLabel to display an image? You may be better off writing an ImagePanel class that extends JPanel and overrides the paint() method to do your own drawing. Then you can attach MouseListeners right to the panel.

Find "real" height/width of Swing/AWT object

Because Canvas3D doesn't have the ability to resize dynamically with the parent frame, I would like to be able to track when a user resizes a window and then resize it manually myself. (If this ends up crashing Canvas3D, as some docs suggest, I will simply destroy and recreate it when the user resizes their window). Part of this procedure involves being able to accurately tell how big the container panel is to begin with.
The two methods I've tried:
panel.getHeight();
panel.getPreferredSize().height;
Don't seem to accurately report things: getHeight() is invariably zero, and getPreferredSize() returns numbers that don't actually have anything to do with the actual size of the panel.
Any ideas?
Edit: So, I took a debugger to the panel object and manually inspected the non-object properties and I didn't see anything that resembled width/height. Granted, there are sub-objects that I didn't look at. Also, maybe the window has to be visible (it isn't, at the point I'm interfacing the object) when I query for height/object?
Edit 2: So, Swing classes are subclasses of AWT classes, so I imagine if you're able to find the height/width of those, the approach would generalize. I've amended the title accordingly.
To determine the size of a component you have to either:
have set it manually at some point
run the layout manager responsible for layouting the component
Generally, you get the exact size of a component via the getSize() method, which returns a Dimension object containing width and height, but getWidth/Height() should work too. But this can only work, if one of the two preconditions are met. If a window has never been made visible, has no layout manager or the component (you want to know the size of) has been added after the window/container has been made visible, the size usually is zero.
So to get the correct size, you have to make the container/frame visible (after you have added the component) or call validate() or doLayout() on the container to recalculate the layout, if you added the component after the last layout was done. Another thing to keep in mind is setting and probably configuring a layout manager on the container. If no layout manager ist set (null), even making a container visible oder calling validate() does not set a size on its children.
The minimumSize/preferredSize/maximumSize properties are hints to the layout manager, how the component should be sized, but it does not have to obey them (most layout managers don't).
Edit 2: After I read your other question about the same subject, I think you should read Using Layout Managers from The Java Tutorials
Edit: I don't know if you already figured that out, but to react to the resizing of the window, you can do something like this:
public class WindowResizeTest extends JFrame {
public static void main(String[] args) {
new WindowResizeTest();
}
public WindowResizeTest() {
this.setSize(640, 480);
JPanel panel = new JPanel();
panel.setBackground(Color.RED);
this.add(panel);
this.addComponentListener(new ComponentListener() {
public void componentResized(ComponentEvent e) {
System.out.println(e.getComponent().getSize());
}
public void componentHidden(ComponentEvent e) {}
public void componentMoved(ComponentEvent e) {}
public void componentShown(ComponentEvent e) {}
});
this.setVisible(true);
}
}
I found out that if you extend by JFrame, this code can be used also to save time, effort and space.
int windowWidth = getWidth();
int windowHeight = getHeight();
I know you already got an answer but if you ever need an alternative, here it is.

Categories

Resources