本来swing是不想看了的,但是既然书上有,还是得追求个有始有终
组件可以分为容器组件 和 非容器组件
容器组件是指可以包含其他组件的组件 又分为顶层容器 和 一般用途容器 非容器组件 必须要包含在容器中所有容器类有一个父类 Container
容器所有的共有操作都定义在 Container 中
Swing提供了 4 种顶层容器
JFrame 带有标题行 和控制按钮(最小化,最大化,关闭)的独立窗口创建应用程序时需要使用 JApplet 被包含在浏览器窗口中创建小应用程序时使用 JDialog 创建对话框时使用 JWindow 不带有 标题行 和 控制按钮 的窗口,很少使用JFrame类实例
public static void main(String[] args) throws FileNotFoundException { // 创建一个JFrame实例,带有标题 JFrame frame = new JFrame("JFrameDemo"); // 创建一个JButton实例,按钮带文件 JButton butt = new JButton("点我"); // 将按钮放到JFrame的中央 frame.getContentPane().add(butt, BorderLayout.CENTER); // 将JFrame设置为适当的大小 frame.pack(); // 显示JFrame frame.setVisible(true); // 退出时关闭窗口 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }顶层容器的组件都放在内容窗格中
4个顶层容器都有一个内容窗格,有两种方法可将组件放入该窗格中
通过 顶层容器的 getContentPane( )方法
frame.getContentPane().add(butt, BorderLayout.CENTER);创建一个新的内容窗格
JPanel contentPane = new JPanel(); // 创建Jpanel实例 contentPane.setLayout(new BorderLayout()); // 创建布局管理器 contentPane.add(butt,BorderLayout.CENTER); // 添加组件 frame.setContentPane(contentPane); // 添加内容窗格顶层容器的内容窗格默认是BorderLayout
Japanel默认的是 FlowLayout,因此需要给Jpanel实例设置一个BorderLayout布局管理器
修改JFrame实例
public static void main(String[] args) throws FileNotFoundException { // 创建一个JFrame实例,带有标题 JFrame frame = new JFrame("JFrameDemo"); // 创建一个JButton实例,按钮带文件 JButton butt = new JButton("点我"); // 创建一个Jpanel实例 JPanel contentPane = new JPanel(); // 为Jpanel设置BorderLayout布局 contentPane.setLayout(new BorderLayout()); // 将JButton放到Jpanel中央 contentPane.add(butt,BorderLayout.CENTER); // 为JFrame设置新的内容窗格 frame.setContentPane(contentPane); // 将JFrame设置为实当的大小 frame.pack(); // 显示JFrame frame.setVisible(true); // 退出时关闭窗口 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }普通面板 JPanel 和 滚动面板 JScrollPane 都是用途广泛的容器
面板不能独立存在,可以嵌套实例:创建一个黄色普通面板,通过add( )方法在面板中添加一个按钮,然后将该面板添加到JFrame的一个实例中,JFrame实例的背景色被设置成蓝绿色
public static void main(String[] args) { // 创建带标题的JFrame实例 JFrame frame = new JFrame("Hello"); // 获取内容窗格 Container contentPane = frame.getContentPane(); // 将JFrame实例的背景色设置成蓝绿色 contentPane.setBackground(Color.CYAN); // 创建一个JPanel实例 JPanel panel = new JPanel(); // 将JPanel实例的背景色设置为黄色 panel.setBackground(Color.YELLOW); JButton button = new JButton("点我"); // 将按钮实例添加到JPanel面板中 panel.add(button); // 将面板JPanel实例添加到JFrame的南侧 contentPane.add(panel,BorderLayout.SOUTH); // 设置容器大小 frame.setSize(300,200); // 设置容器可见性 frame.setVisible(true); // 退出时关闭窗口 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }JScrollPane 是滚动条的面板
Container的子类,只能添加一个组件一般先将多个组件添加到JPanel,然后将这个 JPanel 添加到 JScrollPane中显示提示性的文本信息或图标
创建一个以右对齐方式显示的标签
JLabel label = new JLabel("Hello",JLabel.RIGHT);
将组件挨个放置在容器的一行上,一行满了,就另起一行
使用FlowLayout管理JFrame中的若干按钮
public class Test { private JFrame frame; private JButton btn1,btn2,btn3; public static void main(String[] args) { Test test = new Test(); test.go(); } public void go() { frame = new JFrame("Hello"); Container contentPane = frame.getContentPane(); // 内容窗格 contentPane.setLayout(new FlowLayout()); // 将内容窗格设置FlowLayout布局管理器 btn1 = new JButton("OK"); // 分别创建3个按钮 btn2 = new JButton("Open"); btn3 = new JButton("Close"); contentPane.add(btn1); // 向内容窗格中添加3个按钮 contentPane.add(btn2); contentPane.add(btn3); frame.setSize(300,100); // 设置窗口大小 frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 退出时关闭窗口 } }BorderLayout是顶层容器中内容窗格默认的布局管理器
被划分为5个区域
BorderLayout.NORTH 上BorderLayout.SOUTH 下BorderLayout.WEST 左BorderLayout.EAST 右BorderLayout.CENTER 中实例
public class Test { private JFrame frame; private JButton btnNorth,btnSouth,btnWest,btnEast,btnCenter; public static void main(String[] args) { Test test = new Test(); test.go(); } public void go() { frame = new JFrame("Hello"); btnNorth = new JButton("上部"); btnSouth = new JButton("下部"); btnWest = new JButton("左部"); btnEast = new JButton("右部"); btnCenter = new JButton("中部"); frame.getContentPane().add(btnNorth,"North"); frame.getContentPane().add(btnSouth,"South"); frame.getContentPane().add(btnWest,"West"); frame.getContentPane().add(btnEast,"East"); frame.getContentPane().add(btnCenter,"Center"); frame.setSize(350,200); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 退出时关闭窗口 } }将容器空间划分为若干行乘若干列的网格,组件依次放入,每个组件占一格
public class Test { private JFrame frame; private JButton b1,b2,b3,b4,b5,b6; public static void main(String[] args) { Test test = new Test(); test.go(); } public void go() { frame = new JFrame("HELLO"); Container contentPane = frame.getContentPane(); contentPane.setLayout(new GridLayout(3,2)); b1 = new JButton("Grid1"); b2 = new JButton("Grid2"); b3 = new JButton("Grid3"); b4 = new JButton("Grid4"); b5 = new JButton("Grid5"); b6 = new JButton("Grid6"); contentPane.add(b1); contentPane.add(b2); contentPane.add(b3); contentPane.add(b4); contentPane.add(b5); contentPane.add(b6); frame.setSize(400,500); frame.pack(); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }卡片式布局管理器,将容器指的组件处理为一系列卡片,每一时刻只显示出一张
实例:
指定一个CardLayout类型的布局,然后其中加入了3张卡片,每张卡片都是JPanel的实例,并且具有不同的背景色,每按动鼠标,就会显示下一张
public class Test extends MouseAdapter { JPanel p1,p2,p3; JLabel l1,l2,l3; CardLayout myCard; // 声明一个CardLayout对象 JFrame frame; Container containerPane; public static void main(String[] args) { Test test = new Test(); test.go(); } /** * 处理鼠标事件,每当按下鼠标键,显示下一张卡片 * 如果显示到最后一张,则重新显示第一张 * @param e */ @Override public void mouseClicked(MouseEvent e) { myCard.next(containerPane); } public void go() { frame = new JFrame("HELLO"); containerPane = frame.getContentPane(); myCard = new CardLayout(); containerPane.setLayout(myCard); // 设置CardLayout布局管理器 p1 = new JPanel(); p2 = new JPanel(); p3 = new JPanel(); l1 = new JLabel("这是第一个标签"); // 为每个JPanel创建一个标签 p1.add(l1); p1.setBackground(Color.YELLOW); // 设定不同的背景颜色 l2 = new JLabel("这是第二个标签"); // 创建标签 p2.add(l2); p2.setBackground(Color.GREEN); l3 = new JLabel("这是第三个标签"); p3.add(l3); p3.setBackground(Color.BLUE); p1.addMouseListener(this); // 设置鼠标事件侦听程序 p2.addMouseListener(this); // 设置鼠标事件侦听程序 p3.addMouseListener(this); // 设置鼠标事件侦听程序 // 将每个Jpanel作为卡片加入Frame的内容窗格 containerPane.add(p1,"First"); // First是p1的名字 containerPane.add(p2,"Second"); containerPane.add(p3,"Third"); frame.setSize(300,200); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }将容器中的组件按水平方向排成一行或按垂直方向排成一列
排成一行时,每个组件可以有不同的宽度
一列时,可以有不同的高度
实例
public class Test { private JFrame frame; private JPanel pv,ph; public static void main(String[] args) { Test test = new Test(); test.go(); } public void go() { frame = new JFrame("World"); Container contentPane = frame.getContentPane(); pv = new JPanel(); // 为pv设置为垂直方向的BoxLayout pv.add(new JLabel("First")); // 为pv添加标签label pv.add(new Label("Second")); pv.add(new Label("Third")); // 将pv添加到内容窗格的中部 contentPane.add(pv,BorderLayout.CENTER); ph = new JPanel(); // 为ph设置水平方向的BoxLayout ph.setLayout(new BoxLayout(ph,BoxLayout.X_AXIS)); ph.add(new JButton("Yes")); // 为ph添加按钮 ph.add(new JButton("No")); ph.add(new JButton("Cancel")); // 将ph添加到内容窗格的下部 contentPane.add(ph,BorderLayout.SOUTH); frame.pack(); frame.setVisible(true); } }通过数值指定组件的位置和大小,需要将容器的布局管理器设置为空
调用组件的 setBounds( )方法设置组件的位置和大小实例
public class Test { private JFrame frame; private JButton b1,b2,b3; public static void main(String[] args) { Test test = new Test(); test.go(); } void go() { frame = new JFrame("空布局"); Container contentPane = frame.getContentPane(); contentPane.setLayout(null); // 将布局管理器设置为空 b1 = new JButton("Yes"); contentPane.add(b1); // 添加按钮 b2 = new JButton("No"); contentPane.add(b2); b3 = new JButton("Cancel"); contentPane.add(b3); // 设置按钮的位置和大小 b1.setBounds(30,15,75,50); b2.setBounds(60,60,75,50); b3.setBounds(160,20,75,30); frame.setSize(300,200); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }每当用户在组件上进行某种操作时,事件处理系统会生成一个事件类对象
操作不同,事件类对象也会不同
系统为了给每个事件类型提供一个侦听程序接口,规定了接收并处理该类事件的方法规范
事件侦听程序
为了接收某类用户事件,组件必须注册相应的事件处理程序作为侦听程序对象的类必须实现相应的接口,并实现接口中的方法委托事件处理模型
事件被直接送往产生这个事件的组件,组件需要注册一个或多个侦听程序侦听程序的类包含了事件处理程序,用来接收和处理这个事件事件是一个对象,只向注册的侦听程序报告事件处理的步骤
1.程序中引入 Java.awt.event 包2.给所需的事件源对象注册事件侦听程序,事件源对象.addXXXListent(XXXListent);3.实现相应的方法ActionEvent事件处理示例
public class Test { public static void main(String[] args) { JFrame frame = new JFrame("ActionEvent Demo"); JButton btn = new JButton("点我"); // 注册事件侦听程序 btn.addActionListener(new ButtonHandler()); // 添加按钮 frame.getContentPane().add(btn,BorderLayout.CENTER); frame.pack(); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } class ButtonHandler implements ActionListener { @Override public void actionPerformed(ActionEvent e) { System.out.println("触发了事件"); } }事件的侦听程序可以定义在一个单独的类中,也可以定义在组件类中
侦听程序定义在组件类中的示例
public class Test { public static void main(String[] args) { JFrame frame = new JFrame("ActionEvent Demo"); JButton btn = new JButton("点我"); // 注册事件侦听程序 btn.addActionListener(new ButtonHandler()); // 添加按钮 frame.getContentPane().add(btn,BorderLayout.CENTER); frame.pack(); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } } class ButtonHandler implements ActionListener { @Override public void actionPerformed(ActionEvent e) { System.out.println("触发了事件"); } }自定义的MyButton组件继承自JButton,同时实现了ActionListener接口
在MyButton的构造方法中,通过addActionListenter(this)将自身注册为自己的侦听程序
当用户单击按钮时,调用System.exit(0)结束运行
检查鼠标拖动示框
// 同时实现MouseListener接口和MouseListener public class Test implements MouseMotionListener,MouseListener { private JFrame frame; private JTextField tf; public static void main(String[] args) { Test test = new Test(); test.go(); } public void go() { frame = new JFrame("鼠标拖动实例"); Container contentPane = frame.getContentPane(); contentPane.add(new Label("点击鼠标"),BorderLayout.NORTH); tf = new JTextField(30); contentPane.add(tf,BorderLayout.SOUTH); // 注册侦听程序 frame.addMouseMotionListener(this); frame.addMouseListener(this); frame.setSize(300,300); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void mouseClicked(MouseEvent e) { String s = "点击"; tf.setText(s); } @Override public void mousePressed(MouseEvent e) { String s = "按下"; tf.setText(s); } @Override public void mouseReleased(MouseEvent e) { String s = "释放"; tf.setText(s); } // 实现MouseListener接口中方法 @Override public void mouseEntered(MouseEvent e) { String s = "The Mouse entered"; tf.setText(s); } @Override public void mouseExited(MouseEvent e) { String s = "The mouse has left the building"; tf.setText(s); } // 实现MouseMotionListener接口中的方法 @Override public void mouseDragged(MouseEvent e) { String s = "Mouse Dragging: X = "+e.getX()+"Y="+e.getY();tf.setText(s); } @Override public void mouseMoved(MouseEvent e) { String s = "移动"; tf.setText(s); } }事件侦听模式允许为一个组件注册多个侦听程序
通过在该事件的处理程序中编写需要的所有响应
事件侦听模型允许多个调用addListener方法
为了进行事件处理,需要创建实现Listener接口的类,需要一 一实现这些抽象方法
在适配器类中实现了相应接口中的全部方法只是方法为空
在创建新类时,可以不实现接口,只继承某个适当的适配器,并且重写所需要的方法
适配器实例
// 同时实现MouseListener接口和MouseListener public class Test extends MouseAdapter { // 只关心单击鼠标事件的处理,在这里继承MouseAdapter,并只覆盖有关的方法 @Override public void mouseClicked(MouseEvent e) { System.out.println("鼠标点击了"); } }列出当前机器上所有的可用字体
public static void main(String[] args) { GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); String[] fontName = env.getAvailableFontFamilyNames(); System.out.println("可用字体:"); for (int i = 0; i < fontName.length; i++) { System.out.println(" "+fontName[i]); } }为了解决图形对象的局限性。引入了Java2D,包括一个继承于Graphics类的Graphics2D类,增加了许多状态属性,扩展了Graphics的绘图功能
图形状态属性
stroke属性 控制属性线的宽度,笔形样式,线段连接方式,创建BasicSrtoke对象,再调用setStroke()方法即可设置其属性 paint属性 属性控制填充效果,先调用GradientPanint()方法确定填充效果,再使用setPaint()方法进行设置 transform属性 用来实现常用的图形平移,缩放,斜切等变化操作 clip属性 用于实现剪裁效果,可以调用setClip()方法,确定剪裁区的Shape,从而设置剪裁属性 composit属性 设置图形重叠区域的效果Graphics2D类的绘图方法
先在重画方法paintComponent()或paint()中,把参数对象g强制转换为Graphics2D对象
然后用图形类提供的静态方法Double()创建该图形的对象
最后,以图形对象为参数调用Graphics2D对象的draw()方法绘制
@Override protected void printComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; // 将对象g类型Graphics转换为Graphics2D Line2D.Double line = new Line2D.Double(30.0, 30.0, 240.0, 30.0); // 创建图形对象 g2d.draw(line); // 绘制线段 RoundRectangle2D.Double rRect = new RoundRectangle2D.Double(13.0, 30.0, 100.0, 70.0, 40.0, 20.0); g2d.draw(rRect); // 绘制圆角矩形 }Graphics2D的几何图形类
声明并创建线段对象,起点时(2,3) 终点是(200,300)
Line2D line = new Line2D.Double(2, 3, 200, 300);声明并创建矩形对象,矩形的左上角是(20,30) 宽是80 高是40
Rectangle2D drect = new Rectangle2D.Double(20, 30, 80, 40);