为什么在swing应用程序中需要扩展JFrame?

10
为什么在构建 Swing 应用程序时需要扩展 JFrame 类。据我所知,extends 用于继承基类。以下程序中没有使用JFrame类的任何函数,但仍然扩展了它。我知道我错过了一些信息。是像 JFrame 类的某些函数在后台运行吗?
1)代码
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JPasswordField;
import javax.swing.JOptionPane;

public class tuna extends JFrame{

   private JTextField item1;
   private JTextField item2;
   private JTextField item3;
   private JPasswordField passwordField;
   Container contentPane ;
   public tuna(){
      super("The title");

      setLayout(new FlowLayout());

      item1 = new JTextField(10);
      contentPane.add(item1);

      item2 = new JTextField("enter text here");
      add(item2);

      item3 = new JTextField("uneditable", 20);
      item3.setEditable(false);
      add(item3);

      passwordField = new JPasswordField("mypass");
      add(passwordField);

      thehandler handler = new thehandler();

      item1.addActionListener(handler);
      item2.addActionListener(handler);
      item3.addActionListener(handler);
      passwordField.addActionListener(handler);
   }

   public static void main(String[] args){
      tuna aye = new tuna();
   }

   private class thehandler implements ActionListener{

      public void actionPerformed(ActionEvent event){
         String string = "";

         if(event.getSource()==item1)
            string=String.format("field 1: %s",event.getActionCommand());
         else if (event.getSource()==item2)
            string=String.format("field 2: %s",event.getActionCommand());
         else if (event.getSource()==item3)
            string=String.format("field 3: %s",event.getActionCommand());
         else if (event.getSource()==passwordField)
            string=String.format("password field is: %", event.getActionCommand());
      }
   }
}

9
这个问题的前提是错误的。你不需要扩展一个JFrame来使用它。 - barjak
4
实际上,你不应该扩展JFrame(也不应该扩展任何其他类,除非你真正增强了功能,也就是实现了无法通过使用/配置该类来实现的功能)。大多数教程和Netbeans都提供了糟糕的示例 :-) - kleopatra
4个回答

19
你不需要继承JFrame,实际上我们许多经常进行Swing编程的人会特意避免继承这个类。我个人会尝试继承那些计划改变类本质行为(即重写非静态方法)的类。由于我很少需要这样做来创建JFrame,因此我很少需要去扩展它。
另一个避免扩展它的原因是: 如果你以后想在JDialog、JOptionPane或其他容器中显示你刚创建的GUI作为复杂GUI的一部分,如果你的类继承了JFrame,则会很难实现。我个人会将我的GUI类设计为创建JPanels,这样做会更容易些。
基于你的代码的一个愚蠢的例子:
import javax.swing.*;

// this guy extends *nothing*
public class TunaExample {
   private static final int COLS = 10;
   private JPanel mainPanel = new JPanel(); // this is what I'll add to contentPane
   private JTextField field1 = new JTextField(COLS);
   private JTextField field2 = new JTextField(COLS);
   private JPasswordField passwordField = new JPasswordField(COLS);
   private JComponent[] allComponents = { new JLabel("Field 1:"), field1,
         new JLabel("Field 2:"), field2, new JLabel("Password:"), passwordField };

   public TunaExample() {
      field2.setEditable(false);
      field2.setFocusable(false);
      field1.setText("Field 1");
      field2.setText("Uneditable");

      for (JComponent comp : allComponents) {
         mainPanel.add(comp);
      }
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   private static void createAndShowGui() {
      TunaExample tunaExample = new TunaExample();

      // creating my JFrame only when I need it and where I need it
      JFrame frame = new JFrame("Tuna Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(tunaExample.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

4
您代码中需要注意的第一点是这个:
super("The title");

这实际上调用了JFrame构造函数,并将 "The title" 作为标题字符串传递给它。这是使用Jframe在您的代码中显式使用功能的一个示例。这将为您构建出窗口。

add这样的方法都是从JFrame类继承的。这些方法将Components添加到JFrame对象中。

为什么需要继承?

简单地说,你的类就是一个带有一点点额外功能的JFrame。当你有一个Is A操作时,你就会使用继承。这种方法的另一个优点是,您的类可以被称为 JFrame。

JFrame tuna = new tuna();
// Note: All classes are meant to start with a capital letter.

另一种观点

需要注意的是,您不一定必须继承自JFrame类。您可以使用组合。在这种情况下,您可以有如下代码:

 public class Tuna {
      private JFrame parentWindow;
      // Rest of class.
 }

如上所述,惯例是遵循“Is A”和“Has A”的方法。如果类A是类B的一个示例,我们倾向于使用继承。如果类A有类B的实例,则使用组合,尽管在大多数情况下,继承可以与组合互换使用。
另一个观点
如评论中所述,在尝试自己实现之前,应始终寻找提供此类功能的现有API。

2
@AmlanKarmakar:你在同时做两件事情。你正在创建一个金枪鱼对象(应该命名为“Tuna”,因为它是一个类),但由于Tuna扩展了JFrame,所以它也是一个JFrame。但是它被一个JFrame 变量持有,因此该变量将无法引用任何不属于JFrame的新方法。对Chris的好答案点赞+1。 - Hovercraft Full Of Eels
@HovercraftFullOfEels 每天学点新东西! - christopher
@kleopatra 在大多数情况下,您可以通过组合实现与继承相同的功能。我认为这是一个非常合理的说法。OP的问题是关于在JFrame上下文中为什么要从超类继承。我觉得我已经解释得很清楚了。我没有考虑到API,现在我会进行编辑。 - christopher
傲慢无助于解决问题。你能解释一下为什么这是错误的说法吗? - christopher
当然可以(比我更好),任何一本关于面向对象基础的严肃教材都可以。顺便说一下,没有贬低的意思。 - kleopatra
显示剩余4条评论

2

要在您的应用程序中使用 JFrame,您可以像在您的代码中一样扩展它,或者创建一个 object

JFrame frame= new JFrame();

然后你就可以做到了。

frame.setTitle("Title");
frame.setLayout(layout);

你可以以任何方式完成,但如果要在应用程序中使用JFrame并访问其方法等,则必须使用以下其中一种方法:


0
如果您想创建一个独立的应用程序,可以扩展JPanel或JFrame,或在类实现中创建它们的实例。
通常情况下,具有基于Swing的GUI的独立应用程序至少有一个包含层次结构,其中JFrame是其根。例如,如果一个应用程序有一个主窗口和两个对话框,则该应用程序具有三个包含层次结构,因此有三个顶级容器。http://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html

http://docs.oracle.com/javase/tutorial/uiswing/components/frame.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接