Java 当JComponent不再可见时,是否有方法从集合中删除UCASE父对象以获取通知?
假设我有一个简单的JFrame,其中一个JTabbedPane包含3个面板,第二个面板包含一个JComponent。当“Tab 2”面板从其容器中移除时,是否有一种方法通知JComponent?我的问题是JComponent可能在层次结构中很深 显然,我在这里寻找SWING解决方案…:) 我试着用()来做这件事,但运气不好。。。我显然做错了什么Java 当JComponent不再可见时,是否有方法从集合中删除UCASE父对象以获取通知?,java,swing,ancestor,componentlistener,Java,Swing,Ancestor,Componentlistener,假设我有一个简单的JFrame,其中一个JTabbedPane包含3个面板,第二个面板包含一个JComponent。当“Tab 2”面板从其容器中移除时,是否有一种方法通知JComponent?我的问题是JComponent可能在层次结构中很深 显然,我在这里寻找SWING解决方案…:) 我试着用()来做这件事,但运气不好。。。我显然做错了什么 另外,ASCII艺术是由。我将使用ComponentListener来完成这项工作(CardLayout非常接近,与JTabbedPane类似),代码示
另外,ASCII艺术是由。我将使用
ComponentListener
来完成这项工作(CardLayout
非常接近,与JTabbedPane
类似),代码示例包含所有相关的侦听器(免责声明-->注意阻止EDT仅作为代码示例使用,并且仅以这种形式使用)
Ancesor&HierarchyListener
是有点异步的,从AncestorListener
多亏了mKorbel's发布了一个很好的例子,他使用了HierarchyListener,我想出了一个我认为可以满足我需求的解决方案。在本例中,我使用
JLabel
作为需要通知的组件
我会接受mKorbel的回答,因为他为我节省了很多时间
代码如下:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.JTabbedPane;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
public class TestFrame extends JFrame {
private static final long serialVersionUID = 8388031406846751884L;
private JPanel contentPane;
private JTabbedPane tabbedPane;
private JLabel label; /// The component that needs to be notified when it should save its states.
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestFrame frame = new TestFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Adds necessary listeners.
* @param argLabel
*/
private void install(JLabel argLabel) {
// ::::: HierarchyListener ::::::::::::::::::::::::::::::::::::::::::::::::::::::::
argLabel.addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent arg0) {
if ((arg0.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
if (!arg0.getComponent().isDisplayable()) {
// component is not displayable due to the panel being removed
doSomething();
}
}
}
});
// ::::: AncestorListener :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
argLabel.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent arg0) {
// not interested in this one
}
@Override
public void ancestorMoved(AncestorEvent arg0) {
// not interested in this one
}
@Override
public void ancestorRemoved(AncestorEvent arg0) {
// ancestorRemoved() is useful when user navigates between tabs, and causes
// component to become invisible.
doSomething();
}
});
}
public void doSomething() {
System.out.println("Saving some state(s)...");
}
/**
* Create the frame.
*/
public TestFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 693, 376);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
// first panel
tabbedPane.add(new JPanel());
// second panel
JPanel panelWithComponents = new JPanel();
JPanel childPanel = new JPanel();
label = new JLabel("Test label");
install(label);
childPanel.add(label);
panelWithComponents.add(childPanel);
tabbedPane.add(childPanel);
// third panel
tabbedPane.add(new JPanel());
contentPane.add(tabbedPane, BorderLayout.CENTER);
JButton btnRemove = new JButton("Remove second");
btnRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
tabbedPane.remove(1);
}
});
contentPane.add(btnRemove, BorderLayout.SOUTH);
} // main() method
} // TestFrame class
如果组件本身需要执行某些操作,您还可以覆盖add/removeNotify(不过不要忘记调用super)
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
import javax.swing.*;
public class LabelWithTimer extends JLabel {
private final Timer timer;
public LabelWithTimer() {
timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setText(new Date().toString());
}
});
}
@Override
public void addNotify() {
super.addNotify();
timer.start();
System.out.println("Clock started");
}
@Override
public void removeNotify() {
System.out.println("Clock stopped");
timer.stop();
super.removeNotify();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
final JPanel clock = new JPanel(new GridBagLayout());
clock.add(new LabelWithTimer());
final JTabbedPane tabs = new JTabbedPane();
tabs.addTab("Empty", new JLabel());
tabs.setPreferredSize(new Dimension(400, 300));
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(tabs);
frame.getContentPane().add(new JButton(new AbstractAction("Add/remove clock") {
@Override
public void actionPerformed(ActionEvent e) {
if(tabs.getTabCount() == 2) {
tabs.removeTabAt(1);
}
else {
tabs.addTab("Clock", clock);
tabs.setSelectedIndex(1);
}
}
}), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
这个场景可以通过
antestorremoved()来处理
。当用户选择其他JTabbedPane的子组件时,该组件将获得该事件。问题是,当包含该组件的JTabbedPane的子组件被删除时……看起来唯一得到通知的方法是使用ContainerListener或适配器……感谢mKorbel,我所需要的只是当用户删除该组件时的HierarchyListener专家组:)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.JTabbedPane;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
public class TestFrame extends JFrame {
private static final long serialVersionUID = 8388031406846751884L;
private JPanel contentPane;
private JTabbedPane tabbedPane;
private JLabel label; /// The component that needs to be notified when it should save its states.
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
TestFrame frame = new TestFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Adds necessary listeners.
* @param argLabel
*/
private void install(JLabel argLabel) {
// ::::: HierarchyListener ::::::::::::::::::::::::::::::::::::::::::::::::::::::::
argLabel.addHierarchyListener(new HierarchyListener() {
@Override
public void hierarchyChanged(HierarchyEvent arg0) {
if ((arg0.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
if (!arg0.getComponent().isDisplayable()) {
// component is not displayable due to the panel being removed
doSomething();
}
}
}
});
// ::::: AncestorListener :::::::::::::::::::::::::::::::::::::::::::::::::::::::::
argLabel.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent arg0) {
// not interested in this one
}
@Override
public void ancestorMoved(AncestorEvent arg0) {
// not interested in this one
}
@Override
public void ancestorRemoved(AncestorEvent arg0) {
// ancestorRemoved() is useful when user navigates between tabs, and causes
// component to become invisible.
doSomething();
}
});
}
public void doSomething() {
System.out.println("Saving some state(s)...");
}
/**
* Create the frame.
*/
public TestFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 693, 376);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
// first panel
tabbedPane.add(new JPanel());
// second panel
JPanel panelWithComponents = new JPanel();
JPanel childPanel = new JPanel();
label = new JLabel("Test label");
install(label);
childPanel.add(label);
panelWithComponents.add(childPanel);
tabbedPane.add(childPanel);
// third panel
tabbedPane.add(new JPanel());
contentPane.add(tabbedPane, BorderLayout.CENTER);
JButton btnRemove = new JButton("Remove second");
btnRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
tabbedPane.remove(1);
}
});
contentPane.add(btnRemove, BorderLayout.SOUTH);
} // main() method
} // TestFrame class
import java.awt.*;
import java.awt.event.*;
import java.util.Date;
import javax.swing.*;
public class LabelWithTimer extends JLabel {
private final Timer timer;
public LabelWithTimer() {
timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setText(new Date().toString());
}
});
}
@Override
public void addNotify() {
super.addNotify();
timer.start();
System.out.println("Clock started");
}
@Override
public void removeNotify() {
System.out.println("Clock stopped");
timer.stop();
super.removeNotify();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
final JPanel clock = new JPanel(new GridBagLayout());
clock.add(new LabelWithTimer());
final JTabbedPane tabs = new JTabbedPane();
tabs.addTab("Empty", new JLabel());
tabs.setPreferredSize(new Dimension(400, 300));
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(tabs);
frame.getContentPane().add(new JButton(new AbstractAction("Add/remove clock") {
@Override
public void actionPerformed(ActionEvent e) {
if(tabs.getTabCount() == 2) {
tabs.removeTabAt(1);
}
else {
tabs.addTab("Clock", clock);
tabs.setSelectedIndex(1);
}
}
}), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}