2

I have three components in a container and buttons in it. When I hit the minimize button the components gets minimized to the bottom of the container and when I hit the minimized component then it gets maximized.

Suppose three components are lying at the bottom and if I maximize the 2nd component then it gets maximized and the 3rd minimized component does not take the position of the 2nd and this remains as space.

Screenshot
enter image description here

package Project;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyVetoException;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicInternalFrameTitlePane;
import javax.swing.plaf.basic.BasicInternalFrameUI;

public class Test2 {

    public Test2() throws HeadlessException, PropertyVetoException {
        createAndShowGUI();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new Test2();
                } catch (HeadlessException ex) {
                    ex.printStackTrace();
                } catch (PropertyVetoException ex) {
                    ex.printStackTrace();
                }

            }
        });
    }

    private void createAndShowGUI() throws HeadlessException, PropertyVetoException {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        final JDesktopPane jdp = new JDesktopPane() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600, 400);
            }
        };

        frame.setContentPane(jdp);
        frame.pack();

        createAndAddInternalFrame(jdp, 0, 0);
        createAndAddInternalFrame(jdp, 300, 0);
        createAndAddInternalFrame(jdp, 1, 200);

        frame.setVisible(true);
    }

    private void createAndAddInternalFrame(final JDesktopPane jdp, int x, int y) throws PropertyVetoException {
        final JInternalFrame jInternalFrame = new JInternalFrame("", true, true, true, true);
        jInternalFrame.setLocation(x, y);

        JPanel jp = new JPanel();
        JLabel jl=new JLabel("panel"+x);

        JButton jb = new JButton("_");
        JButton jb2 = new JButton("[]");
        JButton jb3 = new JButton("X");

        jInternalFrame.setLayout(new GridLayout(2, 2));
jp.add(jl);
        jp.add(jb);
        jp.add(jb2);
        jp.add(jb3);

        jInternalFrame.add(jp);

        jb.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    if (jInternalFrame.getLayer() == JDesktopPane.FRAME_CONTENT_LAYER) {
                        jdp.remove(jInternalFrame);
                        jdp.add(jInternalFrame, JDesktopPane.DEFAULT_LAYER);
                        jdp.revalidate();
                        jdp.repaint();
                    }
                    jInternalFrame.pack();
                    jInternalFrame.setIcon(true);
                } catch (PropertyVetoException ex) {
                    ex.printStackTrace();
                }

            }
        });
        jb2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    if (jInternalFrame.isMaximum()) {//restore
                        jInternalFrame.pack();
                    } else {//maximize
                        jInternalFrame.setMaximum(true);
                    }
                    jdp.remove(jInternalFrame);
                    jdp.add(jInternalFrame, JDesktopPane.FRAME_CONTENT_LAYER);
                    jdp.revalidate();
                    jdp.repaint();
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        });
        jb3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    jInternalFrame.dispose();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }

            }
        });

        BasicInternalFrameTitlePane titlePane = (BasicInternalFrameTitlePane) ((BasicInternalFrameUI) jInternalFrame.getUI()).getNorthPane();
        jInternalFrame.remove(titlePane);

        jInternalFrame.pack();
        jInternalFrame.setVisible(true);
        jdp.repaint();

        jdp.add(jInternalFrame);
    }
}
Community
  • 1
  • 1
  • See [How to write mouse listeners](http://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html) – MadProgrammer Feb 15 '13 at 06:35
  • @MadProgrammer is it linked with mouse listener? I dont think so –  Feb 15 '13 at 06:37
  • 1
    Sorry, read it as "user moves" – MadProgrammer Feb 15 '13 at 06:39
  • @MadProgrammer sorry but i did not find any thing related to my question. Can you sort it out? –  Feb 15 '13 at 06:41
  • @MadProgrammer shouldn't he consider using `GridBagLayout` and then decrease the x coordinate of the components based on some calculations ? That is what I get of it :) – An SO User Feb 15 '13 at 07:10
  • @LittleChild He's essentially using a null layout manager. This makes him responsible for updating the layouts – MadProgrammer Feb 15 '13 at 07:13
  • @MadProgrammer Yeah, if he uses `GridBagLayout` then he is basically done. You are the extreme programmer. Why don't you rewrite his code and implement that functionality ? – An SO User Feb 15 '13 at 07:15
  • From what I can gleen (and memory), the `DesktopManager` is responsible for the management of the internal frames, including "iconifying" them, but I don't see any listeners. The other problem is, also, the iconified representation of the internal frames is handled by a different class (so you couldn't just check for all the frames that are minimized and shuffle them). I would imagain if your desperate, you could supply you own `DesktopManager`, but that's a lot of work for little gain. – MadProgrammer Feb 15 '13 at 07:23
  • @LittleChild I don't think `GridBagLayout` will do what he wants (based on his previous question) and I'm working on a trig problem - I hate trig :( – MadProgrammer Feb 15 '13 at 07:24
  • @MadProgrammer trig ? Trigonometry ? You can try [Khan Academy](http://www.khanacademy.org) if you need resources :) – An SO User Feb 15 '13 at 10:06

2 Answers2

2

I've tested this with Metal and Windows L&F, you might need to test it with some others.

Basically, when the component is invalidated and the doLayout method is called, we check for the existence of any JInternalFrame.JDesktopIcon components. We then take these and layout them out as we like...

public class TestInternalFrame {

    public static void main(String[] args) {
        new TestInternalFrame();
    }

    private int xpos = 0;
    private int ypos = 0;

    public TestInternalFrame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception exp) {
                    exp.printStackTrace();
                }
                DesktopPane pane = new DesktopPane();
                pane.add(newInternalFrame());
                pane.add(newInternalFrame());
                pane.add(newInternalFrame());

                JFrame frame = new JFrame();
                frame.add(pane);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(400, 400);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

            }
        });
    }

    public JInternalFrame newInternalFrame() {
        JInternalFrame inf = new JInternalFrame("Blah", true, true, true, true);
        inf.setLocation(xpos, ypos);
        inf.setSize(100, 100);
        inf.setVisible(true);

        xpos += 50;
        ypos += 50;

        return inf;
    }

    public class DesktopPane extends JDesktopPane {

        @Override
        public void doLayout() {
            super.doLayout();
            List<Component> icons = new ArrayList<Component>(25);
            for (Component comp : getComponents()) {
                if (comp instanceof JInternalFrame.JDesktopIcon) {
                    icons.add(comp);
                }
            }

            int x = 0;
            for (Component icon : icons) {

                int y = getHeight() - icon.getHeight();
                icon.setLocation(x, y);
                x += icon.getWidth();

            }
        }
    }
}

Make no mistake, this is a rough hack

Updated

int x = 0;
for (Component icon : icons) {
    int y = getHeight() - icon.getHeight();
    icon.setLocation(x, y);
    x += icon.getWidth();
    setLayer(icon, 10); // <--- Add me
}

To your other problem, you simply need to move the icon to a higher layer. The problem with this, is you actually need to find a layer high enough. You could use Integer.MAX_VALUE, but that's a little harsh (and you might want something over the top of the that), instead, you could calculate the maximum layer and sit +1 ontop of that...

public void doLayout() {
    super.doLayout();
    List<Component> icons = new ArrayList<Component>(25);
    int maxLayer = 0;
    for (Component comp : getComponents()) {
        if (comp instanceof JInternalFrame.JDesktopIcon) {
            icons.add(comp);
            maxLayer = Math.max(getLayer(comp), maxLayer);
        }
    }

    maxLayer++;
    int x = 0;
    for (Component icon : icons) {

        int y = getHeight() - icon.getHeight();
        icon.setLocation(x, y);
        x += icon.getWidth();
        setLayer(icon, maxLayer);

    }
}

You really need to take the the time to study How to use Internal Frames and How to use Layered Panes as (at least the last part) is covered in these...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • thanks for posting your answer but it fulfills half answer. As i said you before the minimized frame should be visible when i max one frame. But in case the max frame overlaps all the other frames(even it is in orginal postion or in minimized state) I hope you have understood my requirement –  Feb 15 '13 at 07:46
  • thanks for your post .you might have seen my original code which shows that i have created my own buttons for max,min etc. But in this code we are using the default buttons. So i am wandering to know if we create our own buttons then will it function here and after max will the min panels move away –  Feb 15 '13 at 09:33
  • 1
    If I understand correctly (IIUC), you can use `Action` to encapsulate functionality, as suggested in the example cited [here](http://stackoverflow.com/a/8542622/230513). – trashgod Feb 15 '13 at 12:50
  • @sukant So long as you are using the internal frame's min/max/restore functionality you should be fine – MadProgrammer Feb 15 '13 at 19:09
  • @MadProgrammer see the 2nd picture I want not to use inbuilt buttons like min/max/restore.I want to create my own buttons so i am asking for that –  Feb 16 '13 at 04:37
  • @sukant You really need to start reading the [Java Docs](http://docs.oracle.com/javase/7/docs/api/javax/swing/JInternalFrame.html). You can either use the `DesktopManager` directly, or use [`JInternalFrame#setIcon`](http://docs.oracle.com/javase/7/docs/api/javax/swing/JInternalFrame.html#setIcon%28boolean%29) and [`JInternalFrame#setMaximum`](http://docs.oracle.com/javase/7/docs/api/javax/swing/JInternalFrame.html#setMaximum%28boolean%29) to change the state of the `JInternalFrame`, which is what I said in the previous comment ;) – MadProgrammer Feb 16 '13 at 04:49
  • @MadProgrammer i have done already buttons on my own ,just i need to implement it. Yes you are right i should read but actually i have much work and has absolutely no time for read,so asking for your help –  Feb 16 '13 at 05:19
1

Something like that:

jdp.setDesktopManager( new DefaultDesktopManager(){
    @Override
    public void deiconifyFrame(JInternalFrame f) {
        super.deiconifyFrame(f);
        JDesktopPane d = f.getDesktopPane();
         JInternalFrame[] frames = d.getAllFrames();
         for(JInternalFrame frame : frames ) {
             Rectangle bounds = getBoundsForIconOf(frame);
              // relayout all frames
         }
    }
});
oliholz
  • 7,447
  • 2
  • 43
  • 82
  • I like your idea, but you're potentially changing the default behavior of the `JDesktop` under different platforms (I know, because the Windows implementation had a bug in it for awhile and we had to switch it out for a different one :P)) – MadProgrammer Feb 15 '13 at 07:31
  • interesting reply, i didn't know – oliholz Feb 15 '13 at 07:35
  • @oliholz sorry but its not working. Can you try in any other way? –  Feb 15 '13 at 07:36
  • We spent 4 weeks trying to track this problem (switch from Metal to Windows and it all feel apart) - ended up relying on the `DefaultDesktopManager` I think – MadProgrammer Feb 15 '13 at 07:37
  • @oliholz It's more of a "beware" then anything, still a nice idea. – MadProgrammer Feb 15 '13 at 07:38
  • @sukant You need to be a little more descriptive over what's not working. What did you try, where do you think it failed... – MadProgrammer Feb 15 '13 at 07:39
  • @MadProgrammer See there are three internal frames.I am minimizing all then it comes down(i mean to the bottom of the container). Again i am maximizing the internal frame(present at the bottom) then it gets maximized but it also overlaps all the internal frames(even the minized frame are also not visible) –  Feb 15 '13 at 07:51
  • @MadProgrammer did you get my requirement? –  Feb 15 '13 at 08:30