Minimizing a supplementary JFrame when main applic

2019-09-02 14:35发布

问题:

The application I'm working on contains a main JFrame, from which users might eventually open another supplementary frame. I am trying to implement such a behavior of the app where the supplementary frame is minimized (iconified) as soon as the main frame gets minimized.

I was thinking of overriding the setExtendedState method of the main frame to capture the moment when it gets minimised, and then fire property change event from there so that the supplementary frame may act upon to it.

I discovered however, that unfortunately the overridden setExtendedState never gets called.

I would greatly appreciate any ideas of achieving the desired behavior. Below is the code I used for testing...

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;


public class IconifySupplementaryFrameTest {

    public static void main(String[] args) {
        (new MainFrame()).setVisible(true);
    }

}

class MainFrame extends JFrame {
    public static final String EXTENDED_STATE_KEY = "extendedState";

    MainFrame() {
        super("Iconify test - main window");

        setLayout(new FlowLayout(FlowLayout.LEADING));

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(400, 400);
        setLocationByPlatform(true);

        add(new JButton(new AbstractAction("Show supplementary frame") {
            @Override
            public void actionPerformed(ActionEvent e) {
                SupplementaryFrame.doShow(MainFrame.this);
            }
        }));
    }

    @Override
    public synchronized void setExtendedState(int state) {
// This overridden method is never called ???       
        int oldState = getExtendedState();
        super.setExtendedState(state);
        firePropertyChange(EXTENDED_STATE_KEY, oldState, state);
    }
}


class SupplementaryFrame extends JFrame implements PropertyChangeListener {
    private static SupplementaryFrame instance;

    private SupplementaryFrame(final JFrame parentFrame) {
        super("Iconify test - supplementary window");

        setSize(300, 300);
        setLocationRelativeTo(parentFrame);

        parentFrame.addPropertyChangeListener(
                MainFrame.EXTENDED_STATE_KEY, this);

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                instance = null;
                parentFrame.removePropertyChangeListener(
                        MainFrame.EXTENDED_STATE_KEY,
                        SupplementaryFrame.this);
                SupplementaryFrame.this.dispose();
            }
        });
    }


    static void doShow(JFrame parentFrame) {
        if(instance == null) {
            instance = new SupplementaryFrame(parentFrame);
            instance.setVisible(true);
        }
        else {
            // omitted _ugly_ code to bring this window (instance) to front 
        }

    }


    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        int state = this.getExtendedState();
        int parentState = ((Integer)evt.getNewValue()).intValue();

        if((parentState & ICONIFIED) == ICONIFIED) 
            this.setExtendedState(state | ICONIFIED);
    }
}

回答1:

Just add WindowStateListener to MainFrame to make your code work with property change listener:

addWindowStateListener(new WindowStateListener() {

        @Override
        public void windowStateChanged(WindowEvent e) {
                firePropertyChange(EXTENDED_STATE_KEY, e.getOldState(), e.getNewState());
        }
    });


回答2:

The application I'm working on contains a main JFrame, from which users might eventually open another supplementary frame

Applications are generally designed to use a single JFrame. Supplementary windows are created by using a JDialog. When you create the dialog make sure you specify the frame as the owner of the dialog. Now when you iconify/deiconify the frame, the dialog is iconified in sync automatically.