在JPanel中调整JTextPane的大小

3

我正在尝试创建一个即时通讯程序作为一种爱好项目。我一直在尝试设计用户界面,并一直在尝试使实际消息显示的原型工作。

目前,框架设置如下:

  • JFrame内容窗格设置为使用Y_AXIS的JPanel,该JPanel使用BoxLayout。
  • 内容面板包含要显示的TextMessage对象,这些对象单独添加到内容面板中。

TextMessage对象的设置如下:

  • 消息和发送者字符串存储在扩展JTextPane并使用StyledDocument进行格式化的TextMessage对象内部。
  • TextMessage放置在JPanel内,以便在BoxLayout中正确放置对象。 JPanel设置为FlowLayout,根据布尔值将TextMessage对象固定在JPanel的任一边缘。

到目前为止,一切都像我想要的那样工作,只有一个显着的例外。当我调整JFrame大小时,TextMessage对象不会调整大小,而是简单地消失在屏幕边缘。

期望结果:

http://oi57.tinypic.com/nnl3bn.jpg

实际结果:

http://oi62.tinypic.com/2re7dbc.jpg

JFrame类:

public class NewMain extends JFrame {

    public NewMain() {
        setTitle("SparrowIM Chat Bubble");
        setPreferredSize(new Dimension(880, 550));
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setResizable(true);

        JPanel panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        setContentPane(panel);

        add(new TextMessage("Hey, man. What's up?", "Jnk1296", true));
        add(new TextMessage("Eh, nothing much.", "KeepJ96", false));
        add(new TextMessage("Wbu? Anything new going on with you?", "KeepJ96", false));

        add(new TextMessage("Nah, not really. Got a job interview coming up in a few " +
                                    "days, though. Sorta excited for that, but sorta not. " +
                                    "Other than that, life as usual. xD", "Jnk1296", true));

        add(new TextMessage("lol Sounds good.", "KeepJ96", false));
        add(new TextMessage("Yeah. How's the wife and kids, though?", "Jnk1296", true));
        add(new TextMessage("Sarah still griping at you to get the roof patched up?", "Jnk1296", true));
        add(new TextMessage("lol you could say that...", "KeepJ96", false));

        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        new NewMain();
    }
}

TextMessage对象(TextMessageContent的JPanel容器):

public class TextMessage extends JPanel {

    private TextMessageContent content;

    public TextMessage(String sender, String message, boolean localMessage) {
        setBorder(new EmptyBorder(5, 5, 5, 5));

        if (localMessage) {
            setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
        } else {
            setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
        }

        this.content = new TextMessageContent(sender, message, localMessage);
        add(content);
    }

    public TextMessageContent getContent() {
        return this.content;
    }
}

TextMessageContent Class: (JTextPane)

public class TextMessageContent extends JTextPane {

private static final long serialVersionUID = -8296129524381168509L;
    private String sender;
    private String message;
    private boolean isClient;

    private Image background;

    public TextMessageContent(String message, String sender, boolean isClient) {
        // Define Data Points
        this.message = message;
        this.sender = sender;
        this.isClient = isClient;

        this.setEditable(false);
        this.setOpaque(false);
        this.setBorder(new EmptyBorder(7, 7, 7, 7));

        // Fetch Background Image (Hard Location Temporary)
        try {
            if (this.isClient) {
                background = ImageIO.read(
                        new File("/home/jacob/Desktop/orange.png"));
            } else {
                background = ImageIO.read(
                        new File("/home/jacob/Desktop/Green.png"));
            }
        } catch (Exception e) { return; }

        // Create Text Styles
        StyledDocument doc = getStyledDocument();

        // Create Default Base Style
        Style def = StyleContext.getDefaultStyleContext()
                .getStyle(StyleContext.DEFAULT_STYLE);
        Style regular = doc.addStyle("regular", def);

        // Create Body Style
        Style body = doc.addStyle("message", regular);
        StyleConstants.setFontFamily(body, "Verdana");
        StyleConstants.setFontSize(body, 12);

        // Create Sender Style
        Style foot = doc.addStyle("sender", body);
        StyleConstants.setFontSize(foot, 9);

        // Build Document
        try {
            doc.insertString(0, this.message + "\n", body);
            doc.insertString(doc.getLength(), this.sender + " - " +
                    getSystemTime(), foot);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        background = ImageUtil.stretch(background, new Insets(5, 5, 5, 5),
                new Dimension(getWidth(), getHeight()),
                BufferedImage.TYPE_INT_ARGB);

        g.drawImage(background, 0, 0, null);
        super.paintComponent(g);
    }

    private String getSystemTime() {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("h:mm a");
        return sdf.format(cal.getTime());
    }
}

我读到过将JTextPane直接添加到容器中的方法,但是在这种情况下,包装文本消息内容的JPanel仍然是必要的,以避免内容面板的BoxLayout使文本消息填满整个面板。
有什么建议吗?

3
首先,我建议您考虑使用自定义项目渲染器的JList,而不是这种复杂的设计。其次,try {} catch(Exception e){}是基本上很糟糕的做法之一...请更具体地指定您要捕获的异常,并且如果发生异常,请至少打印出堆栈跟踪信息。 - ControlAltDel
请参阅Initial ThreadsTextPanePerfectSize - trashgod
这是由于在TextMessage类中使用FlowLayout导致的。 FlowLayout不尝试约束其子项以适合容器内。 您可以改用BorderLayout或GridBagLayout。 您会发现JTextPane对于长内容的首选大小并不理想,因为它实际上是设计用于放入一个强制JTextPane宽度与视口宽度匹配的JScrollPane中。 - VGR
@ControlAltDel JList的问题在于每个单元格必须是相同的大小(我想)。在像这样的聊天应用程序中,消息可能具有不同的高度。 - VGR
尝试将JTextPanes放置在JScrollPanes中而不是直接添加。 - StanislavL
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Sharcoux
1个回答

0
我已经阅读了直接将JTextPane添加到容器等内容的相关信息,但是在这种设置中,包装文本消息内容的JPanel是必要的,以防止内容面板的BoxLayout使文本消息填充整个面板。
不确定是否有帮助,但BoxLayout尊重添加到其中的组件的最大大小。也许您可以覆盖getMaximumSize()方法来控制宽度。宽度应该是首选宽度或父容器宽度中较小的那个。

可以实现,但我一直尽可能避免在任何地方调用set*Size()。我之前尝试过一种设置,大致类似于这个,结果非常不可靠。 - user288467
我一直在尽可能避免调用set*Size()方法。- 我没有建议调用set???Size()方法。你不应该这样做。如果你想要自定义行为,那么你应该重写get???Size()方法。布局管理器只有在拥有足够信息做出明智决策时才能发挥作用。 - camickr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接