Java JTextPane JScrollPane 显示问题

2023-12-12

下面的类实现了一个 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();
        }
    }
}
}

首先有很多一般性评论:

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 来处理文本窗格中的 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,并且所有组件的布局似乎都已重做。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java JTextPane JScrollPane 显示问题 的相关文章

随机推荐

  • 如何从 java servlet 中的 POST 数据中分离出查询字符串参数

    当您在 servlet 中收到 doGet 或 doPost 调用时 您可以使用getparameterxxx 在一个简单的地方获取查询字符串或发布数据 如果调用是 GET 您可以从 url 查询字符串获取数据 如果调用是 POST 您将获
  • CPU 如何从 RAM 访问应用程序和数据

    在应用程序加载到 RAM 并打开文件后 因此文件的数据也存储在 RAM 中 我在理解 CPU 如何从 RAM 访问应用程序和数据时遇到了一些困难 根据我的理解 CPU 只是在程序计数器滴答时从 RAM 获取指令或在中断后执行任务 那么它如何
  • 在 protobuf 消息中存储单个字节

    我使用什么数据类型在协议缓冲区消息中存储单个字节 查看列表位于https developers google com protocol buffers docs proto scalar似乎 int32 类型之一是最合适的 有没有更有效的方
  • 使用比较运算符比较 time_t 值

    我有2个time t值 我想找出哪一个更大 time t是内部的 int64在我的平台上 我可以用吗 lt gt and 运算符来比较值 我不想知道两个时间值之间的差异 代码只会在 Windows 上运行 所以我不关心可移植性 以这种方式比
  • 如何使用Python脚本控制LabView VI前面板开关(开/关、条调节器)?

    我有一个LabView前面板控制硬件的开关和传感器电压调节器 需要使用 Python 脚本来控制它们 我对此了解不多LabView 请解释如何做到这一点 我在 LabVIEW 讨论板上找到了一份参考资料 该参考资料成功地this 它使用以下
  • 如何在 C++ 中将窗口的屏幕截图作为位图对象获取?

    如何在 C 中将窗口的屏幕截图作为位图对象获取 假设我已经有了窗口句柄 我还想知道是否可以在最小化状态下获取窗口的屏幕截图 这里的 C 是指 VC 以及与 Windows XP win32 相关的所有库 你应该调用 PrintWindow
  • RubyMine 代码自动完成

    我即将习惯在 Android Studio 中使用 Java 最棒的是一切都被强烈声明 因此 当我输入 MyClass someme 时 IDE 会为我提供高级代码自动完成功能 发展是迅速而令人愉快的 但后来我想学习 RubyOnRails
  • 如何在 Bash 中读取文件或标准输入

    以下 Perl 脚本 my pl 可以从命令行参数中的文件或从标准输入 标准输入 while lt gt print perl my pl将从标准输入读取 而perl my pl a txt将从中读取a txt 这非常方便 Bash 中有类
  • 如何将 2 个 Excel 文件合并为一个具有不同工作表的 Excel 文件?

    我有 2 个 Excel 文件 我想将它们合并为 1 个具有单独工作表的文件 我尝试与 Microsoft Office Interop Excel 进行合并 但我不明白如何使用它 对于叶海亚 这里是获取范围的方法 我想将它们与不同的文件合
  • 如何为 cout 编写一个允许表达语法的函数包装器?

    我想包起来std cout用于格式化 如下所示 mycout what type x optional args do some formatting on x first std cout lt lt x 并且仍然能够使用表达语法 例如
  • 样式和主题的背景问题

    在 attrs 我有
  • 强制方向为纵向模式

    我的所有应用程序都处于纵向模式 但我有一个横向模式的视图控制器作为图像库 在 项目摘要 选项卡上启用 LandscapeLeft 模式 因此我必须在视图控制器的其余部分中以这种方式禁用旋转 但图像库的 VC 中除外 我想保持旋转为纵向模式
  • 我可以仅使用 twiml bin 将短信转发到电子邮件吗?

    非常清楚如何使用 twilio 将 SMS 转发到电子邮件地址 他们有一个使用托管在第三方服务器上的 php 代码执行此操作的很好的示例 但是 我想仅使用 twiml 应用程序将短信转发到电子邮件地址 而不使用其他第三方请求 代码 我尝试使
  • Spring boot Tomcat – 启用/禁用目录列表

    I have spring boot应用程序和我正在使用embedded tomcat作为网络服务器 我在列出目录时遇到问题 我现在就想怎样才能enable or disable listing directories在嵌入式tomcat中
  • 更改 JPanel Graphics g 颜色绘制线

    我有一个类似于绘画的程序 而且我正在尝试实现更改笔颜色 但是当我更改颜色时 当前绘制的所有内容都会更改为红色 例如在我的程序中 我怎样才能使其不会将当前绘制的所有内容重新绘制为当前颜色改变颜色 下面的代码将编译并运行 JPanel 绘图区域
  • 在 spring 中加载属性文件

    我们的一个团队已经以这种方式实现了加载属性 请参见下面的伪代码 并建议这种方法是正确的 因为使用这种方法的客户端应用程序可以自由地将属性保留在任何文件中 与广泛使用的 propertyplaceholderconfigurer 相反 应用程
  • 将数组转换为 JSON

    我有一个数组var cars 2 3 其中包含一些整数 我已经向数组添加了一些值 但现在需要通过 jQuery 将此数组发送到页面 get方法 如何将其转换为 JSON 对象进行发送 向后兼容的脚本 https github com dou
  • 解析性能(If、TryParse、Try-Catch)

    我了解很多处理解析文本以获取信息的不同方法 例如 对于解析整数 可以预期什么样的性能 我想知道是否有人知道这方面的任何好的统计数据 我正在从测试过这个的人那里寻找一些真实的数字 其中哪一个在哪些情况下提供最佳性能 Parse Crash i
  • 是否有任何浏览器(Chrome、Firefox)插件​​可以模拟地理位置?

    我需要测试广泛使用地理定位 api getCurrentPosition watchPosition 的 Web 应用程序 是否有任何浏览器 Chrome Firefox 插件 可以模拟地理位置 我来晚了一点 但是微软边缘有这个有用的选项卡
  • Java JTextPane JScrollPane 显示问题

    下面的类实现了一个 chatGUI 当它运行正常时 屏幕如下所示 精美 ChatGUI http img21 imageshack us img21 7177 rightchat jpg 当我输入大长度的文本时 问题经常出现 50 100