使用BorderLayout将图形添加到JFrame中

时间:2013-02-14 14:31:57

标签: java swing jframe jpanel paintcomponent

我正在尝试做一个简单的作业,在那里我显示一行文字,显示门对象是否打开。在其下面,我直观地表示它(使用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()绘制的矩形的大小?

2 个答案:

答案 0 :(得分:4)

因为您向JPanel添加组件,所以您在JTextField上绘制的内容将覆盖您的绘图。

<强>解决方案:

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

或更好

2)除非无法帮助,否则不要将组件添加到您正在绘制的同一JPanel

所以基本上我让你的TempDoorPanel添加了一个新的JPanelBorderLayout.CENTER这是绘图面板我们现在可以使用drawRect(0,0,10,10)了将显示在JPanel drawingPanel的左上角。

  • 也不要在setPreferredSize上致电JPanel,而是覆盖getPreferredSize()并返回符合您图纸的Dimension

  • 要在课堂外调用paintComponent,只需致电repaint()其实例

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

enter image description here

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.
    }
}

答案 1 :(得分:3)

当您与听众处理开门事件时;

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

您实际上并未包含重新绘制面板的电话;因此,不会调用面板的paintComponent()方法,也不会调用door.drawOpenDoor()。您可以通过单击按钮然后调整框架大小来测试它。当您调整大小时,面板会自动重新绘制并且宾果游戏,您的门会出现。

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

class openDoorListener implements ActionListener {
  public void actionPerformed(ActionEvent event) {
    door.open();
    repaintText();
    repaint();   // requests that the panel be repainted
  }
}