2

I have a frame with a var , I added that var to a JPanel, and if I want to add the same var to another JPanel, it`s disappearing from the first JPanel. I want a logical explanation for my problem please, thank you ! I want to store my JLabel in both of my jpanels.

public class Gui {
    JPanel panel1, panel2;
    JLabel text = new JLabel("some text");
    JFrame frame = new JFrame();

    public Gui {
        panel1 = new JPanel();
        panel1.setLayout(null);
        panel1.add(text);
        panel1.getComponent(0).setBounds(50,50,50,50);
        panel1.setBorder(BorderFactory.createLineBorder(Color.black));
        panel1.setBounds(x,y,w,h);
        // it`s working, the labels it`s visible

        panel2 = new JPanel();
        panel2.setLayout(null);
        panel2.add(text);
        panel2.getComponent(0).setBounds(100,100,50,50);
        panel2.setBorder(BorderFactory.createLineBorder(Color.black));
        panel2.setBounds(x,y,w,h);
        //it`s not working, the label ins`t visible ...

        frame.add(panel1);
        frame.add(panel2);
    }
}
que1326
  • 2,227
  • 4
  • 41
  • 58
  • Every `Swing` component can only have one parent. By adding the label to the second panel, you effectively removed it from the first (this is done in the add method of the panel on your behalf), which has already been mentioned in some of the answers below. The only choice you have is to produce a new label for each panel, and there are literally dozens of ways you could approach this problem. Without more information, it is going to be difficult for us to provide you with a more detailed approach – MadProgrammer Jul 23 '12 at 21:05
  • I press a button and it`s showing me panel1 , and if I press another button it`s showing me panel2, but empty , because my vars (jlabels/imageicons, textfields an jbuttons ) were added to the first panel (panel1), I think it will be a good ideea to make a function, and call 1 panel at a time right ? – que1326 Jul 23 '12 at 21:06
  • +1 for a clear example of confounding the _view_, `JLabel`, and _model_, `String`; separate them, as shown [here](http://stackoverflow.com/a/11620650/230513), and the problem vanishes. – trashgod Jul 23 '12 at 23:47

3 Answers3

3

Disclaimer: I am editing my answer in response to comments from the OP. However, I am still not entirely sure about some of the details of the question. I will gladly edit my answer as more clarifications are given.

Answer: One possible solution is to create subclasses of the Swing components you are using. For example,

public class MyPanel extends JPanel {
  private JLabel label = new JLabel("some text");

  public MyPanel() {
    this.add(label);
  }
}

Now you can create multiple instances of MyPanel which each have its own JLabel. Then you can add these panels to your frame.

Added: With the additional information given in the comments, I would go a step further and create a custom JFrame class:

public class MyFrame extends JFrame {
  private MyPanel panel = new MyPanel();

  public MyFrame() {
    this.add(panel);
  }
}

Now you can create several instances of MyFrame. If you want to go even further, you can add parameters to the constructors of both of these custom classes to set the JLabel text to different values in each instance MyFrame. I will leave the details as an exercise to the reader. (Of course, please ask if you get stuck, though.)

Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • it`s more complicated then that Code-Guru, I don`t have simple text JLabels in my program, I can`t double my vars with this method – que1326 Jul 23 '12 at 20:51
  • @Vlad Your example only has a JLabel with a text. Can you please explain some of the additional complications from your actual program? – Code-Apprentice Jul 23 '12 at 20:54
  • I press a button and it`s showing me panel1 , and if I press another button it`s showing me panel2, but empty , because my vars (jlabels/imageicons, textfields an jbuttons ) were added to the first panel (panel1), I think it will be a good ideea to make a function, and call 1 panel at a time right ? – que1326 Jul 23 '12 at 21:03
  • @Vlad I have completely changed my answer. Please see if my suggestions help further. – Code-Apprentice Jul 23 '12 at 21:05
  • and now, for all of MyPanels I have inside of them JLabels, this is a very good ideea – que1326 Jul 23 '12 at 21:13
3

Just as it's discussed with in other posts. All Swing UI components (ie JLabel included) can only have one parent (ie JPanel). If you add it to another panel it will remove itself from the prior parent. There are very good reasons for this behavior. For example, JPanel 1 might not use the same Layout as JPanel 2 and hence the label would have to support two different placements within each JPanel. The whole point of using Objects as components is to provide encapsulation of data like (font, position within the parent, width, height, etc) inside that object. If you want two visual elements just create another element. Now that creates a problem "How do you synchronize the data across all of these controls?" That's basically scratching how do you build a proper Swing architecture for your program?

What you don't want to do is use the Swing component model (ie. Jabel, JTextField, etc) as your data model. And after reading your question and code I believe that's what you are doing. You may not realize it. UI Components should be used for display only. They reflect what is in the data model. So you'll want to create a model that doesn't involve Swing. It should model your problem regardless of how its displayed. That means you shouldn't assume it will always be Swing or web, etc.

There are very practical reasons for this. Say in a year you want to redesign your UI. If you combined the view components and data model together you pretty much have to start completely over. Even if you aren't switching technologies. Say you are switching from a JList to a JTable or a JTreeTable. Just simple changes of the types of components you have on the screen can be an absolute nightmare if you don't segment your view from the model. Plus the View displays thing, but the model might need information that isn't displayed to the user but is tied to what is being displayed. For example, the ID of the row in the database. If you stuff the view and data model together you have to play little hacks to store this invisible information in weird ways. Things that make it hard for other people to understand.

If you don't know what I mean you either will in 6 months when you have to make your first major redesign or you'll save yourself some pain now and try and understand what I mean now. Just simple POJOs will suffice. Then share those POJOs with your Swing components. For example:

MySpecialPanel panel1 = new MySpecialPanel();
MyOtherSPecialPanel panel2 = new MyOtherSpecialPanel();
frame.add( panel1 );
frame.add( panel2 );

...a little while later...

MySpecialPOJO specialPOJO = ...some call to a service...;
panel1.setSpecialPOJO( specialPOJO );
panel2.setSpecialPOJO( specialPOJO );

Notice that I created two subclasses of JPanel called MySpecialPanel and MyOtherSpecialPanel. Inside there they create the components contained within them. Then then expose a setter method taking a data model object of type MySpecialPOJO. Inside those methods we might see something like the following:

public void setSpecialPOJO( MySpecialPOJO specialPOJO ) {
   this.model = specialPOJO;
   textField1.setText( specialPOJO.getName() );
   textField2.setText( specialPOJO.getDescription() );
   radioButtonGroup.setSelected( specialPOJO.getGender() );
   ....
}

Now you have a way to take a model object, and update the relative UI components that make up that view. Notice it doesn't care about any other external dependencies (ie where it got the object from). It just updates the controls it owns to reflect what's carried by the POJO. Now if you follow these simple rules it makes instantiating your special panels easy. Whether you need only one instance or many instances. Also if you need to move panels within your program it's pretty easy to do that if you reduce your dependencies to just your POJOs. There's a lot more to this, but for now this will get you started. You still have to figure out how to get data out of the UI and back into your POJOs (events!). Controllers, Services, etc.

This might help you as well:

Up-to-date Swing MVC example + Question

Community
  • 1
  • 1
chubbsondubs
  • 37,646
  • 24
  • 106
  • 138
2

You can't. As you noticed, a control can only be attached to one window at a time, and if you try to attach it to another one, it will remove itself from the first.

Suggestions:

panel2.add(text.clone()); // clone the existing label
panel2.add(new JLabel("some text")); // make a new label from scratch
Wug
  • 12,956
  • 4
  • 34
  • 54
  • so...the only way I could do this, is to make a function add my vars there and add the frames 1 at the time?! – que1326 Jul 23 '12 at 20:46
  • just recreate the jlabel instead of trying to use the same one. `panel2.add(text.clone());` Should work unless jlabels don't support clone, in which case just make a new one manually. Is there some reason you need to store a reference to the label? Might it be more concise to simply `panel2.add(new JLabel("some text"));` ? – Wug Jul 23 '12 at 20:49
  • You could use Factory approach to generate labels faster (this is a little over kill, but can save lots of typing if you want to generate labels in a special way, change the font, color etc)... `panel2.add(createLabel("Some text"))` – MadProgrammer Jul 23 '12 at 20:51
  • @Wug I`ve put there a simple example with a JLabel, to understand, I have lots of JTextFields, JLabels and JButtons – que1326 Jul 23 '12 at 20:54
  • Can you clone the entire panel? will that duplicate all of the controls? worth a shot. – Wug Jul 23 '12 at 20:55