JAVA基础学习day23--GUI基础
一、GUI概述
1.1、GUI概述
Graphical User Interface(图形用户接口)
用图形的方式,来显示计算机操作的界面,
CLI:
Command line User Interface(命令行用户接口)
如DOS,
java为GUI提供的对象都存在java.Awt和javax.Swing两个包中.
1.2、Awt与Swing
java.Awt:Abstract Window ToolKit(抽象窗口工具包)需要调用本地系统方法实现功能。属于重量级级控件
javax.Swing:在AWT的基础上,建立的一套图形界面系统,其中提供了更多的组件,而且完全由Java实现。增强了移植必,属于轻量级控件。
1.3、结构
二、布局管理器
2.1、布局
容器中的组件的排放方式,就是布局。
2.2、常见的布局管理
FlowLayout(流式布局管理器)
从左到右的顺序排列
Panel默认的布局管理器。
BorderLayout(边界布局管理器)
东、南、西、北、中
Fram默认的面布局管理器。
GridLayout(网格布局管理器)
规则的矩阵
CardLayout(卡片布局管理器)
选项卡
GridBagLayout(网络包布局管理器)
非规则的矩阵
2.3、
import java.awt.*;
public class AwtDemo1 { public static void main(String[] args) {
//声明一个容器,Frame并设置标题
Frame f=new Frame("Hello World");
//设置窗体大小第一个参数是宽度,第二个参数是高度
f.setSize(600, 300);
//设置窗体运行的位置,屏幕中显示的位置
f.setLocation(400, 200);
//设置窗体布局方式,默认为BorderLayout,设置为流式布局
f.setLayout(new FlowLayout()); //声明新的控件
Button btn=new Button("按键");
//将控件添加到窗体
f.add(btn); //设置窗体可见,默认是不可见的
f.setVisible(true); } }
三、事件
3.1、事件监听机制
事件源(组件)awt包或者swing中的那些图形界面组件
事件(Event):每一个事件源都自己的特有的对应的事件和共性事件
监听器(Listener):将可以触发某一个事件的动作(不只一个动作)都已经封闭到了监听器中.
以上3种,都在java中已经定义好了,直接获取对象用使用就可以
事件处理(引发事件后处理方式):我们要做的事情是,就是产生的动作进行处理.
3.2、事件监听机制特点
3.3、 示例
WindowsListener 接口有7个方法要重写,一般为直接实现而使用其子类
WindwoAdapter()
接收窗口事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。
扩展此类可创建 WindowEvent
侦听器并为所需事件重写该方法。(如果要实现 WindowListener
接口,则必须定义该接口内的所有方法。此抽象类将所有方法都定义为 null,所以只需针对关心的事件定义方法。)
只需要继承 WindwoAdapter类,实现需要的方法即可
import java.awt.*;
import java.awt.event.*;
public class AwtDemo1 { public static void main(String[] args) {
//声明一个容器,Frame并设置标题
Frame f=new Frame("Hello World");
//设置窗体大小第一个参数是宽度,第二个参数是高度
f.setSize(600, 300);
//设置窗体运行的位置,屏幕中显示的位置
f.setLocation(400, 200);
//设置窗体布局方式,默认为BorderLayout,设置为流式布局
f.setLayout(new FlowLayout()); //声明新的控件
Button btn=new Button("按键");
//添加监听事件 //将控件添加到窗体
f.add(btn); //设置窗体可见,默认是不可见的
f.setVisible(true);
//添加监听器
f.addWindowListener(new MyWinEvent()); } }
class MyWinEvent extends WindowAdapter{ @Override
public void windowActivated(WindowEvent e) {
// 激活窗口时调用
super.windowActivated(e);
System.out.println("我被激活了");
} @Override
public void windowClosed(WindowEvent e) {
// 当窗口已被关闭时调用
super.windowClosed(e);
System.out.println("我被关闭了");
} @Override
public void windowClosing(WindowEvent e) {
// 窗口正处在关闭过程中时调用。
super.windowClosing(e);
System.out.println("我正在被关闭");
} @Override
public void windowDeactivated(WindowEvent e) {
// 停用窗口时调用。
super.windowDeactivated(e);
System.out.println("我被停用了");
} @Override
public void windowDeiconified(WindowEvent e) {
// 取消图标化窗口时调用
super.windowDeiconified(e);
System.out.println("取消图标化窗口"); } @Override
public void windowGainedFocus(WindowEvent e) {
// 该 Window 被设置为聚焦 Window 时调用,聚焦 Window 意味着该 Window 或其某个子组件将接收键盘事件。
super.windowGainedFocus(e);
System.out.println("获取焦点");
} @Override
public void windowIconified(WindowEvent e) {
//图标化窗口时调用。
super.windowIconified(e);
System.out.println("图标化窗口时调用。");
} @Override
public void windowLostFocus(WindowEvent e) {
// 该 Window 不再为聚焦 Window 时调用,不再为聚焦 Window 意味着键盘事件不再传递到该 Window 或其任意子组件。
super.windowLostFocus(e);
System.out.println("失去焦点");
} @Override
public void windowOpened(WindowEvent e) {
//已打开窗口时调用。
super.windowOpened(e);
System.out.println("窗口打开了");
} @Override
public void windowStateChanged(WindowEvent e) {
// 窗口状态改变时调用。
super.windowStateChanged(e);
System.out.println("窗口状态改变时调用。");
} }
四、Action事件
4.1、Action事件
addActionListener(ActionListener l)
添加指定的动作侦听器,以接收发自此按钮的动作事件
只有一个方法
actionPerformed(ActionEvent e)
发生操作时调用。
用于接收操作事件的侦听器接口。对处理操作事件感兴趣的类可以实现此接口,而使用该类创建的对象可使用组件的 addActionListener
方法向该组件注册。在发生操作事件时,调用该对象的 actionPerformed
方法。
4.2、示例
import java.awt.*;
import java.awt.event.*;
class ActionDemo
{
public static void main(String[] args)
{
new FrameDemo();
}
}
class FrameDemo
{
//定义成员变量frame和Button
private Frame f;
private Button btn;
public FrameDemo()
{
init();
}
public void init()
{
//初始人成员变量,并设置初始值
f=new Frame("我的Frame窗体");
//设置窗口位置水平与垂直坐标,宽度与高度
f.setBounds(200,200,600,500);
//
f.setLocation(400,100);
//可见的
f.setVisible(true);
//设置布局
f.setLayout(new FlowLayout()); //给窗体添中监听器,事件
myEvent();
btn=new Button("我的按键");
//添控件添加到frame窗体上
f.add(btn);
//给按键添加Action事件
btn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.out.println("按键事件!,按键关闭窗口");
System.exit(0);
}
});
}
//事件方法
private void myEvent()
{
//添加事件
f.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e)
{
System.out.println("myFram 关闭");
System.exit(0);
}
}); }
}
五、鼠标、键盘与对话框事件
5.1、示例
/*
鼠标与键盘事件
*/
import java.awt.*;
import java.awt.event.*;
class AwtDemo3
{
public static void main(String[] args)
{
new mouseAndKey();
}
}
class mouseAndKey
{
private Frame f;
private Button btn;
private TextField tf;
public mouseAndKey()
{
init();
}
//初始化
public void init()
{
f=new Frame("My Frame");
btn=new Button("My Button");
//指定列数
tf=new TextField(20);
//设置位置,大小
f.setBounds(200,300,500,400);
f.setLayout(new FlowLayout()); //流式布局 f.add(btn);
f.add(tf);
f.setVisible(true);
//为窗口添加监听器
myEvent();
//添加鼠标监听器
addMouseEvent();
//添加键盘监听器
addMykeyEvent();
//添加文件框监听器
addTfEvent();
}
//窗口监听器
private void myEvent()
{
f.addWindowListener(new WindowAdapter(){
//添加关闭事件
public void windowClosing(WindowEvent e)
{
System.out.println("窗口关闭了");
System.exit(0);
}
});
}
//添加鼠标事件
private void addMouseEvent()
{ btn.addActionListener(new ActionListener(){
//活动状态
public void actionPerformed(ActionEvent e){
System.out.println("窗口活动状态action");
}
});
//添加鼠标监听器
btn.addMouseListener(new MouseAdapter(){
/*
int clickedCount=1;
//单击事件
public void mouseClicked(MouseEvent e)
{
System.out.println("鼠标单击"+clickedCount++);
}
});
*/
//双击事件 int doubleClickCount=1;
public void mouseClicked(MouseEvent e)
{
if (e.getClickCount()==2)
{
System.out.println("鼠标双击"+doubleClickCount++);
} } //鼠标进入事件
int count=1;
public void mouseEntered(MouseEvent e)
{ System.out.println("鼠标进入控件"+count++);
}
}); }
private void addMykeyEvent()
{
btn.addKeyListener(new KeyAdapter(){
//按下某个键时调用此方法 public void keyPressed(KeyEvent e)
{
//System.out.println("按下:"+KeyEvent.getKeyText(e.getKeyCode())+"...."+e.getKeyCode());
/*
//按下esc键关闭窗口
if(e.getKeyCode()==KeyEvent.VK_ESCAPE)
{
System.exit(0);
}
*/
if(e.isControlDown()&&e.getKeyCode()==KeyEvent.VK_ENTER)
{
System.out.println("ctrl+enter");
} }
//释放某个键时调用此方法。 public void keyReleased(KeyEvent e)
{
//System.out.println("释放:"+KeyEvent.getKeyText(e.getKeyCode())+"...."+e.getKeyCode());
} //键入某个键时调用此方法。 public void keyTyped(KeyEvent e)
{
//System.out.println("输入:"+KeyEvent.getKeyText(e.getKeyCode())+"...."+e.getKeyCode()); }
});
}
private void addTfEvent(){
tf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e)
{
int code=e.getKeyCode();
if(!(code>=KeyEvent.VK_0 && code<=KeyEvent.VK_9))
{
System.out.println(code+"....是不合法的!");
//不能输入进去
e.consume();
}
}
}); }
}
示例、
/*
在文本框中输入目录,点击转到 按键,将该目录中的文件与文件
夹名称列在下面的文本区域中
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
class TextFieldDemo
{
public static void main(String[] args)
{
new MyTextField();
}
}
/*
private Frame f; 窗体
private Button btn; 按键
private TextField tf; 文本框
private TextArea ta; 多行文本域
private Dialog d; 对话框
private Label lab; 文本信息
private Button okBtn; 确定按键
*/
class MyTextField
{
private Frame f;
private Button btn;
private TextField tf;
private TextArea ta;
private Dialog d;
private Label lab;
private Button okBtn;
public MyTextField()
{
init();
}
//初始化
public void init()
{
f=new Frame("根据目录列出所有文件");
f.setBounds(300,100,600,500);
f.setLayout(new FlowLayout());
tf=new TextField(30);
btn=new Button("转到");
ta=new TextArea(20,50);
/*
提示窗口
*/
d=new Dialog(f,"提示信息",true);
lab=new Label();
okBtn=new Button("确定");
d.add(lab);
d.add(okBtn);
d.setBounds(400,200,240,150);
d.setLayout(new FlowLayout()); //将控件添回到窗体
f.add(tf);
f.add(btn);
f.add(ta); //设置窗体可见
f.setVisible(true);
//添加事件
myEvent();
}
public void myEvent()
{
//窗体监听器,
f.addWindowListener(new WindowAdapter(){
//关闭事件
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
//文本框添加事件监听,输入完成,敲回车执行
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
{
//调用
showDir();
}
}
}
); //按键添加监听器,事件输入完成,点按键执行
btn.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//调用显示
showDir();
}
}
);
//对话框事件
//窗体监听器,
d.addWindowListener(new WindowAdapter(){
//关闭事件
public void windowClosing(WindowEvent e)
{ //将对话框隐藏
d.setVisible(false);
}
});
okBtn.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{//将对话框隐藏
d.setVisible(false);
}
});
}
private void showDir()
{
//获取文本框输入的内容
String dirPath=tf.getText();
//封装为文件
File dir=new File(dirPath);
//判断是不是目录同时是否存在
if(dir.exists()&&dir.isDirectory())
{ //存在并且目录存在就把多行文本框清空
ta.setText("");
//获取文件列表
File [] files=dir.listFiles();
for(File f:files)
{
//向多行文本域中添加内容,增加
ta.append(f.getName()+"\n");
}
}else
{
//对话框信息设置
String info="您输入的路径:"+dirPath+" 是错误的请重新输入";
lab.setText(info);
//对话框显示
d.setVisible(true); }
//将文本框清空
tf.setText("");
}
}
六、菜单
6.1、示例
/*
菜单:
private Frame f; 窗体
private MenuBar mb; 菜单栏
private Menu m; 菜单
private MenuItem closeItem; 菜单项关闭菜单
*/
import java.awt.*;
import java.awt.event.*; class MenuDemo
{
private Frame f;
private MenuBar mb;
private Menu m;
private Menu subMenu;//子菜单的子菜单
private MenuItem closeItem;
private MenuItem subItem; //子菜单条目属于subMenu的子菜单项
//构造方法
public MenuDemo()
{
init();
}
/*
初始化
*/
public void init()
{
//窗体
f=new Frame("有菜单的窗体");
//设置位置,宽,高
f.setBounds(300,100,500,400);
//布局
f.setLayout(new FlowLayout());
//菜单栏
mb=new MenuBar(); //菜单
m=new Menu("文件");
subMenu=new Menu("子菜单");
//菜单项
closeItem=new MenuItem("退出");
subItem=new MenuItem("子菜单条目"); //菜单添加菜单项
subMenu.add(subItem);
m.add(subMenu);
m.add(closeItem); //菜单栏添加菜单
mb.add(m);
//窗体设置菜单栏
f.setMenuBar(mb);
//设置显示
f.setVisible(true);
myEvent();
}
/*
设置监听器
*/
private void myEvent()
{
/*
通过右上角X关闭窗体
*/
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
System.out.println("通过关闭X退出,这个窗体");
System.exit(0);
}
}); /*
通过菜单退出
*/
closeItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.out.println("通过菜单退出,这个窗体");
System.exit(0);
}
});
} /*
测试
*/
public static void main(String[] args)
{
new MenuDemo ();
}
}
七、打开与关闭文件
7.1、示例,添加打开菜单项
FileDialog
public FileDialog(Frame parent,
String title,
int mode)
- 创建一个具有指定标题的文件对话框窗口,用于加载或保存文件。
如果
mode
的值为LOAD
,那么文件对话框将查找要读取的文件,所显示的文件是当前目录中的文件。如果mode
的值为SAVE
,则文件对话框将查找要写入文件的位置。- 参数:
parent
- 对话框的所有者title
- 对话框的标题mode
- 对话框的模式,可以是FileDialog.LOAD
或FileDialog.SAVE
-
/*
菜单:
private Frame f; 窗体
private MenuBar mb; 菜单栏
private Menu m; 菜单
private MenuItem openItem; 打开
private MenuItem closeItem; 关闭
private MenuItem saveItem;保存
//构造方法
*/
package mymenu;
import java.awt.*;
import java.awt.event.*;
import java.io.*; public class MenuDemo1
{
private Frame f;
private MenuBar mb;
private Menu fileMenu;
private MenuItem openItem;
private MenuItem closeItem;
private MenuItem saveItem;
private FileDialog openDia; //打开对话框
private FileDialog saveDia;//保存对话框
private TextArea ta;
private File file;
//构造方法
public MenuDemo1()
{
init();
}
/*
初始化
*/
public void init()
{
//窗体
f=new Frame("有菜单的窗体");
//设置位置,宽,高
f.setBounds(300,100,650,500);
//布局
//f.setLayout(new FlowLayout());
//菜单栏
mb=new MenuBar();
//菜单
fileMenu=new Menu("文件");
//菜单项
openItem=new MenuItem("打开");
saveItem=new MenuItem("保存");
closeItem=new MenuItem("退出");
//菜单添加菜单项
fileMenu.add(openItem); //添加打开
fileMenu.add(saveItem); //添加保存
fileMenu.add(closeItem); //添加关闭
//菜单栏添加菜单
mb.add(fileMenu);
//窗体设置菜单栏
f.setMenuBar(mb);
//打开,关闭对话框
openDia=new FileDialog(f,"打开",FileDialog.LOAD);
saveDia=new FileDialog(f,"保存",FileDialog.SAVE);
ta=new TextArea(); f.add(ta);
myEvent();
//设置显示
f.setVisible(true); }
/*
设置监听器
*/
private void myEvent()
{
/*
通过右上角X关闭窗体
*/
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
System.out.println("通过关闭X退出,这个窗体");
System.exit(0);
}
});
/*
打开
*/
openItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
openDia.setVisible(true);
show();
}
});
/*
保存
*/
saveItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
save(); }
}); /*
通过菜单退出
*/
closeItem.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.out.println("通过菜单退出,这个窗体");
System.exit(0);
}
});
}
private void show()
{
String dirPath=openDia.getDirectory(); //路径
String fileName=openDia.getFile();//文件名
//打印路径
System.out.println(dirPath+"..."+fileName); if(dirPath==null || fileName==null)
return;
ta.setText("");
File file=new File(dirPath,fileName); //封装为文件
BufferedReader br=null;
try{
br=new BufferedReader(new FileReader(file));
String line=null; while((line=br.readLine())!=null)
{
ta.append(line+"\n");
}
}catch(IOException e)
{ }finally{
try
{
if(br!=null)
br.close();
}
catch (IOException e)
{
} }
}
/*
保存
*/
private void save()
{
if(file==null){
//设置
saveDia.setVisible(true);
String dirPath=saveDia.getDirectory(); // 目录
String fileName=saveDia.getFile();//文件
//判断路径和文件名是否为空
if (dirPath==null || fileName==null)//啥也不做
return;
//如果文件为空就,new
file=new File(dirPath,fileName);
} //不为空就直接保存
BufferedWriter bw=null;
try
{ bw =new BufferedWriter(new FileWriter(file));
//获取多行文本框内容
String context=ta.getText();
//System.out.println(context);
bw.write(context);
//bw.flush(); }
catch (IOException e)
{ }finally{
try
{
if (bw!=null)
bw.close(); }
catch (IOException ex)
{
}
}
} /*
测试
*/
public static void main(String[] args)
{
new MenuDemo1 ();
}
}
/*
FileDialog
public FileDialog(Frame parent,
String title,
int mode)创建一个具有指定标题的文件对话框窗口,用于加载或保存文件。
如果 mode 的值为 LOAD,那么文件对话框将查找要读取的文件,所显示的文件是当前目录中的文件。如果 mode 的值为 SAVE,则文件对话框将查找要写入文件的位置。 参数:
parent - 对话框的所有者
title - 对话框的标题
mode - 对话框的模式,可以是 FileDialog.LOAD 或 FileDialog.SAVE
*/ - 八、打包
8.1、将示中打所为jar文件
编译带包的源文件
javac -d F:\java\day22\menu MenuDemo1.java
打包
Manifest-Version: 1.0
Created-By: 1.8.0_60 (Oracle Corporation)
Main-Class: mymenu.MenuDemo1
每个标签冒号后都跟上一个空格
最后一行需要有一个回车键,否则后面那一行是不能打包进去的
没有空格会报
java.io.IOException: invalid header field
at java.util.jar.Attributes.read(Attributes.java:393)
at java.util.jar.Manifest.read(Manifest.java:182)
at java.util.jar.Manifest.<init>(Manifest.java:52)
at sun.tools.jar.Main.run(Main.java:132)
at sun.tools.jar.Main.main(Main.java:1022)
1.txt
Main-Class: mymenu.MenuDemo1
JAVA基础学习day23--GUI基础的更多相关文章
- Java最新学习线路(基础,源码,项目,实战)
如需获取以下学习资源请关注公众号:Java编程指南 我们为自学者编程的或初学java的小伙伴们准备了一整套完整的学习资源和文章,还有我自己在自学路上的一些总结和学习线路,希望能帮到小伙伴们,如果有什么 ...
- java基础学习总结——GUI编程(二)
一.事件监听
- java基础学习总结——GUI编程(一)
一.AWT介绍
- java基础学习总结——GUI编程(二) 未学习
一.事件监听
- java基础学习总结——GUI编程(一) 还未仔细阅读
一.AWT介绍
- 【java基础学习】GUI
GUI 容器 布局管理器 组件 菜单 事件处理机制
- <java基础学习>02JAVA的基础组成
Java的基础组成 1 关键字 (被赋予了特殊含义的单词) 2 标识符 3 注释 4 常量和变量 5 运算符 6 语句 7 函数 8 数组 关键字 class Demo{ public static ...
- java基础学习05(面向对象基础01)
面向对象基础01 1.理解面向对象的概念 2.掌握类与对象的概念3.掌握类的封装性4.掌握类构造方法的使用 实现的目标 1.类与对象的关系.定义.使用 2.对象的创建格式,可以创建多个对象3.对象的内 ...
- java安全学习-环境准备/基础知识
补java的坑,开始! 1.Intellij一些快捷键 intell常用快捷键: ctrl+n 快速查找定位类的位置 ctrl+q 快速查看某个类的文档信息 shift + F6 快速类.变量重命名 ...
- Java开发学习(三)----Bean基础配置及其作用范围
一.bean基础配置 对于bean的基础配置如下 <bean id="" class=""/> 其中,bean标签的功能.使用方式以及id和clas ...
随机推荐
- Scene视图辅助线绘制
有时候需要在Scene视图中绘制一些辅助线,方便进行一些编辑的工作,可以通过如下类和函数完成: 绘制辅助线,相关类: Gizmos类:用于在Scene视图中绘制调试信息或辅助线,这些辅助线只有在Sce ...
- NGUI 动态添加控件
本文链接地址: Unity3D NGUI动态创建按钮 本例仅以熟悉NGUI组件功能为目的,想快捷简便的创建按钮或其它游戏物体请参考 “Unity3D 动态实例化Prefab” 以动态创建服务器列表为例 ...
- WP8 SqlCE和SqlLite数据存储性能比较
在平时的开发中一定会用到本地数据存储,除了独立存储外我们还可以选择SqlCE和SqlLite:于是在选择上我们就必须权衡他们两者的性能择优选择. 测试代码:(这个例子是在msdn sqllite例子上 ...
- [Node.js] Node + Redis 实现分布式Session方案
原文地址: http://www.moye.me/?p=565 Session是什么? Session 是面向连接的状态信息,是对 Http 无状态协议的补充. Session 怎么工作? Sessi ...
- Blocked Process Report
当同个对象上有互斥的锁存在时,查询需要等待很长时间,我们是否可以收到来自SQL Server提醒?答案是可以的,做法非常简单,因为SQL Server为你提供了称为Blocked Process Re ...
- 浅谈DOM性能考虑
浅谈DOM性能考虑 很多人都会忽视脚本对Web应用整体性能的影响.为保证应用的流畅运行,在为文档编写和应用脚本时,需要注意一些问题.一.尽量减少访问DOM和尽量减少标记 访问DOM的方式对脚本性 ...
- Eclipse魔法堂:任务管理器
一.前言 Eclipse的任务管理器为我们提供一个方便的入口查看工程代办事宜,并定位到对应的代码行继续之前的工作. 二.使用示例 示例1: /** * @Descripti ...
- JS魔法堂:属性、特性,傻傻分不清楚
一.前言 或许你和我一样都曾经被下面的代码所困扰 var el = document.getElementById('dummy'); el.hello = "test"; con ...
- 创建一个带模版的用户控件 V.3
再重构此篇<创建一个带模版的用户控件 V.2>http://www.cnblogs.com/insus/p/4164149.html 让其它动态实现header,Item和Footer. ...
- iOS开发之蓝牙通讯
iOS开发之蓝牙通讯 一.引言 蓝牙是设备近距离通信的一种方便手段,在iPhone引入蓝牙4.0后,设备之间的通讯变得更加简单.相关的蓝牙操作由专门的CoreBluetooth.framework进行 ...