- package test.gui.stopwatch;
- import java.awt.BorderLayout;
- import java.awt.Checkbox;
- import java.awt.CheckboxGroup;
- import java.awt.Color;
- import java.awt.Dimension;
- import java.awt.Font;
- import java.awt.Frame;
- import java.awt.Graphics;
- import java.awt.GridLayout;
- import java.awt.Label;
- import java.awt.Panel;
- import java.awt.event.HierarchyBoundsAdapter;
- import java.awt.event.HierarchyEvent;
- import java.awt.event.ItemEvent;
- import java.awt.event.ItemListener;
- import java.awt.event.MouseAdapter;
- import java.awt.event.MouseEvent;
- import java.awt.event.WindowAdapter;
- import java.awt.event.WindowEvent;
- import java.awt.event.WindowStateListener;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- public class MyStopWatch extends Panel implements ItemListener, Runnable
- {
- //用Label作为计时器的主体,直接设置里边的文本即可
- Label label = new Label();
- //记录开始结束时间,默认为0
- long startTime, endTime;
- //记录计时器字体大小,便于动态调整字体大小,增加这个变量的原因下边注释有说明
- int fontSize = 25;
- //构造函数,让类对象一创建出来就具备想要的一些效果和功能
- public MyStopWatch()
- {
- //让自定义组件使用边界布局
- setLayout(new BorderLayout());
- //再用一个Label组件显示提示信息
- Label notic = new Label("在黑色区域按下鼠标开始计时,松开停止,单选按钮改变文字颜色");
- //设置提示文字颜色
- notic.setForeground(Color.RED);
- //设置提示文字对齐方式,居中
- notic.setAlignment(Label.CENTER);
- //设置提示文字字体
- notic.setFont(new Font("楷体_GB2312", Font.BOLD, 12));
- //将提示文字Label加入到自定义组件上方
- add(notic, "North");
- //将计时器主体Label加到自定义组件的中间
- add(label, "Center");
- //设置计时器的文本对齐方式
- label.setAlignment(Label.CENTER);
- //定义一个选择框组,管理用于改变颜色的一组单选按钮
- CheckboxGroup checkgroup = new CheckboxGroup();
- //创建3个颜色单选按钮,添加到同一个组中
- Checkbox cb_green = new Checkbox("绿色", false, checkgroup);
- Checkbox cb_red = new Checkbox("红色", true, checkgroup);
- Checkbox cb_white = new Checkbox("白色", false, checkgroup);
- //定义一个单独的Panel,集中存放单选按钮
- Panel checks = new Panel();
- //设置单选按钮区域的前景色和背景色
- checks.setBackground(Color.BLACK);
- checks.setForeground(Color.GREEN);
- //设置单选按钮区域的字体
- checks.setFont(new Font("楷体_GB2312", Font.BOLD, 15));
- //设置单选按钮面板的布局方式为网格布局,添加一列三行按钮
- checks.setLayout(new GridLayout(3, 1));
- checks.add(cb_green);
- checks.add(cb_red);
- checks.add(cb_white);
- //将颜色选择面板加入到自定义组件的右边
- add(checks, "East");
- //为3个单选按钮添加事件监听器,自定义组件本身已经实现了ItemListener接口
- //其本类对象就可以作为监听器对象使用
- cb_green.addItemListener(this);
- cb_red.addItemListener(this);
- cb_white.addItemListener(this);
- //**为计时器添加一个监听器,用来检测大小改变,以实现动态改变文字大小
- //查来查去发现好像这个才能实现吧。试过后确实可以,开工了
- label.addHierarchyBoundsListener(new HierarchyBoundsAdapter()
- {
- public void ancestorResized(HierarchyEvent e)
- {
- //System.out.println("大小变了");
- //看看哪个方法可以获取到窗口大小,找到了,第一次width:321,
- //字体大小也需要定义一个变量进行保存,和设置颜色类似,初始为25
- //int height = label.getHeight();
- //得到计时器的宽度,这里根据宽度计算字体大小
- int width = label.getWidth();
- //System.out.println("Width:"+width+"--Height:"+height);
- fontSize = width/12;
- //字体大小改变后,进行重绘
- repaint();
- }
- });
- //为计时器添加鼠标监听器,实现计时功能
- label.addMouseListener(new MouseAdapter()
- {
- //鼠标按下时的处理方式
- public void mousePressed(MouseEvent e)
- {
- //记录一下,表示鼠标已经按下,可以刷新时间值了
- isPressed = true;
- //开启线程,不断刷新时间值,以便实现时间动态显示的效果
- new Thread(MyStopWatch.this).start();
- //开始计时
- startTime = endTime = System.currentTimeMillis();
- //重绘组件,以免上次的时间值遗留在组件表面
- repaint();
- }
- //鼠标释放时的处理方式
- public void mouseReleased(MouseEvent e)
- {
- //将结束时间置为当前时间
- endTime = System.currentTimeMillis();
- //改变标记值,停止刷新
- isPressed = false;
- //再次重绘,将最后的时间值刷一下
- repaint();
- }
- });
- }
- //定义一个记录颜色值的变量,默认红色,便于颜色的动态改变
- Color color = Color.RED;
- //覆盖paint方法,实现自定义的重绘效果
- public void paint(Graphics g)
- {
- //定义SimpleDateFormat对象,便于将时间值进行格式化
- SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
- //计算鼠标按下到释放耗用的时间,因为计算机内部时间表示方式的差异,
- //与我们想要的效果(刚开始显示00:00:00)相差了8个小时,所以减掉8个小时
- Date costTime = new Date(endTime-startTime-8*60*60*1000);
- //将耗用的时间值格式化为我们想要的字符串形式
- String strTime = sdf.format(costTime);
- //设置计算器的背景色为黑色,前景色动态获取
- label.setBackground(Color.BLACK);
- label.setForeground(color);
- //设置计时器表面字体
- label.setFont(new Font("楷体_GB2312", Font.BOLD, fontSize));
- //将时间值显示在计算器表面
- label.setText(strTime);
- }
- //实现ItemListener接口中的方法,让自定义组件具有监听器功能
- public void itemStateChanged(ItemEvent e)
- {
- //定义一个Checkbox变量,记录产生事件的具体对象
- Checkbox cb = (Checkbox)e.getItemSelectable();
- //获取事件源表面的文字信息,便于对比和进行相应设置
- String strColor = cb.getLabel();
- if (strColor!=null)//如果获取到的信息不为空,应该不会空吧
- {
- //根据单选按钮表面的文字信息,动态修改计时器的前景色
- if (strColor.equals("绿色"))
- {
- color = Color.GREEN;
- label.setForeground(Color.GREEN);
- }
- else if (strColor.equals("白色"))
- {
- color = Color.WHITE;
- label.setForeground(Color.WHITE);
- }
- else
- {
- color = Color.RED;
- label.setForeground(Color.RED);
- }
- }
- }
- //定义标记变量,记录鼠标按下状态,默认没有按下
- boolean isPressed = false;
- //实现Runnable接口,复写其中的run方法,让自定义组件具有自动运行指定任务的功能
- public void run()
- {
- //判断鼠标状态,如果按下就开始执行任务
- while (isPressed)
- {
- //让线程稍微休息一会,不能休息太长时间了,不然就不能实现较好的动态效果了
- try
- {
- Thread.sleep(500);
- } catch (InterruptedException e)
- {
- e.printStackTrace();
- }
- //将结束时间修改为当前时间,以便重绘后达到动态显示时间的效果
- endTime = System.currentTimeMillis();
- //对组件进行重绘,更新时间值
- repaint();
- }
- }
- //主函数,测试使用,也可以直接新建一个类,在Frame中加入一个此类对象
- public static void main(String[] args)
- {
- Frame frame = new Frame("My own StopWatch");
- //在窗口中加入一个上边的自定义组件
- frame.add(new MyStopWatch());
- frame.setSize(380, 180);
- //设置窗口最小值,以免用户调的太小,组件都挤不下难看死了
- frame.setMinimumSize(new Dimension(380, 180));
- //固定大小,用户不可调整
- //frame.setResizable(false);
- //给窗口添加窗口监听器,处理窗口事件
- frame.addWindowListener(new WindowAdapter()
- {
- //指定默认关闭事件处理方式
- public void windowClosing(WindowEvent e)
- {
- System.exit(0);
- }
- //想通过这个事件来动态调整计时器内的文本大小,发现这个好像没什么效果,
- //不知道具体有什么用,文档中只是简单地说状态i改变,到底什么状态呢
- public void windowStateChanged(WindowEvent e)
- {
- System.out.println("窗口大小改变了");
- }
- });
- //发现这个只有在最大化、最小化时起效果
- frame.addWindowStateListener(new WindowStateListener()
- {
- public void windowStateChanged(WindowEvent e)
- {
- System.out.println("窗口状态改变了");
- }
- });
- //设置窗口左上角的小图标
- //frame.setIconImage(frame.getToolkit().createImage("c:/logo.jpg"));
- frame.setVisible(true);
- }
- }
复制代码 |