Java的簡(jiǎn)單數(shù)字時(shí)鐘
這里是最簡(jiǎn)單的實(shí)現(xiàn)方法,大概思路就是在一個(gè)JComponent上每隔一段時(shí)間進(jìn)行一次重繪,為了保證重繪Timer的執(zhí)行時(shí)間和終了時(shí)間,重寫(xiě)JComponent的addNotify方法和removeNotify方法,最后在DigitalClockUI中重寫(xiě)paint方法來(lái)繪制界面,并且重寫(xiě) getPreferredSize使繪制的內(nèi)容自適應(yīng)界面的大小.
先看看效果:
基本的工程目錄如下:
首先是最基本的界面: Clock,在這個(gè)工程里,這個(gè)類(lèi)作用很小,定義不定義其實(shí)都無(wú)所謂,這兒定義它主要是為了統(tǒng)一,為以后實(shí)現(xiàn)其它時(shí)鐘提供方便
這兒把它定義成抽象的
/**
* This bean to define basic properties and
behaviors of a clock, concrete
* instances will be implemented by <code>DigitalClock</code> and
others.
*/
publicabstractclass Clock extends JComponent {
為它提供幾個(gè)屬性:
/**
* The calendar instance
for this clock.
*/
private Calendar calendar;
/**
* Background image of the
clock.
*/
private Image bgImage;
/**
* Font rendering context - assumes no
default transform, anti-aliasing
* active and fractional
metrics allowed.
*/
publicstaticfinal FontRenderContext frc = new FontRenderContext(null, true, true);
其中FontRenderContext提供了文本顯示和繪制的信息容器.
在構(gòu)造函數(shù)中把calendar初始化:
calendar = Calendar.getInstance();
接著看DigitalClock類(lèi),這個(gè)類(lèi)繼承Clock類(lèi),主要是提供時(shí)鐘計(jì)時(shí)Timer啟動(dòng)和終止的,另外提供了數(shù)字時(shí)鐘的頁(yè)面分隔符信息,以及UI設(shè)置和取得.
首先是定義的屬性:
/**
* divide time.
*/
private String padding1 = "";
private String padding2 = "";
分別代表時(shí)分秒之間的分隔和秒與毫秒之間的分隔.
接著是構(gòu)造函數(shù),提供基本的和帶參數(shù)的兩種:
/**
* Default construct: Uses
default format and appearance.
*/
public DigitalClock() {
super();
setFont(new Font("Arial", Font.BOLD, 20));
setOpaque(true);
padding1 = ":";
padding2 = ".";
setUI(DigitalClockUI.createUI(this));
}
/**
* Constructor: Initializes a digital-type clock by
using given *parameters.
*/
public DigitalClock(String padding1, String padding2, Font
font,
Color fg, Color bg, Locale locale) {
通過(guò)setUI(DigitalClockUI.createUI(this));把新的自定義UI賦給JComponent.
最后通過(guò)addNotify和removeNotify方法復(fù)寫(xiě)啟動(dòng)和終止計(jì)時(shí)Timer
/**
* Invoked when panel is
added to a container.
*/
@Override
publicvoid addNotify() {
super.addNotify();
getUI().start();
}
/**
* Invoked when panel is
removed from a container.
*/
@Override
publicvoid removeNotify() {
getUI().stop();
super.removeNotify();
}
最后就是DigitalClockUI類(lèi)了,它主要提供頁(yè)面的繪制,計(jì)時(shí)Timer的管理和時(shí)間的計(jì)算以及界面大小的調(diào)整功能.
首先是繼承關(guān)系:
publicclass DigitalClockUI extends PanelUI implements
ActionListener {
它通過(guò)繼承PanelUI(其實(shí)就是ComponentUI)實(shí)現(xiàn)時(shí)鐘界面UI管理,實(shí)現(xiàn)ActionListener接口則是為了Swing的Timer.
在構(gòu)造函數(shù)中,把Timer啟動(dòng)
// stopwatch
timer = new Timer(10, this);
仿照其他Component組件提供UI代理,使界面可以設(shè)置UI:
// Create an instance of the
UI delegate for this component
publicstatic ComponentUI createUI(DigitalClock component) {
returnnew DigitalClockUI(component);
}
然后定義類(lèi)使用的屬性:
// Attributed string containing current
time
protected AttributedString timeString = null;
// Text layout of attributed string
protected TextLayout textLayout = null;
// Attributed string containing current timezone.
protected AttributedString timezoneString = null;
// Text layout of attributed timezone.
protected TextLayout textTimezoneLayout = null;
分別定義了繪制時(shí)間和時(shí)區(qū)的字符串屬性格式和布局.
當(dāng)組件加入到容器中呈現(xiàn)時(shí),Timer啟動(dòng),actionPerformed將會(huì)被調(diào)用.
@Override
publicvoid actionPerformed(ActionEvent event) {
在這個(gè)方法里,取得當(dāng)前時(shí)間:
// Create a new attributed
string with the new time
Date current = new Date();
Calendar cal = panel.getCalendar();
cal.setTime(current);
通過(guò)SimpleDateFormat類(lèi)把時(shí)間格式化:
// Hour24 mode
df = new SimpleDateFormat("HH" + panel.getPadding1() + "mm"
+ panel.getPadding1() + "ss", panel.getLocale());
// Draw AM/PM
int tmpLen2 = 0;
// mode
df.applyPattern("a");
// timezone
df.applyPattern("Z");
StringBuffer sb = new StringBuffer("GMT");
sb.append(df.format(current));
sb.insert(6, ":");
df.applyPattern("zzzz");
然后將格式化好的時(shí)間字符串通過(guò)AttributedString設(shè)置顯示格式:
timeString = new AttributedString(str);
// Render main time area
timeString.addAttribute(TextAttribute.FONT, font, 0, 6 + 2 * panel
.getPadding1().length());
timeString.addAttribute(TextAttribute.FOREGROUND,panel.getForeground());
// Do blinking if reach alarm
point
timeString.addAttribute(TextAttribute.FOREGROUND,
panel.getForeground(), 0, 6 + 2 * panel.getPadding1().length());
// Render padding1, do
blinking
timeString.addAttribute(TextAttribute.FOREGROUND, blink == 0 ? panel
.getForeground() : panel.getBackground(), 2, 2 + panel
.getPadding1().length());
timeString.addAttribute(TextAttribute.FOREGROUND, blink == 0 ? panel
.getForeground() : panel.getBackground(), 2 + panel
.getPadding1().length() + 2, 4 + 2 * panel.getPadding1()
.length());
然后設(shè)置TextLayout
// Create a new text layout
and signal the panel that it needs
// repainting
textLayout = null;
textLayout = new TextLayout(timeString.getIterator(), Clock.frc);
最后根據(jù)字符串大小設(shè)置組件大小,刷新
// To keep the clock size fit for
// actual size in time.
panel.setSize(getPreferredSize(panel));
panel.repaint();
current = null;
df = null;
最后一個(gè)方法是復(fù)寫(xiě)getPreferredSize使組件可以自適應(yīng)大小
// Return the preferred size for the
component
@Override
public Dimension getPreferredSize(JComponent c) {
首先得出兩個(gè)字符串大小:
Dimension size1 = textLayout.getBounds().getBounds().getSize();
Dimension size2 = textTimezoneLayout == null ? null : textTimezoneLayout.getBounds().getBounds().getSize();
然后寬度取2者大的,再額外增加一點(diǎn)Border
int max = width1;
if (width2 > max)
max = width2;
size.width = max + MARGIN + 2;
高度選取2者之和加上兩者間的間隙:
int height1 = (int) (textLayout.getAscent() + textLayout.getDescent() + textLayout.getLeading());
int height2 = (int) (textTimezoneLayout == null ? 0 : textTimezoneLayout.getAscent()+ textTimezoneLayout.getDescent() + textTimezoneLayout.getLeading());
size.height = (height1 + MARGIN) + (height2 + MARGIN);
到此為止,最簡(jiǎn)單的數(shù)字時(shí)鐘就完成了.
通過(guò)
private DigitalClock getDigitalClock() {
if (digitalClock == null) {
// To create a digital-type
clock with dark
// red foreground and black
background.
digitalClock = new DigitalClock(":", "'", new Font("Comic Sans
MS",Font.BOLD, 20), Color.GREEN.darker(), Color.BLACK
.brighter(), Locale.ENGLISH);
}
returndigitalClock;
}
取得數(shù)字時(shí)鐘組件,然后就和一般Java組件一樣使用了.