I have extended the JPanel class with some additional functionality I require, and I then created an instance of it like so:
CustomPanel pan = new CustomPanel();
I then add it to my to my frame:
frame.getContentPane().add(pan);
I then need to the panel back off the frame, I do this like so:
for (Component c : frame.getComponents())
{
if(c instanceof CustomPanel)
{
System.out.println("Should get here");
}
}
But it doesn't exist in memory as a CustomPanel, instead it exists as a JPanel, why is this?
From what I understand, the JFrame contains a JPanel, when you add your custom Panel to the JFrame using getContentPane().add(pan), you're actually adding your custom panel to the JFrame's JPanel. I'm guessing you'll have to call frame.getContentPane().getComponents(); to iterate over the components contained in the JFrame's panel.
Your for should read:
for (Component c : frame.getContentPane().getComponents())
You didn't add your Panel to the frame, you added it to the content pane.
Related
I am almost certain this question was asked before here: Java Swing: How to change GUI dynamically , but I seem to just have some fundamental misunderstanding in how it works.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class JTest extends JFrame
{
public static void main(String[] args)
{
JTest t = new JTest();
}
Container pane;
public JTest()
{
setSize(500,500);
setTitle("JTest");
setDefaultCloseOperation(EXIT_ON_CLOSE);
pane = getContentPane();
pane.setLayout(new GridLayout(1,2));
JButton old = new JButton("old");
old.addActionListener(new OldButton());
pane.add(old);
JScrollPane scroll = new JScrollPane(new JTextArea(50,20));
pane.add(scroll);
setVisible(true);
}
private class OldButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
pane.setLayout(new GridLayout(1,2));
JButton old = new JButton("new");
old.addActionListener(new NewButton());
pane.add(old);
JScrollPane scroll = new JScrollPane(new JTextArea(50,20));
pane.add(scroll);
pane.validate();
}
}
private class NewButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
pane.setLayout(new GridLayout(1,2));
JButton old = new JButton("old");
old.addActionListener(new OldButton());
pane.add(old);
JScrollPane scroll = new JScrollPane(new JTextArea(50,20));
pane.add(scroll);
pane.validate();
}
}
}
This code should replace the preexisting layout with a new one anytime the button in the corner is pressed, but instead, it just adds the new layout to the frame. Can someone tell me what I'm doing wrong?
EDIT:
Adding some information. A picture for reference:
I'm making a set of components like this inside the scroll pane. whenever I press the "Make new field" button, I want it to add a "field" (the name of the field followed by a textarea or some such) to the set in that scrollpane. This means changing the layout of the area inside the scrollpane to include the new field.
OK -- so it looks like what you want to do (and please correct me if I'm wrong) is to add a new component to a JPanel that is displayed within a JScrollPane. If so, then you do not want to change or swap layouts, and you certainly don't want to keep adding new JScrollPanes. Instead consider doing:
Create one JScrollPane and add to your GUI. Don't re-add this as you'll only need one.
add a JPanel to the JScrollPane's viewport that uses a layout that allows multiple components to be easily added to it. Perhaps a GridLayout or a BoxLayout, depending on what you need.
Also consider not adding the above JPanel directly to the viewport but rather adding it to another JPanel, one that uses BorderLayout, adding the first JPanel to the BorderLayout-using JPanel's BorderLayout.PAGE_START position, and then add this to the JScrollPane's viewport. This way the first JPanel won't stretch to fill the viewport initially.
Then in your button's ActionListener, add your components to the first JPanel by calling .add(...) on it, and then call revalidate() and repaint() on that first JPanel to layout the newly added components and repaint the JPanel and its contents.
Ok, so it turns out this wasn't a layout problem at all. I had failed to realize that setting a new layout doesn't cause the previous layout's components to disappear, you have to remove them before adding the new components. That's why I was getting duplication.
Thanks for pointing me in the right direction, though.
Hi I have a JPanel which has many JPanel inside. When the user changed data in the inside panel. I need to refresh the outerpanel; I removed all insider panel and add the new inside panel. My problem is that there are no inside panel showing after refresh. If I make the JFrame minimize and then maximize, it shows the refresh panel. Would someone tell me how to solve this problem. Thanks in advance.
There is my code to remove and add the new JPanel
private void getListCommentPane(){
//sortPage
Component[] components = jpListCommentPane.getComponents();
for (Component component : components) {
jpListCommentPane.remove(component);
jpListCommentPane.validate();
}
ArrayList<CommentItem>sortComment= lstComment;
Collections.sort(sortComment,CommentItem.sortPage);
for(CommentItem comm: sortComment){
//The class DivCommentJPane extends JPanel
DivCommentJPane d=new DivCommentJPane(comm, this);
jpListCommentPane.add(d);
}
jpListCommentPane.repaint();
}
After removing and adding your components to jpListCommentPane, try calling jpListCommentPane.revalidate() instead of jpListCommentPane.repaint(), do this last, do it once. There should be no need to call jpListCommentPane.validate(); and especially from within a loop
revalidate will instruct the container that it needs to perform a layout and update its contact hierarchy
I created a class that extends JComponent. An object of that class is added to a JPanel. A JPanel has a default flow layout manager. When I added the JPanel to a JFrame, nothing was visible except an empty JFrame. Yes, the frame is visible and sized to the maximum screen dimensions.
I tried several modifications to change this problem and deduced:
Component size - set it to no avail and still an empty JFrame
Intermediate panel - adding component to an intermediate panel and still an empty JFrame
Finally I decided to change the layout manager of the panel I was adding my component to and changed the panel layout manager to a border layout. I then added the component to the center and now it appears.
Follow-on questions I have are:
When making a custom JComponent, what are my considerations?
Why do I have to change the layout manager of a panel for a custom JComponent?
My naivety asks "If I can add a JButton to a panel and, using the default flow layout manager it shows, why not a custom JComponent?
My custom JComponent is an inner class:
public class OuterClass
{
private class Panel extends JPanel
{
public Panel()
{
add(new Custom());
}
}
private class Custom extends JComponent
{
public Custom()
{
// Initialization of members but not size of component
}
}
}
A JPanel has a default flow layout manager.
Yes, and the FlowLayout respects the preferred size of every component. Your component doesn't have a preferred size so it defaults to (0, 0).
Override the getPreferredSize() method to return the appropriate dimension.
"Why do I have to change the layout manager of a panel for a custom JComponent?"
The thing about JComponent is that it has no default LayoutManager to layout the components. If you run this test, you'll see
public static void main(String[] args) {
JComponent component = new JComponent() {};
System.out.println("JComponent = " + component.getLayout());
JPanel panel = new JPanel();
System.out.println("JPanel = " + panel.getLayout());
}
The result is
JComponent = null
JPanel = java.awt.FlowLayout[hgap=5,vgap=5,align=center]
So with JComponent, since it has a null layout, it doesn't know where to layout the the component. So you either have to
Explicity setBounds() on the component you want to add, or
Explicity set the layout, like you mentioned you had to do for the JComponent.
"Finally I decided to change the layout manager of the panel I was adding my component to and changed the panel layout manager to a border layout. I then added the component to the center and now it appears."
So by setting the LayoutManager to BorderLayout, you told the JComponent how to layout the components you add. It can be any LayoutManager though, not just BorderLayout
I'm trying to close a frame yet open a new frame.
My application has page A, a JPanel with some controls and a specific button, and when the user clicks the button, I want page A to disappear and page B to appear (page B has controls that depend on the choices that are made by the user on page A).
This has been asked before, but there was no satisfactory answer. Inside the ActionListener implementation, namely public void ActionPerformed(ActionEvent e) from my jpanelForPageA class, I can comfortably write this.setVisible(false), but how can I set page B to a visible state?
You can do the removal of panel a and then the addition of panel b trick. Another is to use a CardLayout.
When you create your panels, you add them to a containing JPanel that you initialize with a CardLayout:
JPanel container = new JPanel(new CardLayout());
containter.add(getPanelA(), "PANEL_A");
containter.add(getPanelB(), "PANEL_B");
Then, in your actionPerformed, when you want to show panelB, you do this:
CardLayout cl = (CardLayout) container.getLayout();
cl.show("PANEL_B");
Take a look at this tutorial for some more ideas.
For some reason, I can never to get setVisible() to work for me to do what you're describing. Instead, I do this:
frame.remove(panelA);
frame.add(panelB);
"frame" is just the JFrame you want to put the panels in. Try this if the setVisible() method doesn't work :)
To your original question, all you have to do is (like aioobe said):
panelB.setVisible(true);
((btw, posting some of your code would help me figure out what you're trying to ask))
And this is just a guess as to what you're trying to do -- I'm guessing your JPanels are in different classes. Then, you'll need to do this:
class pages extends JFrame implements ActionListener
{
public pages()
{
panelA a = new panelA(this)
}
changeToA(panelB b)
{
remove(panelB);
add(new panelA(this));
}
changeToB(panelA a)
{
remove(panelA);
add(new panelB(this));
}
}
class panelA extends JPanel implements ActionListener
{
pages p;
public panelA(pages p)
{
this.p = p
}
// all that actionlistener code stuff
p.changeToB(this);
}
class panelB extends JPanel implements ActionListener
{
pages p;
public panelB(pages p)
{
this.p = p
}
// all that actionlistener code stuff
p.changeToA(this);
}
You pass the pages class to the panels so the panels can tell the pages class to remove themselves.
((I don't know if there is an easier way, but this is what I do all the time))
I hope I helped :)
You have to remove Panel A from the frame, add Panel B to the frame, and call invalidate on the frame (or containing panel). At least in Swing, I'm not sure about AWT, there you might need repaint or revalidate instead of invalidate.
You could also just create a whole new JFrame and dispose the one containing panel A.
I am implementing a Comment box facility in my application which user can resize using mouse. This comment box contains a scrollpane which instead contains a JEditorPane in which user can insert comment. I have added the editor pane inside a scroll pane for the following reason:
auto scolling of jeditorpane
When the user resizes the comment box, I am setting the desired size for JScrollPane and the JEditorPane. When the user is increasing the size of the comment box, the size of these components are increasing as desired but when the size of the comment box is decreased, the size of the JEditorPane does not decrease even after setting the size. This leads to the scrollbars inside the scrollpane.
I tried using setPreferrredSize, setSize, setMaximumSize for JEditorPane. Still the size of the editor pane is not reducing. I tried calling revalidate() or updateUI() after the setting of size but no use.
I am using Java 1.4.2.
Please provide me some insight....
I realise this is long since answered, but for future reference all you need to do is override the getScrollableTracksViewportWidth() to always return true, eg.
JEditorPane pane = new JEditorPane() {
public boolean getScrollableTracksViewportWidth() {
return true;
}
};
panel.add(new JScrollPane(pane));
Actually it is possible, luiscubal. Here is how,
To the JScrollPane add a ComponentListener for resize events
public static void main(String...args) {
//our test frame
JFrame frame = new JFrame("JEditorPane inside JScrollPane resizing");
frame.setLayout(new BorderLayout());
//our editing pane
final JEditorPane editor = new JEditorPane();
//our simple scroll pane
final JScrollPane scroller = new JScrollPane(editor);
//NOTE: this is the magic that is kind of a workaround
// you can also implement your own type of JScrollPane
// using the JScrollBar and a JViewport which is the
// preferred method of doing something like this the
// other option is to create a JEditorPane subclass that
// implements the Scrollable interface.
scroller.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
editor.setSize(new Dimension(
scroller.getWidth()-20,
scroller.getHeight()-20));
}
});
//just use up the entire frame area.
frame.add(scroller, BorderLayout.CENTER);
//quick and dirty close event handler
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(320, 240); //something not too big
frame.setLocationRelativeTo(null); //centers window on screen
frame.setVisible(true); // normally done in a SwingUtilities.invokeLater
}
Look luiscubal it is possible. Don't be so quick to announce things in Java as not possible. The swing api is quiet flexible and can do a lot of the work for you. However, if you use JComponents in ways they weren't made to be used you will end up with problems and have two options.
subclass subclass subclass basically create your own component.
find a work around, like the above solution.
Decreasing the size of a JEditorPane in a JScrollPane and then reducing it, is not possible.
You may want to use a JTextArea instead.