Java很神奇 用swing制作欢迎屏幕
以下资料为广州java培训整理
几乎所有时髦的应用都有一个欢迎屏幕。欢迎屏幕既是宣传产品的方法之一,而
且在长时间的应用启动过程中,欢迎屏幕还用来
示应用正在准备过程中。现在
教你怎么用java中的swing技术制作一个时髦的欢迎屏幕.
下面是一个最简单的欢迎屏幕实现:
Java代码
class SplashWindow1 extends JWindow
{
public SplashWindow1(String filename, Frame f)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
setVisible(true);
screenSize = null;
labelSize = null;
}
}
SplashWindow1类从Swing的JWindow派生。JWindow是一个容器,它没有
其他窗口所具有的各种窗口元素,如标
条、窗口管理按钮,甚至连突出显示的
边框也没有。因此,JWindow对于制作欢迎屏幕来说是非常合适的。上面的代码
假定图形文件在当前目录。图形通过ImageIcon装入内存,然后它就被放到了
JWindow的中心。接着,窗口被pack(),这使得Swing把窗口调整到适当的大小,
最后窗口被移到了屏幕的中心。
如果我们运行上面的程序,可以发现虽然欢迎画面确实出现在屏幕中央,但
遗憾的,它却不会关闭~要关闭欢迎画面,我们需要加入更多的代码: Java代
码
class SplashWindow2 extends JWindow
{
public SplashWindow2(String filename, Frame f)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
setVisible(false);
dispose();
}
});
setVisible(true);
}
}
和原先的SplashWindow1类相比,这个SplashWindow2类唯一的区别在于多出了一个安装到JWindow上的匿名MouseListener。经过这个改动之后,用户可以点击欢迎屏幕关闭它。
现在我们有了一个很不错的欢迎屏幕,它可以通过点击的方法关闭,但它不会自己消失。接下来我们要加入代码,使得欢迎屏幕在显示一定的时间之后自动消失。这里我们要考虑到运用线程。
Java代码
class SplashWindow3 extends JWindow
{
public SplashWindow3(String filename, Frame f, int waitTime)
{
super(f);
JLabel l = new JLabel(new ImageIcon(filename));
getContentPane().add(l, BorderLayout.CENTER);
pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
Dimension labelSize = l.getPreferredSize();
setLocation(screenSize.width/2 - (labelSize.width/2),
screenSize.height/2 - (labelSize.height/2));
addMouseListener(new MouseAdapter()
{
public void mousePressed(MouseEvent e)
{
setVisible(false);
dispose();
}
});
final int pause = waitTime;
final Runnable closerRunner = new Runnable()
{
public void run()
{
setVisible(false);
dispose();
}
};
Runnable waitRunner = new Runnable()
{
public void run()
{
try
{
Thread.sleep(pause);
SwingUtilities.invokeAndWait(closerRunner);
}
catch(Exception e)
{
e.printStackTrace();
// 能够捕获InvocationTargetException
// 能够捕获InterruptedException
}
}
};
setVisible(true);
Thread splashThread = new Thread(waitRunner, "SplashThread");
splashThread.start();
}
}
这里的基本思路是利用一个在一定时间内暂停等待的Thread对象。在上面的代码中,线程的暂停时间是4秒。当这个线程唤醒时,它将关闭欢迎屏幕。由于Swing是非线程安全的,除非代码在事件分派线程上执行,否则它就不应该影响任何UI组件的状态。所谓事件分派线程,就是Swing中负责绘图和事件处理的线程。
为了解决这个问题,Swing设计者赋予我们安全地把Runnable对象加入UI事件队列的能力。在本例中,我们用可运行对象closerRunner完成最关键的工作。我们把可运行对象传入SwingUtilities.invokeAndWait()静态方法,然后wingUtilities.invokeAndWait()进行所有未完成的UI操作,并执行传递给该方
法的可运行对象closerRunner的run方法。通过运用一个独立的线程负责欢迎屏幕的关闭操作,应用担负起了显示和关闭欢迎屏幕之间的所有操作。
如果要让欢迎屏幕总是显示且用户不能关闭它,你必须删除那些隐藏欢迎屏幕的代码。如果要让欢迎屏幕只能由用户手工关闭,你可以象使用任何其他JWindow对象一样调用SplashWindow3对象上的setVisible(false)和dispose()方法。
总而言之,借助于SwingUtilities.invokeAndWait()方法,我们可以安全地创建出多线程欢迎屏幕。具体实现时,欢迎屏幕可以由用户点击关闭,也可以在一定的时间之后自动关闭。Swing所支持的线程模型使得应用在显示欢迎屏幕之后仍能够响应其他事件和处理其他任务。
文以spring框架的XmlBeanFactory为入手点进行
,希望能够以尽量简
洁明了的方式给予有需要的朋友一定的帮助。
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new
XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
这个类的代码很简单,一个成员对象加两个构造函数,从这里我们可以看出,最
重要的地方在于最后一个构造函数:
第一句就是将父亲工厂交给父类的构造函数,实际上最后也就是把父工厂保
存到类的parentBeanFactory成员对象中,这个对象是在AbstractBeanFactory抽象类中定义的,而这个父工厂也会一直传递到该抽象类进行保存。第二句就是
整个类中最重要的地方了,顾名思义,它的目的是通过
XmlBeanDefinitionReader这个XML的Reader从资源resource中(也就是你的
配置文件)读取bean的定义。接下来我们打开XmlBeanDefinitionReader的
loadBeanDefinitions方法,我们可看到在这个方法里代码就一行,调用了一个
同名不同参的方法,而参数是EncodedResource的一个实例,这个类实际上是
Resource的一个包装类,用来保存资源的Encode的,那接下来我们再看被调用
的loadBeanDefinitions方法,这个方法里最主要的部分就是:
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
这里的目的是将资源包装成一个InputSource,连同Resource作为参数传
递到doLoadBeanDefinitions方法
DocumentBuilderFactory factory = createDocumentBuilderFactory();
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP implementation [" + factory + "]");
}
DocumentBuilder builder = createDocumentBuilder(factory);
Document doc = builder.parse(inputSource);
return registerBeanDefinitions(doc, resource);
这个方法的目的一目了然,就是为了将资源解释成为Document对象,然后
调用registerBeanDefinitions方法,这里不做详细解释,不了解的话请去看看
关于JAXP的介绍。接下来我们打开registerBeanDefinitions方法:
public int registerBeanDefinitions(Document doc, Resource resource)
throws BeansException {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser)
BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
这里创建了一个XmlBeanDefinitionParser接口的实现,这个接口的具体类
是DefaultXmlBeanDefinitionParser,这个接口很简单,只有
registerBeanDefinitions一个方法,这个方法的作用也很明了,就是用来注册
Bean的定义的,所以说类和方法的名字一定要起得有意义,这样可以让人一看
就大概了解其作用,减少了很多阅读代码的痛苦。废话不多说,我们打开
DefaultXmlBeanDefinitionParser的registerBeanDefinitions方法,这个类
就是解释XML配置文件的核心类了,打开registerBeanDefinitions方法后我们
看到如下代码:
public int registerBeanDefinitions(BeanDefinitionReader reader,
Document doc, Resource resource)
throws BeanDefinitionStoreException {
this.beanDefinitionReader = reader;
this.resource = resource;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//初始化根元素
initDefaults(root);
if (logger.isDebugEnabled()) {
logger.debug("Default lazy init '" + getDefaultLazyInit() + "'");
logger.debug("Default autowire '" + getDefaultAutowire() + "'");
logger.debug("Default dependency check '" + getDefaultDependencyCheck() + "'");
}
preProcessXml(root);//一个空方法用于扩展
int beanDefinitionCount = parseBeanDefinitions(root);//解释配置的
主要方法
if (logger.isDebugEnabled()) {
logger.debug("Found " + beanDefinitionCount + "
elements in
" + resource);
}
postProcessXml(root); //一个空方法用于扩展
return beanDefinitionCount;
}
在这个方法当中,主要用于解释定义的有两个方法,一个是initDefaults,
一个是parseBeanDefinitions,第一个方法是用来解释根元素的属性的,例如
lazy-init, autowire等,而parseBeanDefinitions就是用来解释具体的bean
定义了,方法代码如下:
protected int parseBeanDefinitions(Element root) throws
BeanDefinitionStoreException {
NodeList nl = root.getChildNodes();
int beanDefinitionCount = 0;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (IMPORT_ELEMENT.equals(node.getNodeName())) {
importBeanDefinitionResource(ele);
}
else if (ALIAS_ELEMENT.equals(node.getNodeName())) {
String name = ele.getAttribute(NAME_ATTRIBUTE);
String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
this.beanDefinitionReader.getBeanFactory().registerAlias(name, alias);
}
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele,
false);
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.beanDefinitionReader.getBeanFactory());
}
}
}
return beanDefinitionCount;
}
其他标签具体如何被解释这里就不多说,相信大家也能看得懂,这里主要讲一下
解释bean的的处理,我们注意以下代码:
else if (BEAN_ELEMENT.equals(node.getNodeName())) {
beanDefinitionCount++;
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele,
false);
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,
this.beanDefinitionReader.getBeanFactory());
}
这里是当碰到一个bean标签的时候所进行的处理,也既是对bean的定义进
行解释,可以看到parseBeanDefinitionElement方法的第一个参数就是bean
则个元素,第二个参数表示该bean是否为内置的bean,从这里进行解释的bean
都不可能是内置的,所以这里直接以false为参数,打开
parseBeanDefinitionElement方法,就可以看到这个方法里就是对bean的内部
的解释,也很简单,也不多讲了,呵呵(下班时间已经到了,所以就写这么多了,
基本的流程也就这样,没什么特别难的地方。),对了,最后还有一点就是解释
完后,bean的定义将会被保存到beanFactory中,这个beanFactory的实现就
是XmlBeanFactory了,该beanFactory是在new的时候被传递到reader中的,
就是该类中以下这行代码:
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);