Hi
I'm developing a GUI component that should provide a single column of components I'll call MessageViews. Each MessageView consists of a JButton displayed above a JTextPane. I'm seeing what seems like inconsistent behavior in the way this component is laid out under different conditions.
Here is the behavior that I want: suppose the component contains two MessageViews, one above the other. The top button is labeled "Hide", and the top text pane is displaying text. The bottom button is labeled "Show" and no text is displayed. If you click the top button, the top text should disappear, and the bottom button and text should slide up to just below the top button.
I have an example (attached) that is about halfway to working. I have pared it down as small as I can (about 100 lines). Obviously the final component will be more polished.
When this is run, you can click the bottom button, and the text is displayed, no problem. Click the bottom button again, and the text is hidden. The button labels change as one would like. Click the top button, and the bottom button slides up to just below the top button, with no text showing anywhere, again as we would like. So far so good.
Now click the bottom button. The bottom text is shown, but the whole thing slides down to make space for the top text, which is not displayed. The bottom button should stay in place just below the top button. There are other, similar inconsistencies if you play with this thing awhile. Why is the action performed on the lower MessageView object affecting how the parent object lays out the top MessageView object? What am I missing, and what can I do to fix it?
Thanks in advance.
--Don
import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
public class MessagePanel extends JPanel
{
public MessagePanel()
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new MessageView("test text 0", true)); // shown
add(new MessageView("test text 1", false)); // hidden
}
private class MessageView extends JPanel implements ActionListener
{
JButton showHideButton; // at top, ctrls display of msgsPane
JTextPane msgsPane; // at bottom
MessageView(String text, boolean doShow)
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(400,200));
showHideButton = new JButton("Show >>"); // set up button
showHideButton.addActionListener(this);
msgsPane = createTextPane(text);
add(showHideButton);
add(msgsPane);
if (doShow) {
doShowState();
} else {
doHideState();
}
}
private void doShowState()
{
showHideButton.setActionCommand("Hide <<");
showHideButton.setText("Hide <<");
msgsPane.setVisible(true);
}
private void doHideState()
{
showHideButton.setActionCommand("Show >>");
showHideButton.setText("Show >>");
msgsPane.setVisible(false);
}
public void actionPerformed(ActionEvent event) {
if (event.getActionCommand().equals("Show >>")) {
doShowState();
} else {
doHideState();
}
}
private JTextPane createTextPane(String text)
{
// create the pane
JTextPane newPane = new JTextPane();
StyledDocument doc = newPane.getStyledDocument();
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
Style regular = doc.addStyle("regular", def);
StyleConstants.setFontFamily(def, "SansSerif");
newPane.setEditable(false);
// add some text
for (int i=0; i<4; i++)
{
try {
doc.insertString(doc.getLength(), i + ". ",
doc.getStyle("bold"));
doc.insertString(doc.getLength(), text+"\n",
doc.getStyle("regular"));
} catch(Exception e) {
System.err.println("Couldn't insert text into text pane.");
}
}
return newPane;
}
}
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("CcffMessagePanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add content to the window.
MessagePanel msgPanel = new MessagePanel();
frame.add(msgPanel);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}