How to move minimized components placed at the bot

2020-04-11 07:43发布

问题:

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

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);
    }
}

回答1:

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...



回答2:

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
         }
    }
});