Java核心技术卷1Chapter7笔记 图形程序设计

时间:2022-12-25 15:00:35

Swing是指被绘制的用户界面类,AWT是指像事件处理这样的窗口工具箱的底层机制。

SWT,JavaFX是可能的代替技术。

 

创建框架

Java中,顶层窗口(就是没有包含在其他窗口中的窗口)被称为框架(frame),在AWT库中有一个被称为Frame的类,用于描述顶层窗口。这个类的Swing版本名为JFrame,它拓展于Frame类。JFrame是极少数几个不绘制在画布上的Swing组件之一。因此,它的修饰部件(按钮、标题栏、图标等)由用户的窗口系统绘制,而不是由Swing绘制。

import java.awt.*;//abstract wiindow toolkit
import javax.swing.*;//swing类在java拓展包中

/**
 * @version 1.32 2007-06-12
 * @author Cay Horstmann
 */
public class SimpleFrameTest
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(new Runnable()/*swing组件由事件分派线程进行配置,
      线程将鼠标点击和按键控制转移到用户接口组件*/
         {
            public void run()
            {
               SimpleFrame frame = new SimpleFrame();
               /*
                * 定义一个用户关闭框架时的响应动作。
                * 在此,让程序简单的退出即可。
                */
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               /*
                * 框架起初是不可见的。
                */
               frame.setLocationByPlatform(true);
               frame.setVisible(true);
            }
         });
      /*
       * 主线程终止
       */
   }
}

class SimpleFrame extends JFrame
{
   private static final int DEFAULT_WIDTH = 300;
   private static final int DEFAULT_HEIGHT = 200;

   public SimpleFrame()
   {
      setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
   }
}

在每个Swing程序中,有两个技术问题需要强调。

首先,所有的Swing组件必须由事件分派线程(event dispatch thread)进行配置,线程将鼠标点击和按键控制转移到用户接口组件。下面的代码片段是事件分派线程中的执行代码:

  EventQueue.invokeLater(new Runnable()
       {
            public void run()
            {
               //statements           
            }
         });    

接下来,定义一个用户关闭这个框架时的响应动作。对于这个程序而言,只是让程序简单退出即可。选择这个响应动作的语句是

 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

在包含多个框架的程序中,不能在用户关闭其中的一个框架时就让程序退出。在默认情况下,用户关闭窗口时只是将框架隐藏起来,而程序并没有终止(在最后一个框架不可见之后,程序再终止,这样处理比较合适,而Swing却不是这样工作的)。

After scheduling the initialization statements, the main method exits. Note that exiting main does not terminate the program—just the main thread. The event dispatch thread keeps the program alive until it is terminated, either by closing the frame or by calling the System.exit method.

 

框架定位

JFrame继承了许多用于处理框架大小和位置的方法。重要的有下面几个:

• The setLocation and setBounds methods for setting the position of the frame

• The setIconImage method, which tells the windowing system which icon to display in the title bar, task switcher window, and so on

• The setTitle method for changing the text in the title bar

• The setResizable method, which takes a boolean to determine if a frame will be resizeable by the user

可以让窗口系统控制窗口的位置,如果在显示之前调用

   frame.setLocationByPlatform(true);

窗口系统会选用窗口的位置。

框架属性

确定合适的框架大小:根据屏幕的分辨率编写代码重置框架的大小。

要得到屏幕大小,调用Toolkit类的静态方法getDefaultToolkit得到一个Toolkit对象。然后调用getScreenSize方法,以Dimension对象的形式返回屏幕的大小。Dimension对象同时用共有实例变量widthheight保存着屏幕的宽度和高度。Here is the code:

      Toolkit kit = Toolkit.getDefaultToolkit();
      Dimension screenSize = kit.getScreenSize();
      int screenHeight = screenSize.height;
      int screenWidth = screenSize.width;

下面,将框架大小设定为上面取值的50%,再告知窗口系统定位框架:

      setSize(screenWidth / 2, screenHeight / 2);
      setLocationByPlatform(true);

另外提供一个图标。由于图像的描述与系统有关,所以需要再次使用系统工具箱加载图像。然后将这个图像设置为框架的图标。

      Image img = new ImageIcon("icon.gif").getImage();
      setIconImage(img); 

• If your frame contains only standard components such as buttons and text fields, you can simply call the pack method to set the frame size. The frame will be set to the smallest size that contains all components. It is quite common to set the main frame of a program to the maximum size. As of Java SE 1.4, you can simply maximize a frame by calling

frame.setExtendedState(Frame.MAXIMIZED_BOTH);

• It is also a good idea to remember how the user positions and sizes the frame of your application and restore those bounds when you start the application again.

在组件中显示信息

You could draw the message string directly onto a frame, but that is not considered good programming practice. In Java, frames are really designed to be containers for components, such as a menu bar and other user interface elements. You normally draw on another component which you add to the frame.

现在将一个绘制消息的组件添加到框架中去。绘制一个组件,需要定义一个拓展JComponent的类,并覆盖其中的paintComponent方法。

class MyComponent extends JComponent{
   public void paintComponent(Graphics g){
      code for drawing
   }
}

 

无论何种原因,只要窗口需要重新绘图,事件处理器就会通告组件,从而引发执行所有组件的paintComponent方法。如果需要强制刷新屏幕,就需要调用repaint方法,而不是paintComponent方法。它将引发采用相应配置的Graphics对象调用所有组件的paintComponent方法。

在框架中填入一个或多个组件时,如果你只想使用它们的首选大小,可以调用pack方法而不是setSize方法。

import javax.swing.*;
import java.awt.*;
/**
 * @version 1.32 2007-06-12
 * @author Cay Horstmann
 */
public class NotHelloWorld
{
   public static void main(String[] args)
   {
      EventQueue.invokeLater(new Runnable()
         {
            public void run()
            {
               JFrame frame = new NotHelloWorldFrame();
               frame.setTitle("NotHelloWorld");
               frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
               frame.setVisible(true);
            }
         });
   }
}
 /**
 * A frame that contains a message panel
 */
class NotHelloWorldFrame extends JFrame
{
   public NotHelloWorldFrame()
   {
      add(new NotHelloWorldComponent());
      pack();
   }
}
/**
 * A component that displays a message.
 */
class NotHelloWorldComponent extends JComponent
{
   public static final int MESSAGE_X = 75;
   public static final int MESSAGE_Y = 100;
 
   private static final int DEFAULT_WIDTH = 300;
   private static final int DEFAULT_HEIGHT = 200;
 
   public void paintComponent(Graphics g)
   {
      g.drawString("Not a Hello, World program", MESSAGE_X, MESSAGE_Y);
   }
  
   public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
}