java-jtextarea在转换其父图形后有一个虚假的可视位置

6vl6ewon  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(276)

我想画一幅画布( JPanel )可以有文本框的( JTextArea )在上面,我还可以拖动画布或文本框。现在拖动文本框功能正常。我可以用 setBounds() 设置 JTextArea .
然而,当涉及到拖拽画布时,问题就来了。我用 Graphics2D.transform 移动画布。画布移动后,将出现一个可视文本区域和一个隐藏的真实文本区域。我已经重新设定了 JTextArea 以适应画布的移动偏移,但它不起作用。
下面是一个例子,

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.AffineTransform;

/**
 * @author Zhijie Lan<p>
 * create date: 2020/11/25<p>

**/

public class TranslateJPanel extends JFrame
{
    public TranslateJPanel() throws HeadlessException
    {
        Canvas canvas = new Canvas();
        add(canvas,BorderLayout.CENTER);

        this.setSize(1280, 720);     
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);   
        this.setLocationRelativeTo(null);                               
        this.setVisible(true);
    }

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

class Canvas extends JPanel
{
    private final JTextArea jTextArea;
    private int offset = 0;

    public Canvas()
    {
        setLayout(null);

        jTextArea = new JTextArea("hello!!!!!!!!!!!");

        jTextArea.setBounds(0,0,100,100);
        jTextArea.setBorder(BorderFactory.createLineBorder(Color.BLACK));
        add(jTextArea);

        this.addMouseMotionListener(new MouseMotionAdapter()
        {
            @Override
            public void mouseDragged(MouseEvent e)
            {
                super.mouseDragged(e);
                offset++;
                revalidate();
                repaint();
            }
        });

        this.addMouseListener(new MouseAdapter()
        {
            @Override
            public void mouseClicked(MouseEvent e)
            {
                super.mouseClicked(e);
                System.out.println("M: "+ e.getX()+"  "+e.getY());
            }
        });

    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);

        Graphics2D g2 = (Graphics2D) g;

        AffineTransform at = new AffineTransform();
        at.translate(offset, offset);
        g2.transform(at);

        jTextArea.setBounds(offset,offset,100,100);

        System.out.println(offset);
        System.out.println(jTextArea.getX()+"      "+jTextArea.getY());
        System.out.println("***************************");

    }
}
vsdwdz23

vsdwdz231#

我找到了解决这个问题的办法。
void paintComponent(Graphics g) ,而不是

Graphics2D g2 = (Graphics2D) g;

使用

Graphics2D g2 = (Graphics2D) g.create();

解决问题,但不知道为什么。
我是java新手,所以我不能深刻理解大家的建议中的所有警告,但还是非常感谢!

xriantvc

xriantvc2#

对于可拖动的文本区域,我建议如下:
不要覆盖paintcomponent或任何绘制方法,不要使用仿射变换或任何移动像素的方法。而是移动组件本身。
这可能是我使用空布局的少数几次之一。请注意,有一些布局管理器可以代替它使用(我认为camickr已经为此编写了代码,也许可以给您一个链接)。
永远不要设置jtextarea的大小,甚至是它的首选大小。
而是设置列和行属性。
将jtextarea添加到jscrollpane(实际添加到其视口)
将mouselistener和mousemotionlistener添加到移动它的jscrollpane
将mouselistener和mousemotionlistener添加到jtextarea,该区域将鼠标操作转发到保存它的jscrollpane,但请确保更改mouseevent的source属性以反映jscrollpane,而不是jtextarea。
例如:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class DraggingBoxesPanel extends JPanel {
    public DraggingBoxesPanel() {
        int w = 900;
        int h = 600;
        setPreferredSize(new Dimension(w, h));

        setLayout(null); // I usually avoid doing this
        add(createTextBox()); // add first "box" to this JPanel
    }

    // exposed method to allow adding a new "box" to GUI
    public void newBox() {
        add(createTextBox());
        revalidate(); // The JScrollPane requires this
        repaint();
    }

    private JComponent createTextBox() {
        int rows = 10; // jtextarea property
        int cols = 20; // jtextarea property

        // create text area and scroll pane
        JTextArea textArea = new JTextArea(rows, cols);
        JScrollPane scrollPane = new JScrollPane(textArea);

        // let scrollpane size itself
        scrollPane.setSize(scrollPane.getPreferredSize());

        // scrollpane's mouse listeners
        MyMouse myMouse = new MyMouse();
        scrollPane.addMouseListener(myMouse);
        scrollPane.addMouseMotionListener(myMouse);

        // mouse adapter that forwards mouse actions in
        // text area into its containing scrollpane
        MouseAdapter textAreaMouseAdapter = new MouseAdapter() {
            @Override
            public void mouseReleased(MouseEvent e) {
                // make sure source is correct
                e.setSource(scrollPane);
                myMouse.mouseReleased(e);
            }

            @Override
            public void mousePressed(MouseEvent e) {
                e.setSource(scrollPane);
                myMouse.mousePressed(e);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                e.setSource(scrollPane);
                myMouse.mouseDragged(e);
            }
        };

        textArea.addMouseListener(textAreaMouseAdapter);
        textArea.addMouseMotionListener(textAreaMouseAdapter);

        return scrollPane;
    }

    // code that allows a component to be dragged
    private class MyMouse extends MouseAdapter {
        private Point mousePt1;
        private Point compPt1;

        @Override
        public void mousePressed(MouseEvent e) {
            mousePt1 = e.getLocationOnScreen();
            Component comp = (Component) e.getSource();
            compPt1 = comp.getLocation();

            Container container = comp.getParent();
            container.setComponentZOrder(comp, 0);
            container.revalidate();
            container.repaint();
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            if (mousePt1 == null) {
                return;
            }
            dragComponent(e);
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            dragComponent(e);
            mousePt1 = null;
        }

        private void dragComponent(MouseEvent e) {
            Point mousePt2 = e.getLocationOnScreen();
            int x = compPt1.x + mousePt2.x - mousePt1.x;
            int y = compPt1.y + mousePt2.y - mousePt1.y;
            Component comp = (Component) e.getSource();
            comp.setLocation(x, y);

            Container container = comp.getParent();
            container.revalidate();
            container.repaint();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }

    private static void createAndShowGui() {
        final DraggingBoxesPanel mainPanel = new DraggingBoxesPanel();
        JButton newBoxBtn = new JButton("New Box");
        newBoxBtn.addActionListener(e -> mainPanel.newBox());
        JPanel bottomPanel = new JPanel();
        bottomPanel.add(newBoxBtn);

        JFrame frame = new JFrame("DraggingBoxesPanel");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(mainPanel);
        frame.add(bottomPanel, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

相关问题