3

我正在尝试做一个简单的作业,在其中显示一行文本,显示门对象是否打开。在此之下,我直观地表示它(使用 drawRect)方法。在底部我有两个按钮,可以打开或关闭门,从而改变文本和矩形。

编辑:现在可以编译的代码列表:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;

    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;

    public class Test {

    public static void main(String[] args) {

        // Creates new JFrame called frame, with title "Door" 
        // (displayed at top of screen).
        JFrame frame = new JFrame ("Door");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        TempDoorPanel panel = new TempDoorPanel();
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);

        }
    }

    class Door {

    private String state;
    private String message;

    Door (String state) {
        this.state = state;
        message = "The door is currently closed.";
    }

    public boolean isOpen() {
        return state.equals ("open");
    }

    public boolean isClosed() {
        return state.equals ("closed");
    }

    public void setState(String state) {
        this.state = state;
    }

    public String getMessage() {
        return message; 
    }

    public void open() {
        if (state.equals("open")) {
            message = "The door is already open.";
        }
        else {
            state = "open";
            message = "The door has been opened.";
        }
    }

    public void drawOpenDoor (Graphics page) {
        page.drawRect(100, 100, 100, 100);
    }
    }

    class TempDoorPanel extends JPanel {

    private Door door;
    private JTextField currentStateOfDoor;
    private JButton openDoor;

    public TempDoorPanel() {
        super.setLayout(new BorderLayout());
        door = new Door("closed");
        super.setBackground(Color.blue);
        super.setPreferredSize(new Dimension (360, 400));

        currentStateOfDoor = new JTextField(14);
        currentStateOfDoor.setText(door.getMessage());
        super.add(currentStateOfDoor, BorderLayout.NORTH);

        openDoor = new JButton("Open Door");

        class openDoorListener implements ActionListener {
            public void actionPerformed (ActionEvent event) {
                door.open();
                repaintText();
            }
        }

        openDoorListener openlistener = new openDoorListener();
        openDoor.addActionListener(openlistener);

        JPanel holder = new JPanel();
        holder.add(openDoor);
        super.add(holder, BorderLayout.SOUTH);
    }

    private void repaintText() {
        currentStateOfDoor.setText(door.getMessage());
        // These methods are from Door class.
    }

    public void paintComponent (Graphics page) {
        super.paintComponent(page);
        if (door.isOpen())
            door.drawOpenDoor(page);
        // isOpen is a boolean method from Door class.
    }
}

什么有效:

  • 按钮一个接一个地出现在屏幕上的正确位置,在 BorderLayout.SOUTH。
  • JTextField 出现在正确的位置,在 BorderLayout.NORTH
  • 最后,蓝色区域出现在屏幕中央的正确位置。

我要解决的问题:

  • 我不知道如何在该蓝色区域的中间正确显示矩形。我试过改变矩形的坐标和大小,这根本不会改变它的大小。我可以让它 drawRect(100, 100, 100, 100) 并且它没有任何改变。
  • 我也知道矩形目前隐藏在 JTextField 的左上角后面,但我不知道如何将它移到 BorderLayout 中。

问题:

  • 如何在 BorderLayout 中放置一个矩形?
  • 在这样的布局中,如何调整通过 drawrect() 绘制的矩形的大小?
4

2 回答 2

4

因为您将组件添加到您在其上绘制的 JPanelJTextField会覆盖您的绘图。

解决方案:

1)通过检查方法JTextField中的高度来弥补这一点drawRect(..)

或更好

JPanel2)除非无法帮助,否则不要将组件添加到您正在绘制的相同组件上。

所以基本上我为你TempDoorPanel添加了一个新JPanel绘图面板BorderLayout.CENTER,我们现在可以使用它,它将显示在.drawRect(0,0,10,10)JPanel drawingPanel

  • 也不要调用而是覆盖并返回适合您的图纸的 s setPreferredSizeJPanelgetPreferredSize()Dimension

  • paintComponent在类外部调用,只需调用repaint()其实例

请参阅使用第 2 点的示例:

在此处输入图像描述

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Door");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

                TempDoorPanel panel = new TempDoorPanel();
                frame.add(panel);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}
class Door {

    private String state;
    private String message;

    public Door(String state) {
        this.state = state;
        message = "The door is currently closed.";
    }

    public void drawOpenDoor(Graphics page) {
        page.setColor(Color.GREEN);
        page.drawRect(0, 0, 10, 10);
    }
}

class TempDoorPanel extends JPanel {

    private Door door;
    private JTextField currentStateOfDoor;
    private JButton openDoor;

    public TempDoorPanel() {
        super.setLayout(new BorderLayout());
        door = new Door("closed");

        currentStateOfDoor = new JTextField(14);
        //AcurrentStateOfDoor.setText(door.getMessage());
        super.add(currentStateOfDoor, BorderLayout.NORTH);

        openDoor = new JButton("Open Door");

        final JPanel drawingPanel = new JPanel() {
            @Override
            protected void paintComponent(Graphics grphcs) {
                super.paintComponent(grphcs);
                // if (door.isOpen()) {
                door.drawOpenDoor(grphcs);
                // }
                // isOpen is a boolean method from Door class.

            }
        };
        drawingPanel.setBackground(Color.blue);
        add(drawingPanel);

        class openDoorListener implements ActionListener {

            public void actionPerformed(ActionEvent event) {
                //door.open();
                repaintText();
                drawingPanel.repaint();//so paint component of drawing panel is called
            }
        }

        openDoorListener openlistener = new openDoorListener();
        openDoor.addActionListener(openlistener);

        JPanel holder = new JPanel();
        holder.add(openDoor);
        super.add(holder, BorderLayout.SOUTH);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(300, 300);
    }

    private void repaintText() {
        // currentStateOfDoor.setText(door.getMessage());
        // These methods are from Door class.
    }
}
于 2013-02-14T14:57:43.703 回答
3

当您与侦听器一起处理开门事件时;

class openDoorListener implements ActionListener {
  public void actionPerformed(ActionEvent event) {
    door.open();
    repaintText();
  }
}

您实际上并没有调用重新绘制面板;因此面板的paintComponent()方法不会被调用,door.drawOpenDoor()也不会被调用。您可以通过单击按钮然后调整框架大小来对此进行测试。当您调整大小时,面板会自动重新粉刷和宾果游戏,您的门就会出现。

repaint()您可以通过在 ActionListener 中添加调用来解决此问题;

class openDoorListener implements ActionListener {
  public void actionPerformed(ActionEvent event) {
    door.open();
    repaintText();
    repaint();   // requests that the panel be repainted
  }
}
于 2013-02-14T15:12:03.330 回答