Can't a Swing Component Be Added to Multiple Containers

Can't a Swing component be added to multiple containers?

From: http://download.oracle.com/javase/tutorial/uiswing/components/toplevel.html:

Each GUI component can be contained
only once. If a component is already
in a container and you try to add it
to another container, the component
will be removed from the first
container and then added to the
second.

Sharing Components with multiple containers

If you want to share an Object then you need to create the Object and pass the Object as a parameter to your other classes. Something like:

JPopupMenu popup = createSharedPopupMenu();
Pane.addTab("TabOne", M.new DebugBox(500, 500, popup));
Pane.addTab("TabTwo", M.new DebugBox(500, 500, popup));

Then you need to create generic Actions that will work on any text component. The DefaultEditorKit provides some of these Actions for you:

public JPopupMenu createSharedPopupMenu()
{
JPopupMenu popup = new JPopupMenu()

JMenuItem copy = new JMenuItem( new DefaultEditorKit.CopyAction() );
popup.add( copy );
...

return popup.
}

If the editor kit doesn't provide an Action for you then you need to create your own and you should extend TextAction instead of AbstractAction. The TextAction class has a method that will return the text component that has focus. So you can implement the Action in a generic way.

Also you don't need to use a MouseListener to invoke the popup. You can just use the following JComponent method:

JComponent.setComponentPopupMenu(JPopupMenu popup)

Adding the same components to multiple panels?

However, only the panel I add to the frame last has these buttons. I
am adding the same set of labels/textfields to p2, p3, and p4. But
since I added the labels/textfields to p4 last, it seems to show only
p4 as having it.

If any component c1 of panel1 gets added to another Container panel2, then it first removed from the old Container(panel1) and then gets added to panel2. Refer to the source code of Container class add(component) function.

add(p4, BorderLayout.CENTER);   // <-----HERE, only p4 has visible buttons
// p2 and p3 are just blank if used in here.

Yes, when using layout we can't place two component in the same place. That doesn't make any sense. If p1, p2 and p3 contains same JComponent instances, there is no meaning to use it with multiple panel. However if you are thinking about Group of components with similar(not same) outlet and orientation, we can easily create our own version of component and orient other necessary component inside of it:

class MyPanel extends JPanel
{
JTextFeild tf1;
JLabel label1;
JLabel label2;
JTextFeild tf2;
JLabel label3;

public MyPanel(String lab1Val, String lab2Val, String lab3Val)
{
setLayout(myLayout);
// create the component tf1, label1, label2, etc instances

add(tf1);
add(label2);
add(tf2);
add(label3);
add(tf3);
}

@Override
public Dimension getPreferredSize() {
}
}

Then we can create any number of MyPanel instances to work with suitable layout manager.

Tabbed pane with several time the same panel

As others have mentioned, a Swing JComponent cannot be added to more than one other JComponent (its parent).

If your concern is to share the content of components then you generally have an easy option: since Swing components are based on MVC, they all have a Model which you can share between several JComponents.

For instance, JTextComponent (JTextField and JTextArea are JTextComponents) has a Document as its model, this Document can be shared as in the following snippet:

JTextField field1 = new JTextField();
JTextField field2 = new JTextField();

field2.setDocument(field1.getDocument());

Now if you want to synchronize other properties (e.g. number of columns of JTextField), you'll have to use a PropertyChangeListener as someone else suggested.

Java Card Layout. One component in multiple cards

You are correct that it only appears in the "last card it was added to", but that has nothing to do with CardLayout, that has to do with the fact each component can only be in one parent.

From the Javadoc for java.awt.Container.addImpl(Component comp, Object constraints, int index):

If the component is not an ancestor of this container and has a non-null parent, it is removed from its current parent before it is added to this container.

How to Instantiate Java Class of Swing Components Multiple Times

LuxxMiner is right in his comment.. MoreTabs should extend JPanel
Then you can add multiple instances of MoreTabs if that's what you want to do.

There are a couple of other major issues with your code:

1) In MoreTabs you have lines:

panel.add(lblPutStuffOn);
panel.add(text);

randomly at the top of your class. You can't do this and it will be a compile error. You should have a constructor in the MoreTabs class to initialize your variables.

Constructor:

public MoreTabs(String labelText){
lblPutStuffOn = new JLabel(labelText);
add(lblPutStuffOn);
add(text);
}

2) These two lines don't make sense:

// add new JPanel to TabbedPane via a reusable Class
MoreTabs mt1 = new MoreTabs();

tabbedPane1.addTab( mt1() ); //non-static

It looks like what you are trying to do is instantiate MoreTabs and add as a tab to the tabbed Panel. You cant just call mt1(). You need to prefix it with 'new' like this:

// add new JPanel to TabbedPane via a reusable Class
MoreTabs mt1 = new MoreTabs("Label 1");
MoreTabs mt2 = new MoreTabs("Label 2");
MoreTabs mt3 = new MoreTabs("Label 3");

tabbedPane1.addTab( "More Tabs 1", mt1);
tabbedPane1.addTab( "More Tabs 2", mt2);
tabbedPane1.addTab( "More Tabs 3", mt3);

Note that The constructor I created accepts a String parameter, which is used to set the label in the tab and when calling new MoreTab("Some Label") you will create a new MoreTab instance and pass in the label you want displayed.

Here is your code after modification, which runs and should do basically what you want:

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.border.EmptyBorder;

@SuppressWarnings("serial")
public class TestContainer extends JFrame {

private JPanel contentPane;
public static JTabbedPane tabbedPane1;

/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
TestContainer frame = new TestContainer();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

/**
* Create the frame.
*/
public TestContainer() {

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);

JScrollPane scrollBasePane = new JScrollPane();
scrollBasePane.setBounds(10, 11, 414, 239);
contentPane.add(scrollBasePane);

JPanel panelBase = new JPanel();
scrollBasePane.setViewportView(panelBase);
panelBase.setLayout(null);

tabbedPane1 = new JTabbedPane(JTabbedPane.TOP);
tabbedPane1.setBounds(10, 11, 392, 215);
panelBase.add(tabbedPane1);

// add new JPanel to TabbedPane via a reusable Class
MoreTabs mt1 = new MoreTabs("Label 1");
MoreTabs mt2 = new MoreTabs("Label 2");
MoreTabs mt3 = new MoreTabs("Label 3");

tabbedPane1.addTab( "More Tabs 1", mt1); //non-static
tabbedPane1.addTab( "More Tabs 2", mt2); //non-static
tabbedPane1.addTab( "More Tabs 3", mt3); //non-static
}
}

And

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MoreTabs extends JPanel{

private JLabel lblPutStuffOn;
private JTextField text = new JTextField();

public MoreTabs(String labelText){
lblPutStuffOn = new JLabel(labelText);
add(lblPutStuffOn);
add(text);
}

public String getLblText() {
return lblPutStuffOn.getText();
}

public void setLblText(String s){
lblPutStuffOn.setText(s);
}

public String getTxtText() {
return text.getText();
}

public void setTxtText(String s){
text.setText(s);
}

}

JMenuItem reuse

A JMenuItem belongs to one, and only one, JPopupMenu (or any other menu). You cannot add a Swing component to more than one container; if you do, then the component will automatically be removed from the previous container.
Actaully if you want, you can create Actions. Actions can be shared and added to multiple components (JMenuItems, JButtons etc). You can even enable/disable the Action which will enable/disable all the components at the same time.



Related Topics



Leave a reply



Submit