Question

The following class implements a chatGUI. When it runs okay the screen looks like this:

Fine ChatGUI http://img21.imageshack.us/img21/7177/rightchat.jpg

The problem is very often when i enter text of large length ie. 50 - 100 chars the gui goes crazy. the chat history box shrinks as shown in this

image http://img99.imageshack.us/img99/6962/errorgui.jpg.

Any ideas regarding what is causing this?

Thank you.

PS: the attached class below is complete code. you can copy it and compile on your computer to see exactly what i mean.

NOTE: once the GUI goes crazy then if i hit the "Clear" button the history window clears and the GUI goes back to being correctly displayed again.

package Sartre.Connect4;

import javax.swing.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.StyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.BadLocationException;
import java.io.BufferedOutputStream;
import javax.swing.text.html.HTMLEditorKit;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.JFileChooser;


/**
 * Chat form class
 * @author iAmjad
 */
public class ChatGUI extends JDialog implements ActionListener {

/**
 * Used to hold chat history data
 */
private JTextPane textPaneHistory = new JTextPane();

/**
 * provides scrolling to chat history pane
 */
private JScrollPane scrollPaneHistory = new JScrollPane(textPaneHistory);

/**
 * used to input local message to chat history
 */
private JTextPane textPaneHome = new JTextPane();

/**
 * Provides scrolling to local chat pane
 */
private JScrollPane scrollPaneHomeText = new JScrollPane(textPaneHome);

/**
 * JLabel acting as a statusbar
 */
private JLabel statusBar = new JLabel("Ready");

/**
 * Button to clear chat history pane
 */
private JButton JBClear = new JButton("Clear");

/**
 * Button to save chat history pane
 */
private JButton JBSave = new JButton("Save");

/**
 * Holds contentPane
 */
private Container containerPane;

/**
 * Layout GridBagLayout manager
 */
private GridBagLayout gridBagLayout = new GridBagLayout();

/**
 * GridBagConstraints
 */
private GridBagConstraints constraints = new GridBagConstraints();

/**
 * Constructor for ChatGUI
 */
public ChatGUI(){

    setTitle("Chat");

    // set up dialog icon
    URL url = getClass().getResource("Resources/SartreIcon.jpg");
    ImageIcon imageIcon = new ImageIcon(url);
    Image image = imageIcon.getImage();
    this.setIconImage(image);

    this.setAlwaysOnTop(true);

    setLocationRelativeTo(this.getParent());
    //////////////// End icon and placement /////////////////////////

    // Get pane and set layout manager
    containerPane = getContentPane();
    containerPane.setLayout(gridBagLayout);
    /////////////////////////////////////////////////////////////

    //////////////// Begin Chat History //////////////////////////////

    textPaneHistory.setToolTipText("Chat History Window");
    textPaneHistory.setEditable(false);
    textPaneHistory.setPreferredSize(new Dimension(350,250));

    scrollPaneHistory.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPaneHistory.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

    // fill Chat History GridBagConstraints
    constraints.gridx = 0;
    constraints.gridy = 0;
    constraints.gridwidth = 10;
    constraints.gridheight = 10;
    constraints.weightx = 100;
    constraints.weighty = 100;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.insets = new Insets(10,10,10,10);
    constraints.ipadx = 0;
    constraints.ipady = 0;

    gridBagLayout.setConstraints(scrollPaneHistory, constraints);

    // add to the pane
    containerPane.add(scrollPaneHistory);

    /////////////////////////////// End Chat History ///////////////////////

    ///////////////////////// Begin Home Chat //////////////////////////////

    textPaneHome.setToolTipText("Home Chat Message Window");
    textPaneHome.setPreferredSize(new Dimension(200,50));

    textPaneHome.addKeyListener(new MyKeyAdapter());

    scrollPaneHomeText.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPaneHomeText.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

    // fill Chat History GridBagConstraints
    constraints.gridx = 0;
    constraints.gridy = 10;
    constraints.gridwidth = 6;
    constraints.gridheight = 1;
    constraints.weightx = 100;
    constraints.weighty = 100;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.insets = new Insets(10,10,10,10);
    constraints.ipadx = 0;
    constraints.ipady = 0;

    gridBagLayout.setConstraints(scrollPaneHomeText, constraints);

    // add to the pane
    containerPane.add(scrollPaneHomeText);

    ////////////////////////// End Home Chat /////////////////////////

    ///////////////////////Begin Clear Chat History ////////////////////////

    JBClear.setToolTipText("Clear Chat History");

    // fill Chat History GridBagConstraints
    constraints.gridx = 6;
    constraints.gridy = 10;
    constraints.gridwidth = 2;
    constraints.gridheight = 1;
    constraints.weightx = 100;
    constraints.weighty = 100;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.insets = new Insets(10,10,10,10);
    constraints.ipadx = 0;
    constraints.ipady = 0;

    gridBagLayout.setConstraints(JBClear, constraints);

    JBClear.addActionListener(this);

    // add to the pane
    containerPane.add(JBClear);

    ///////////////// End Clear Chat History ////////////////////////

    /////////////// Begin Save Chat History //////////////////////////

    JBSave.setToolTipText("Save Chat History");

    constraints.gridx = 8;
    constraints.gridy = 10;
    constraints.gridwidth = 2;
    constraints.gridheight = 1;
    constraints.weightx = 100;
    constraints.weighty = 100;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.insets = new Insets(10,10,10,10);
    constraints.ipadx = 0;
    constraints.ipady = 0;

    gridBagLayout.setConstraints(JBSave, constraints);

    JBSave.addActionListener(this);

    // add to the pane
    containerPane.add(JBSave);

    ///////////////////// End Save Chat History /////////////////////

    /////////////////// Begin Status Bar /////////////////////////////
    constraints.gridx = 0;
    constraints.gridy = 11;
    constraints.gridwidth = 10;
    constraints.gridheight = 1;
    constraints.weightx = 100;
    constraints.weighty = 50;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.CENTER;
    constraints.insets = new Insets(0,10,5,0);
    constraints.ipadx = 0;
    constraints.ipady = 0;

    gridBagLayout.setConstraints(statusBar, constraints);

    // add to the pane
    containerPane.add(statusBar);

    ////////////// End Status Bar ////////////////////////////

    // set resizable to false
    this.setResizable(false);

    // pack the GUI
    pack();
}

/**
 * Deals with necessary menu click events
 * @param event
 */
public void actionPerformed(ActionEvent event) {

    Object source = event.getSource();

    // Process Clear button event
    if (source == JBClear){

        textPaneHistory.setText(null);
        statusBar.setText("Chat History Cleared");
    }

    // Process Save button event
    if (source == JBSave){

        // process only if there is data in history pane
        if (textPaneHistory.getText().length() > 0){

            // process location where to save the chat history file
            JFileChooser chooser = new JFileChooser();

            chooser.setMultiSelectionEnabled(false);

            chooser.setAcceptAllFileFilterUsed(false);

            FileNameExtensionFilter filter = new FileNameExtensionFilter("HTML Documents", "htm", "html");

            chooser.setFileFilter(filter);

            int option = chooser.showSaveDialog(ChatGUI.this);

            if (option == JFileChooser.APPROVE_OPTION) {

                // Set up document to be parsed as HTML
                StyledDocument doc = (StyledDocument)textPaneHistory.getDocument();

                HTMLEditorKit kit = new HTMLEditorKit();

                BufferedOutputStream out;

                try {

                    // add final file name and extension
                    String filePath = chooser.getSelectedFile().getAbsoluteFile() + ".html";

                    out = new BufferedOutputStream(new FileOutputStream(filePath));

                    // write out the HTML document
                    kit.write(out, doc, doc.getStartPosition().getOffset(), doc.getLength());

                } catch (FileNotFoundException e) {

                    JOptionPane.showMessageDialog(ChatGUI.this,
                    "Application will now close. \n A restart may cure the error!\n\n"
                    + e.getMessage(),
                    "Fatal Error",
                    JOptionPane.WARNING_MESSAGE, null);

                    System.exit(2);

                } catch (IOException e){

                    JOptionPane.showMessageDialog(ChatGUI.this,
                    "Application will now close. \n A restart may cure the error!\n\n"
                    + e.getMessage(),
                    "Fatal Error",
                    JOptionPane.WARNING_MESSAGE, null);

                    System.exit(3);

                } catch (BadLocationException e){

                    JOptionPane.showMessageDialog(ChatGUI.this,
                    "Application will now close. \n A restart may cure the error!\n\n"
                    + e.getMessage(),
                    "Fatal Error",
                    JOptionPane.WARNING_MESSAGE, null);

                    System.exit(4);
                }

                statusBar.setText("Chat History Saved");
            }
        }
    }
}

/**
 * Process return key for sending the message
 */
private class MyKeyAdapter extends KeyAdapter {

    @Override
    @SuppressWarnings("static-access")
    public void keyPressed(KeyEvent ke) {

        //DateTime dateTime = new DateTime();
        //String nowdateTime = dateTime.getDateTime();

        int kc = ke.getKeyCode();

        if (kc == ke.VK_ENTER) {

            try {
                // Process only if there is data
                if (textPaneHome.getText().length() > 0){

                    // Add message origin formatting
                    StyledDocument doc = (StyledDocument)textPaneHistory.getDocument();

                    Style style = doc.addStyle("HomeStyle", null);

                    StyleConstants.setBold(style, true);

                    String home = "Home [" + nowdateTime + "]: ";

                    doc.insertString(doc.getLength(), home, style);

                    StyleConstants.setBold(style, false);

                    doc.insertString(doc.getLength(), textPaneHome.getText() + "\n", style);

                    // update caret location
                    textPaneHistory.setCaretPosition(doc.getLength());

                    textPaneHome.setText(null);

                    statusBar.setText("Message Sent");
                }

            } catch (BadLocationException e) {

                JOptionPane.showMessageDialog(ChatGUI.this,
                        "Application will now close. \n A restart may cure the error!\n\n"
                        + e.getMessage(),
                        "Fatal Error",
                        JOptionPane.WARNING_MESSAGE, null);

                System.exit(1);
            }
            ke.consume();
        }
    }
}
}
Was it helpful?

Solution

Lots of general comments first:

a) Post a SSCCE when you post code. If you don't know what a SSCCE is the search the forum or web. We only have limited time to look at code and 300 lines is way too much. For example:

  • the code is set the dialog icon is irrelevant to the problem and does not run since we don't have access to your resource file
  • the code to perform the save is irrelevant since that is not the proble you are trying to solve
  • as mentioned earlier the main() method is missing

b) use proper Java naming conventions. Variable names start with a lower case character. "JBSave" and "JBClear" are not standard names and it makes your code confusing to read.

c) I also agree the the Gridbaglayout is complicated and other layout managers (like the BorderLayout approach given earlier) are easier to use. In specific your understanding of the gridx and gridy is incorrect. They should be used to indicate "sequential" row and column positions. That is in your case you should use (0, 0), (0, 1), (1, 1), (2, 1). You jumped your gridy to 10. The 10 does not reflect a relative size. So you are missing rows, 1, 2, 3, 4, 5, 6, 7... Yes, it may work, but it is confusing to understand when reading the code.

d) Don't use a KeyListener to handle the Enter key in the textpane. Swing was designed to use "Key Bindings". Read the section from the Swing tutorial on the same topic for more information.

Finally the fix to your code is simply:

    textPaneHome.setToolTipText("Home Chat Message Window");
//    textPaneHome.setPreferredSize(new Dimension(200,50));
    textPaneHome.addKeyListener(new MyKeyAdapter());

    scrollPaneHomeText.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
    scrollPaneHomeText.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
    scrollPaneHomeText.setPreferredSize(new Dimension(200,50));

In general, you should never set the preferred size of a component added to a scrollpane. In this case when you set the text to null the preferred size gets reset to 0 and the layout of all the components appears to be redone.

OTHER TIPS

The problem might be the layout manager you're using.

You have a GridBagLayout for all the components. Try adding the bottom component in their own panel instead of align them with the history text area.

Something like:

JScrollPane history = new JScrollPane( new JTextPane() );

JPanel inputClearSavePane = new JPanel();
// layout the input, clear save button

getContentPane().add( history );
getContentPane().add( inputClearSavePane, BorderLayout.SOUTH );

And see if that helps. edit

BTW, it works on Mac

works on my machine

Linux

on linux

And windows:

alt text

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top