JavaGUI-Swing
sf2gis@163.com
2015年12月31日
1 目标:针对JVM重写AWT,减少对OS的依赖。
2 原理:使用Java重写AWT组件,模拟各个组件,减少对OS的依赖,使各平台都具有相同外观。
Swing继承AWT的事件机制、基础容器、布局,在容器中针对JVM编程,模拟不同平台的组件,实现所有平台的组件一致性,减少了平台依赖(基本容器各平台基本相同,但依然有依赖),但这需要更多的内存,速度会减慢。
Swing在AWT的基础上重写了所有的组件(在原组件的名字前加上J前缀(果然是Java的亲儿子)),扩展了原有的组件和形式(UIManager)。
AWT使用方法参见:JavaGUI-AWT.docx
3 流程:创建组件,设置布局,添加监听对象
3.1 创建组件:在AWT的组件名前加J,就是Swing重写的组件
JFrame f=new JFrame();
3.2 设置布局:使用AWT相同的布局。
3.3 添加监听对象:使用AWT相同的事件机制。
3.4 示例
参考:http://blog.csdn.net/aeolus1019/article/details/7980950
/**
* Demo
*/
package lee;
importjava.awt.BorderLayout;
importjava.awt.event.ActionEvent;
importjava.awt.event.ActionListener;
importjavax.swing.JButton;
importjavax.swing.JFrame;
/**
* @author sf2gis@163.com
*
*/
public class Main{
/**
*@param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame f=new JFrame();
f.setLayout(new BorderLayout());
f.setBounds(30,30,200,200);
f.setVisible(true);
f.setTitle("Hello,World!");
JButton btn1=newJButton("btn1");
f.add(btn1,BorderLayout.NORTH);
btn1.addActionListener(new ActionListener() {
@Override
public voidactionPerformed(ActionEvent e) {
// TODO Auto-generatedmethod stub
System.out.println("btn1,click");
}
});
f.pack();
}
}
4 方法:外观风格UIManager
4.1 目标:控制组件的外观风格。
4.2 原理:由于Swing全部使用Java模拟了所有平台的组件,因此外观控制变得方便。使用UIManager控制组件的外观,可以使用不同的外观对象为组件设置外观。
4.3 流程:设置外观,更新外观。
4.3.1设置外观:UIManager.SetLookAndFeel()。
UIManager.setLookAndFeel(newMetalLookAndFeel());
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
4.3.2更新外观:SwingUtilities.updateComponentTreeUI(组件)。
SwingUtilities.updateComponentTreeUI(f);
4.3.3示例:Swing外观风格
参考:http://tieba.baidu.com/p/1607650603
//Main.java
/**
* Demo
*/
package lee;
import java.awt.*;
importjava.awt.event.*;
importjavax.swing.*;
importjavax.swing.event.*;
importjavax.swing.plaf.metal.MetalLookAndFeel;
importjavax.swing.plaf.nimbus.NimbusLookAndFeel;
/**
* @author sf2gis@163.com
*
*/
public class Main{
static int laf;
/**
*@param args
*/
public static void main(String[] args)
throwsUnsupportedLookAndFeelException {
// TODO Auto-generated method stub
//ew SwingComponent().init();
final JFrame f = new JFrame();
f.setLayout(new FlowLayout());
f.setBounds(30, 30, 200, 200);
f.setVisible(true);
f.setTitle("Hello,World!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//get laf
for(UIManager.LookAndFeelInfoinfo:UIManager.getInstalledLookAndFeels()){
System.out.println(info.getName()+"="+info);
}
//view laf
JButton btn1 = newJButton("btn1");
f.add(btn1);
JCheckBox cb = newJCheckBox("cb");
f.add(cb);
JComboBox<String> combo = newJComboBox<>(new String[]{"aa","bb","cc"});
f.add(combo);
btn1.addActionListener(newActionListener() {
@Override
public voidactionPerformed(ActionEvent e) {
// TODO Auto-generatedmethod stub
try {
switch (laf) {
case 0:
UIManager.setLookAndFeel(newMetalLookAndFeel());
break;
case 1:
UIManager.setLookAndFeel(newNimbusLookAndFeel());
break;
case 2:
UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel");
break;
case 3:
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
break;
case 4:
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel");
break;
default:
break;
}
} catch (UnsupportedLookAndFeelException| ClassNotFoundException | InstantiationException | IllegalAccessException e1){
// TODOAuto-generated catch block
e1.printStackTrace();
}
SwingUtilities.updateComponentTreeUI(f);
System.out.println(laf++);
if(5==laf){
laf=0;
}
}
});
f.pack();
}
}
5 方法:常用组件
5.1 组织结构:AWT的派生增强版,但是结构改变
Object:基类
-|Container:容器
--|Window
---|JWindow
---|JDialog
---|Frame
--|Panel
--|JComponent:基本组件
---|JButton等具体组件
---|JMenuBar:菜单栏
参考:http://blog.sina.com.cn/s/blog_90b03d9201015v05.html
5.2 容器:AWT增强版。
5.2.1关闭按钮自动退出程序:f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
5.3 布局管理器:AWT的扩展。
保留原有的布局,增加了BoxLayout。
5.3.1.1 BoxLayout:GridBagLayout的简化版本。
//Main.java
/**
* Demo
*/
package lee;
importjava.awt.BorderLayout;
importjava.awt.Button;
importjava.awt.CardLayout;
importjava.awt.FlowLayout;
importjava.awt.Frame;
import javax.swing.Box;
import javax.swing.BoxLayout;
/**
* @author sf2gis@163.com
*
*/
public class Main{
/**
*@param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Frame f=new Frame();
f.setLayout(new BorderLayout());
f.setBounds(30,30,200,200);
f.setVisible(true);
f.setTitle("Hello,World!");
Box hori=Box.createHorizontalBox();
hori.add(new Button("1"));
f.add(hori,BorderLayout.NORTH);
Box ver=Box.createVerticalBox();
ver.add(new Button("2"));
f.add(ver,BorderLayout.WEST);
Box ver2=Box.createVerticalBox();
ver2.add(new Button("3"));
ver2.add(new Button("4"));
ver2.add(new Button("5"));
f.add(ver2,BorderLayout.CENTER);
f.pack();
}
}
5.4 事件机制:使用Action扩展Listener,抽象一个动作(不仅仅是响应函数)。
5.4.1目标:抽象的动作,具有快捷键,助记符等,图标等属性,能够执行相关的动作。
5.4.2原理:扩展Listener,将原先的响应函数抽象为一个具体的动作,增加快捷键,助记符等属性和相应的动作。
Action是ActionListener的子接口,一般使用Action的实现类AbstractAction(具有默认实现)作为直接基类。
5.4.3流程:创建Action的子类,设置Action对象属性,设置组件的Action
5.4.3.1 创建AbstractAction的子类:实现ActionPerformed。
class MyAction extends AbstractAction{
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("MyAction1");
}
5.4.3.2 设置Action的对象属性:
mya.putValue(Action.NAME,"xx");
mya.putValue(Action.SHORT_DESCRIPTION,"short_xx");
mya.putValue(Action.LONG_DESCRIPTION,"long_xx");
mya.putValue(Action.ACCELERATOR_KEY,KeyStroke.getKeyStroke('B',InputEvent.CTRL_MASK));
mya.putValue(Action.MNEMONIC_KEY,KeyEvent.VK_A);
mya.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY,1);
5.4.3.3 设置组件的Action:
btn1.setAction(mya);
5.4.3.4 示例
//Main.java
/**
* Demo
*/
package lee;
import java.awt.*;
importjava.awt.event.*;
importjava.beans.PropertyChangeListener;
importjavax.swing.*;
/**
* @author sf2gis@163.com
*
*/
public class Main{
static int laf;
/**
*@param args
*/
public static void main(String[] args)
throwsUnsupportedLookAndFeelException {
// TODO Auto-generated method stub
//ew SwingComponent().init();
final JFrame f = new JFrame();
f.setLayout(new FlowLayout());
f.setBounds(30, 30, 200, 200);
f.setVisible(true);
f.setTitle("Hello,World!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btn1=new JButton();
f.add(btn1);
MyAction mya=new MyAction();
btn1.setAction(mya);
mya.putValue(Action.NAME,"xx");
mya.putValue(Action.SHORT_DESCRIPTION,"short_xx");
mya.putValue(Action.LONG_DESCRIPTION,"long_xx");
mya.putValue(Action.ACCELERATOR_KEY,KeyStroke.getKeyStroke('B',InputEvent.CTRL_MASK));
mya.putValue(Action.MNEMONIC_KEY,KeyEvent.VK_A);
mya.putValue(Action.DISPLAYED_MNEMONIC_INDEX_KEY,1);
JButton btn2=new JButton();
f.add(btn2);
btn2.setAction(mya);
//menu
JMenuBar mb = new JMenuBar();
f.setJMenuBar(mb);
JMenu m = newJMenu("File");
mb.add(m);
JMenuItem miOpen = new JMenuItem();
m.add(miOpen);
miOpen.setAction(mya);
f.pack();
}
}
class MyAction extends AbstractAction{
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("MyAction1");
}
}
5.4.4方法:监听属性变化、设置快捷键等属性。
标签Name:用于设置Button或Menu的文本。,
快捷键:菜单时使用ACCELERATOR_KEY(CTRL+KEY),按钮时使用NMEMINC_KEY(ALT+KEY)。
快捷键助记符:显示NAME的第N(从0开始)个字符作为快捷键符。
Tooltip:SHORT_DESCRIPTION,鼠标悬浮时显示的文字。
5.5 菜单:AWT增强版
5.5.1结构:AWT相同的树形结构。
5.5.2菜单快捷键:使用menuitem.setAccelerator(KeyStroke.getKeyStroke())设置。
5.5.3示例
//main.java
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/**
* Demo
*/
package lee;
import java.awt.*;
importjava.awt.event.*;
importjavax.swing.*;
/**
* @author sf2gis@163.com
*
*/
public class Main{
static int laf;
/**
*@param args
*/
public static void main(String[] args)
throwsUnsupportedLookAndFeelException {
// TODO Auto-generated method stub
//ew SwingComponent().init();
final JFrame f = new JFrame();
f.setLayout(new FlowLayout());
f.setBounds(30, 30, 200, 200);
f.setVisible(true);
f.setTitle("Hello,World!");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar mb = new JMenuBar();
f.setJMenuBar(mb);
JMenu m = newJMenu("File");
mb.add(m);
JMenuItem miOpen = newJMenuItem("Open");
m.add(miOpen);
miOpen.setAccelerator(KeyStroke.getKeyStroke('O',InputEvent.CTRL_MASK));
miOpen.addActionListener(newActionListener() {
@Override
public voidactionPerformed(ActionEvent e) {
// TODO Auto-generatedmethod stub
System.out.println("Open");
}
});
f.pack();
}
}
5.6 工具条:
5.7 示例参见http://blog.csdn.net/aeolus1019/article/details/7980950
6 方法:2D绘图
6.1 目标:绘制2D图形。
6.2 原理:AWT的升级版本,直接对组件绘制(不再使用单独的Canvas对象),默认使用双缓冲,分步绘制(双缓冲-》本身-》边框-》子组件)。
paint()实现双缓冲,并实现对组件本身(paintComponent()),边框(paintBorder()),子组件(paintChildren())的顺序调用。所以一般重写paintComponent()进行组件重绘,重写paint()将破坏双缓冲,并有可能错误使用三个绘制函数。
参考:http://bbs.csdn.net/topics/390585720、Swing源码
6.3 流程:创建组件子类,重写paintComponent,向容器添加组件对象。
6.3.1创建组件子类,重写paintComponet()。
class MyPanel extends JPanel{
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
g.drawOval(0, 0, 100, 100);
g.drawString("abc", 50,50);
System.out.println("xx");
}
6.3.2向容器添加组件对象
MyPanel p = new MyPanel();
p.setBounds(0, 0, 100, 100);
p.setLayout(null);
JButton btn1 = newJButton("xx");
btn1.setBounds(50, 0, 50, 30);
p.add(btn1);
JButton btn2 = newJButton("xx");
btn2.setBounds(0, 70, 50, 30);
p.add(btn2);
f.add(p);
6.3.3示例
//Main.java
package lee;
importjava.awt.Graphics;
importjavax.swing.JButton;
importjavax.swing.JFrame;
importjavax.swing.JPanel;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame f=new JFrame();
f.setBounds(0, 0, 200, 200);
f.setTitle("Hello,World!");
f.setVisible(true);
f.setLayout(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel p = new MyPanel();
p.setBounds(0, 0, 100, 100);
p.setLayout(null);
JButton btn1 = newJButton("xx");
btn1.setBounds(50, 0, 50, 30);
p.add(btn1);
JButton btn2 = newJButton("xx");
btn2.setBounds(0, 70, 50, 30);
p.add(btn2);
f.add(p);
}
}
class MyPanel extends JPanel{
@Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
g.drawOval(0, 0, 100, 100);
g.drawString("abc", 50,50);
System.out.println("xx");
}
}
6.4 升级的画笔Graphics2D:扩展Graphics,提供更加细致和优化的控制。
参考:http://blog.csdn.net/caixiexin/article/details/6626772
http://akalius.iteye.com/blog/155207
http://www.xuebuyuan.com/447206.html
可以绘制2D图形,抗锯齿等。
使用时由Graphics转换得到。
示例
//Main.java
package lee;
importjava.awt.Graphics;
importjava.awt.Graphics2D;
importjava.awt.RenderingHints;
importjava.awt.geom.Rectangle2D;
importjavax.swing.JButton;
importjavax.swing.JFrame;
importjavax.swing.JPanel;
public class Main{
public static void main(String[] args) {
// TODO Auto-generated method stub
JFrame f=new JFrame();
f.setBounds(0, 0, 200, 200);
f.setTitle("Hello,World!");
f.setVisible(true);
f.setLayout(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel p = new MyPanel();
p.setBounds(0, 0, 100, 100);
p.setLayout(null);
JButton btn1 = newJButton("xx");
btn1.setBounds(50, 0, 50, 30);
p.add(btn1);
JButton btn2 = newJButton("xx");
btn2.setBounds(0, 70, 50, 30);
p.add(btn2);
f.add(p);
}
}
class MyPanelextends JPanel{
@Override
protected void paintComponent(Graphics g){
// TODO Auto-generated method stub
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2d.drawOval(0, 0, 100, 100);
g2d.drawString("abc", 50,50);
Rectangle2D.Float rect=new Rectangle2D.Float(20, 20, 50,50);
g2d.draw(rect);
System.out.println("xx");
}
}
7 示例