2016-01-13 2 views
0

Я пытался понять разницу между JFrame и JPanel. Я предпочитаю использовать подклассы JFrame вместо JPanel, но люди всегда говорят мне, что вместо этого лучше использовать подкласс JPanel. Вот пример мне с помощью JFrame:Разница между реализацией JFrame и JPanel

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 

import javax.swing.JFrame; 

public class Game extends JFrame implements Runnable { 
int x, y, xCoord, yCoord; 
private Image dbImage; 
private Graphics dbg; 

public void move() { 
    x += xCoord; 
    y += yCoord; 
    if (x <= 20) { 
     x = 20; 
    } 
    if (x >= 480) { 
     x = 480; 
    } 
    if (y <= 40) { 
     y = 40; 
    } 
    if (y >= 480) { 
     y = 480; 
    } 
} 

public void setXCoord(int xcoord) { 
    xCoord = xcoord; 
} 

public void setYCoord(int ycoord) { 
    yCoord = ycoord; 
} 

public class AL extends KeyAdapter { 

    @Override 
    public void keyPressed(KeyEvent e) { 
     int keyCode = e.getKeyCode(); 
     if (keyCode == e.VK_LEFT) { 
      setXCoord(-1); 
     } 
     if (keyCode == e.VK_RIGHT) { 
      setXCoord(+1); 
     } 
     if (keyCode == e.VK_UP) { 
      setYCoord(-1); 
     } 
     if (keyCode == e.VK_DOWN) { 
      setYCoord(+1); 
     } 
     Game.this.repaint(); 
    } 

    @Override 
    public void keyReleased(KeyEvent e) { 
     int keyCode = e.getKeyCode(); 
     if (keyCode == e.VK_LEFT) { 
      setXCoord(0); 
     } 
     if (keyCode == e.VK_RIGHT) { 
      setXCoord(0); 
     } 
     if (keyCode == e.VK_UP) { 
      setYCoord(0); 
     } 
     if (keyCode == e.VK_DOWN) { 
      setYCoord(0); 
     } 
     Game.this.repaint(); 

    } 

} 

public static void main(String[] args) { 
    Game game = new Game(); 
    Thread t = new Thread(game); 
    t.start(); 
} 

public Game() { 
    addKeyListener(new AL()); 
    setTitle("Game"); 
    setSize(500, 500); 
    setResizable(true); 
    setVisible(true); 
    setBackground(Color.BLACK); 
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    x = 250; 
    y = 250; 

} 

public void paintComponent(Graphics g) { 
    g.setColor(Color.GREEN); 
    g.fillOval(x, y, 15, 15); 
} 

@Override 
public void paint(Graphics g) { 
    dbImage = createImage(getWidth(), getHeight()); 
    dbg = dbImage.getGraphics(); 
    paintComponent(dbg); 
    g.drawImage(dbImage, 0, 0, this); 
} 

@Override 
public void run() { 
    try { 
     while (true) { 
      move(); 
      Thread.sleep(30); 
     } 
    } catch (Exception e) { 
     System.out.println(e.getMessage()); 
    } 
} 

} 

Это работает отлично (для там быть небольшая задержка, когда я удерживая одну из кнопок, кроме), но когда я пытаюсь изменить мой код, реализовав JPanel вместо JFrame, ничего не отображается ... Вот код для подкласса JPanel:

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.event.KeyAdapter; 
import java.awt.event.KeyEvent; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class Game extends JPanel implements Runnable { 
int x, y, xCoord, yCoord; 
private Image dbImage; 
private Graphics dbg; 
JFrame frame; 

public void move() { 
    x += xCoord; 
    y += yCoord; 
    if (x <= 20) { 
     x = 20; 
    } 
    if (x >= 480) { 
     x = 480; 
    } 
    if (y <= 40) { 
     y = 40; 
    } 
    if (y >= 480) { 
     y = 480; 
    } 
} 

public void setXCoord(int xcoord) { 
    xCoord = xcoord; 
} 

public void setYCoord(int ycoord) { 
    yCoord = ycoord; 
} 

public class AL extends KeyAdapter { 

    @Override 
    public void keyPressed(KeyEvent e) { 
     int keyCode = e.getKeyCode(); 
     if (keyCode == e.VK_LEFT) { 
      setXCoord(-1); 
     } 
     if (keyCode == e.VK_RIGHT) { 
      setXCoord(+1); 
     } 
     if (keyCode == e.VK_UP) { 
      setYCoord(-1); 
     } 
     if (keyCode == e.VK_DOWN) { 
      setYCoord(+1); 
     } 
     Game.this.repaint(); 
    } 

    @Override 
    public void keyReleased(KeyEvent e) { 
     int keyCode = e.getKeyCode(); 
     if (keyCode == e.VK_LEFT) { 
      setXCoord(0); 
     } 
     if (keyCode == e.VK_RIGHT) { 
      setXCoord(0); 
     } 
     if (keyCode == e.VK_UP) { 
      setYCoord(0); 
     } 
     if (keyCode == e.VK_DOWN) { 
      setYCoord(0); 
     } 
     Game.this.repaint(); 

    } 

} 

public static void main(String[] args) { 
    Game game = new Game(); 
    Thread t = new Thread(game); 
    t.start(); 
} 

public Game() { 
    frame = new JFrame(); 
    frame.addKeyListener(new AL()); 
    frame.setTitle("Game"); 
    frame.setSize(500, 500); 
    frame.setResizable(true); 
    frame.setVisible(true); 
    frame.setBackground(Color.BLACK); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    x = 250; 
    y = 250; 

} 

@Override 
public void paintComponent(Graphics g) { 
    g.setColor(Color.GREEN); 
    g.fillOval(x, y, 15, 15); 
} 

@Override 
public void paint(Graphics g) { 
    dbImage = createImage(getWidth(), getHeight()); 
    dbg = dbImage.getGraphics(); 
    paintComponent(dbg); 
    g.drawImage(dbImage, 0, 0, this); 
} 

@Override 
public void run() { 
    try { 
     while (true) { 
      move(); 
      Thread.sleep(30); 
     } 
    } catch (Exception e) { 
     System.out.println(e.getMessage()); 
    } 
} 

} 
+0

Вы забыли добавить панель во втором примере: _frame.getContentPane(). add (это); _ – Berger

+0

http://stackoverflow.com/questions/13212431/jpanel-vs-jframe-in-java – chenchuk

+0

@Berger Спасибо, я этого не видел ... Но не могли бы вы объяснить мне, почему вы нужно добавить jframe в jframe если jframe является компонентом верхнего уровня? – Eames

ответ

1

Как показывает код, вам нужен обычай JPanel, потому что вы хотите изменить поведение некоторых методов, таких как paintComponent.

Однако вам не нужен пользовательскийJFrame, поэтому нет необходимости создавать класс, расширяющий его.

Наконец, ваш основной класс не должен быть вашим классом панели.

Вот пример класса, я переместил материал кадра из конструктора Game в этот основной класс.

public class MainClass { 

    public static void main(String[] args) { 

    Game game = new Game(); 

    JFrame frame = new JFrame(); 

    frame.addKeyListener(new AL()); 
    frame.setTitle("Game"); 
    frame.setSize(500, 500); 
    frame.setResizable(true); 
    frame.getContentPane().add(game); 
    frame.setBackground(Color.BLACK); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    frame.setVisible(true); 

    Thread t = new Thread(game); 
    t.start(); 

    } 


    } 
1

JFrame является гораздо более сложный компонент, то вы могли бы подумать, для начала, он имеет JRootPane, как это первичный контейнер, который содержит contentPane, JMenuBar и контролирует glassPane

RootPane

см. How to Use Root Panes для более подробной информации.

JFrame также имеет декорации (границы), эти границы окрашены в пределах самого окна, содержимое затем выкладывается внутри них, поэтому границы не красятся тогда.

При переопределении paint контейнера верхнего уровня, как JFrame, существует целый ряд вопросов, которые вы столкнетесь:

  • Это не двойной буферизации, который может вызвать мерцание в окне обновляется
  • остальные компоненты могут быть окрашены независимо от кадра (так paint метод фрейма не называется), который не может вызвать никакого конца проблем
  • Теперь вы можете рисовать под украшением врезки см Java graphic image, How to get the EXACT middle of a screen, even when re-sized и How can I set in the midst? для более подробной информации.
  • Вы заблокировав себя в одном случае использования, вы не можете добавить окна в другие контейнеры, что снижает ваши компоненты повторно использовать значение

Вообще говоря, с точки зрения ООП из, вы «на самом деле не добавление каких-либо новых функций в класс (или, по крайней мере, ни один, который не может быть сгенерирован с помощью лучших подходов).

Когда вы используете что-то вроде JPanel, все остальные выше не больше беспокойства нет:

  • Они двойной буферизации по умолчанию
  • Если вы используете менеджер компоновки (на панели содержимого), компонент будет выложен в украшении врезки
  • width и height компонента представляет всю видимую область
  • вы можете добавить этот компонент к тому, что когда-либо контейнеру вы хотите

Вы должны также переопределить getPreferredSize метод JPanel «s и возвращает нужный размер вы хотите, чтобы ваша панель вообще будет, то вы можете использовать JFrame#pack„упаковать“окно вокруг него, это будет сделать окно больше, то область содержимого, но означает, что вы не царапаете голову, задаваясь вопросом, почему вы устанавливаете окно определенного размера, но ваш компонент меньше.

+0

Скопируйте этот ответ на [бета-версию документации] (http://docs-beta.stackexchange.com/). –

+0

Спасибо за отличный ответ! Только один вопрос ... Как я запираю себя в одном случае? Почему я не могу повторно использовать JFrame (подкласс)? Благодарю. – Eames

+0

Вы можете подклассом, но вы не можете повторно использовать рамку в других контейнерах – MadProgrammer

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