Java JTextPane JScrollPane显示问题

以下类实现了chatGUI。 当它运行正常时,屏幕看起来像这样:

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

当我输入大长度的文本时,问题经常发生。 50 – 100 chars 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(); } } } } 

首先是很多一般性评论:

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

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

b)使用适当的Java命名约定。 变量名称以小写字符开头。 “JBSave”和“JBClear”不是标准名称,它会使您的代码难以阅读。

c)我也同意Gridbaglayout很复杂,其他布局管理器(比如前面给出的BorderLayout方法)更容易使用。 具体来说,您对gridx和gridy的理解是不正确的。 它们应该用于表示“顺序”的行和列位置。 在你的情况下你应该使用(0,0),(0,1),(1,1),(2,1)。 你将你的网格跳到了10. 10不反映相对大小。 所以你缺少行,1,2,3,4,5,6,7 …是的,它可能有效,但在阅读代码时理解起来很困惑。

d)不要使用KeyListener来处理textpane中的Enter键。 Swing旨在使用“Key Bindings”。 有关详细信息,请阅读相同主题的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,并且所有组件的布局似乎都将重做。

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

你有一个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

在我的机器上工作http://img293.imageshack.us/img293/5785/capturadepantalla201004v.png

Linux的

在linux上http://img72.imageshack.us/img72/7384/capturadepantalla201004uy.png

和窗户:

替代文字http://img97.imageshack.us/img97/7706/capturadepantalla201004hy.png