1

下面的类实现了一个chatGUI。当它运行正常时,屏幕如下所示:

精美的ChatGUI http://img21.imageshack.us/img21/7177/rightchat.jpg

当我输入大长度的文本时,问题经常出现。50 - 100 个字符 gui 变得疯狂。聊天记录框缩小,如图所示

图片 http://img99.imageshack.us/img99/6962/errorgui.jpg

关于造成这种情况的任何想法?

谢谢你。

PS:下面的附加类是完整的代码。你可以复制它并在你的电脑上编译,看看我的意思。

注意:一旦 GUI 变得疯狂,如果我点击“清除”按钮,历史窗口就会清除,并且 GUI 会再次正确显示。

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();
        }
    }
}
}
4

2 回答 2

4

首先是很多一般性评论:

a) 发布代码时发布 SSCCE。如果您不知道 SSCCE 是什么,请搜索论坛或网络。我们只有有限的时间来查看代码,300 行太多了。例如:

  • 代码已设置对话框图标与问题无关并且由于我们无权访问您的资源文件而无法运行
  • 执行保存的代码无关紧要,因为这不是您要解决的问题
  • 如前所述,缺少 main() 方法

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) 不要使用 KeyListener 来处理文本窗格中的 Enter 键。Swing 被设计为使用“键绑定”。阅读 Swing 教程中关于同一主题的部分以获取更多信息。

最后,对您的代码的修复很简单:

    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));

通常,您永远不应该设置添加到滚动窗格的组件的首选大小。在这种情况下,当您将文本设置为 null 时,首选大小将重置为 0,并且所有组件的布局似乎都已重做。

于 2010-04-30T02:45:52.363 回答
2

问题可能出在您正在使用的布局管理器上。

GridBagLayout对所有组件都有一个。尝试在他们自己的面板中添加底部组件,而不是将它们与历史文本区域对齐。

就像是:

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

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

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

看看这是否有帮助。 编辑

顺便说一句,它适用于 Mac

在我的机器上工作

Linux

在 Linux 上

和窗户:

替代文字

于 2010-04-30T00:45:18.783 回答