如何在JTextPane中嵌入可调整大小的JPanel?

时间:2014-11-23 18:18:32

标签: java image swing jpanel jtextpane

有许多相反的问题,将JTextPane插入到JPanel中。这不是我的问题。我需要能够将自定义JPanel(带有拖放,拖动和鼠标单击侦听器)插入到JTextPane中,然后将其放入JScrollPane,最后放入JFrame进行显示。原因是因为我需要通过在聊天客户端中拖动它来获得支持调整大小的图像,聊天客户端本身主要是文本。

方便的是,JTextPane中有一个相关的方法:insertComponent(Component c),但每当我使用它时,我的组件最终被压缩到一行文本空间(即使它们报告的大小更大) )。这对于普通按钮来说是完美的,但如果我需要更大的东西,我就不走运了。我可以使用ImageIcons自行插入图像,但是包含在JPanel中的图像根本不起作用(加上我不能向ImageIcons添加任何监听器,因为它们不是GUI元素;覆盖一个不是选项)。

每当用户将图像拖入聊天客户端时,这段代码就会插入自定义JPanel:

private void sendImage(BufferedImage im, int cl) throws IOException {
    if(output == null) return;

    //Send the image itself over to your friend
    byte[] toSend = toBytes(im, cl);
    sendString(nickname.hashCode() + "image"); //Header for image
    output.writeInt(toSend.length); //Tells how many bytes to read.
    output.write(toSend);

    //Let the user know that the image was sent
    float linmb = (float)(toSend.length / 1048576.0); //Size of file sent
    addText("\n" + nickname + " sent an image! (" + linmb + " MB)\n", Color.RED.darker());

    //Show the image itself
    DraggerPanel d = new DraggerPanel(im, true);
    text.insertComponent(d);
    d.repaint();

    //Spacer
    addText("\n");
}

这是DraggerPanel的源代码,DraggerPanel是一个包含图像的自定义JPanel:

public class DraggerPanel extends JPanel {
private BufferedImage image; //The image we're drawing
private Point startingPoint = null; //Starting point for resizing
private boolean first = true; //Is this the first drag?
private boolean lockedDrag; //If true, then lock x and y to be proportionally dragged.

public DraggerPanel(BufferedImage image, boolean lockedDrag) {
    super();
    this.image = image;
    this.lockedDrag = lockedDrag;

    //The listener for dragging events.
    addMouseMotionListener(new MouseMotionListener() {
            private int inWidth = 0, inHeight = 0; //Initial height and width values
            private double ratio = 0; //Ratio of height to width for locked drag.

            public void mouseDragged(MouseEvent m) {
                if (first) { //If we're first, record initial position.
                    startingPoint = m.getPoint();
                    first = false;
                    inWidth = getWidth();
                    inHeight = getHeight();
                    ratio = (double)inHeight / inWidth;
                } else { //Otherwise, change the size of the window.
                    if (!lockedDrag) {
                        int w = (int)startingPoint.getX() - m.getX();
                        int h = (int)startingPoint.getY() - m.getY();
                        setSize(Math.abs(inWidth - w), Math.abs(inHeight - h));
                    } else {
                        int w = (int)startingPoint.getX() - m.getX();
                        int h = (int)((double)ratio * w);
                        setSize(Math.abs(inWidth - w), Math.abs(inHeight - h));
                    }
                }
                repaint();
            }

            public void mouseMoved(MouseEvent m){
            }
        });

    //Lets us know when you're not dragging anymore.
    addMouseListener(new MouseAdapter(){public void mouseReleased(MouseEvent m){first = true;}});

    //Set appropriate size.
    if(image != null) setSize(image.getWidth(), image.getHeight());
    else setSize(200,200);

    //We're live, baby.
    setVisible(true);
}

public void paint(Graphics g) {
    if (image == null) super.paint(g);
    else g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
}

更新1:我遵循@camickr的建议,并更新了DraggerPanel以使用setPreferredSize而不是setSize,以及覆盖paintComponent()而不是paint()。现在,图像具有适当的高度,但是被拉伸到JTextPane的宽度(这看起来像以前一样)。此外,调整大小似乎并不重要 - 图像根本不会改变其大小。鼠标事件肯定会通过,但不影响大小。似乎原始问题没有完全解决,因为JPanel的大小不是我需要的,并且解决方案也将导致解决调整大小问题。

更新2:我做到了!我终于做到了。对于有这个问题的未来时间旅行者,我基本上不仅在我的重写JPanel中使用setSize()而且还在setPreferredSize()和setMaximumSize()中使用了JTextPane。首选的一个适用于高度,最大值设置宽度(天知道为什么)。谢谢你的提示,@ camickr!

1 个答案:

答案 0 :(得分:0)

  

我的组件最终会被压缩到一行文本空间(即使它们报告的大小更大)。

我猜大小并不重要。

我认为您需要覆盖DraggerPanel的getPreferredSize()方法以返回面板的首选大小,以便文本窗格可以显示面板。

此外,自定义绘制是通过覆盖paintComponent(...)方法而不是paint()方法完成的。