2013-02-14 5 views
3

Я пытаюсь выполнить простую домашнюю работу, где я показываю строку текста, показывающую, открыт ли дверной объект или нет. Под этим я визуально представляю его (используя метод drawRect). И внизу у меня есть две кнопки, которые могут открывать или закрывать дверь, тем самым меняя текст и прямоугольник.Добавление графики в JFrame с использованием BorderLayout

Edit: Список кода, который может быть составлен с учетом ныне:

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(), в таком макете?
+1

Пожалуйста произвести [SSCCE] (http://sscce.org), который требует одну копию и вставьте Теперь мы должны пойти и создать новый проект, новый класс и новый главный т.д., я хочу, чтобы просто создать класс с тем же именем, что и ваш, и скопируйте и вставьте код. Но эй, это я ленив: P тоже не должен содержать ошибок, т. Е. 'Door.isOpen()' дает ошибку, потому что вы не включили метод –

+0

Теперь работаем над этим, спасибо за подсказку –

+0

Проблема, с которой вы не видите прямоугольник - это его покрытие JTextField, потому что ваши координаты пытаются: 'page.drawRect (100, 100, 10, 10);' –

ответ

4

Поскольку вы добавляете компоненты в JPanel, вы рисуете на JTextField, накрываете свой рисунок.

Решение:

1) Либо компенсировать это путем проверки JTextField высоты в методе drawRect(..)

или лучше

2) Dont добавить компоненты к тому же JPanel, которые вы рисуете если это не поможет.

Поэтому в основном я сделал ваш TempDoorPanel добавить новый JPanel к BorderLayout.CENTER который является рисунок панели теперь мы можем использовать drawRect(0,0,10,10), и она будет отображаться в верхнем левом углу JPaneldrawingPanel.

  • DonT Также называют 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. 
    } 
} 
+0

Есть ли способ сделать это без invokeLater Runnable и т. Д. Я только спрашиваю, потому что это тот раздел, который предоставил мне мой университет, и они не дали никаких указаний на то, что он нуждается в изменении (я не знаю, что такое runnable). Независимо от того, спасибо за это. –

+0

Он нуждается в изменении (да, вы можете его оставить, но это будет полезно позже). Все компоненты Swing должны создаваться и обрабатываться в разделе «Событие Dispatch Thread» через 'SwingUtilties.invokeLater (Runnable r)'. Прочтите его здесь в [Concurrency in Swing] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html). Таким образом, в основном ваш университет не придерживается лучших методов Swing, расскажите им об этом! –

+0

Я буду! Еще одна вещь. Я знаю, что paintComponent автоматически запускается (хотя его можно переопределить вручную). Но я не могу найти в API, где он говорит, что он автоматически запускается. Причина, по которой мне любопытно, это выяснить, что еще запускается автоматически. Когда я начал делать это вчера, мне потребовалось несколько часов, чтобы понять, что мне не нужно передавать объект Graphics в класс paintComponent, поскольку все это было сделано для меня! Где она говорит, почему она автоматическая, а что еще автоматическая? –

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 
    } 
} 
+0

Спасибо за это, внезапно все это работает. Именно эти автоматические звонки убивают меня. Если такие люди, как я, не сказали мне, что я должен был это сделать, я бы не подумал. –

+0

+1 yup еще одна проблема OP не вызывает перерисовку() –

Смежные вопросы