Posted on 2010-09-14 18:41
TWaver 閱讀(2323)
評(píng)論(3) 編輯 收藏
前幾天看了《Swing版小小網(wǎng)管》讓我想起前陣子做過的一個(gè)企業(yè)網(wǎng)管項(xiàng)目??蛻羰且粋€(gè)工廠,搞生產(chǎn)制造的。人并不多,四、五十人,多數(shù)是車間工人。辦公室的也就二十多人,網(wǎng)絡(luò)結(jié)構(gòu)并不復(fù)雜:ADSL寬帶接入,加上幾個(gè)AP進(jìn)行信號(hào)擴(kuò)展;臺(tái)式機(jī)、服務(wù)器、筆記本電腦,加上零星的手機(jī)上網(wǎng),僅此而已。大伙知道做企業(yè)網(wǎng)管是比較艱難的,工作量大,吃力不討好,競爭激烈,賣不了幾個(gè)錢。但是為了能夠在項(xiàng)目中多點(diǎn)籌碼,界面還是要做的精益求精才行。
先到工廠詳細(xì)調(diào)研了網(wǎng)絡(luò)結(jié)構(gòu)圖,并繪制了一個(gè)簡單的草圖結(jié)構(gòu):

其中ADSL和幾個(gè)無線AP是網(wǎng)絡(luò)主干,各個(gè)辦公室的結(jié)構(gòu)都是星形結(jié)構(gòu),通過網(wǎng)線進(jìn)行匯聚,通過AP進(jìn)行互聯(lián)。使用AP的原因是工廠正在進(jìn)行改造,幾個(gè)辦公室之間距離較遠(yuǎn),隔著一個(gè)大院子,網(wǎng)線鋪設(shè)不便。
要在網(wǎng)管里面呈現(xiàn)和監(jiān)控這個(gè)網(wǎng)絡(luò),對(duì)俺來說不算難事。不過我需要一個(gè)好看一點(diǎn)的流量監(jiān)控的圖表。首先通過SNMP獲取AP中的iftable中的端口,并獲取其實(shí)時(shí)流量,然后放置在拓?fù)鋱D的link對(duì)象中。為了不給網(wǎng)絡(luò)造成太多負(fù)擔(dān),網(wǎng)管默認(rèn)每5秒鐘獲取一次數(shù)值,并存儲(chǔ)連續(xù)100個(gè)數(shù)值,多余的拋棄。
繪制chart的圖并不復(fù)雜,整個(gè)chart呈一個(gè)長矩形狀,分為三段(老、中、輕),用不同的顏色進(jìn)行渲染。
1
public void paintIcon(Component c, Graphics g, int x, int y)
{
2
Graphics2D g2d = (Graphics2D) g;
3
4
Rectangle bounds = getBounds();
5
6
g2d.setColor(background);
7
g2d.fill(bounds);
8
9
Point location = bounds.getLocation();
10
int startX = location.x;
11
int startY = location.y + chartHeight;
12
GeneralPath path = new GeneralPath();
13
path.moveTo(startX, startY);
14
15
int[] values = getChartDataValues();
16
17
for (int i = 0; i < values.length; i++)
{
18
path.lineTo(startX + i, startY - values[i]);
19
}
20
path.lineTo(startX + chartWidth, startY);
21
path.closePath();
22
23
g2d.setColor(chartColor1);
24
g2d.fill(path);
25
26
//clip center part, paint with color2.
27
Shape oldClip = g2d.getClip();
28
Rectangle clip = new Rectangle(bounds.x + chartWidth / 4, bounds.y, chartWidth / 2, chartHeight);
29
g2d.setClip(clip);
30
g2d.setColor(chartColor2);
31
g2d.fill(path);
32
g2d.setClip(oldClip);
33
34
g2d.setColor(Color.lightGray);
35
g2d.draw(bounds);
36
37
g2d.setColor(Color.darkGray);
38
g2d.setFont(font);
39
40
int textX = location.x + 5;
41
int textY = location.y + chartHeight / 2 + font.getSize() / 2;
42
g2d.drawString("Sum", textX, textY);
43
44
int speed = 100;
45
if (getElementUI().getElement() instanceof MyLink)
{
46
speed = ((MyLink) getElementUI().getElement()).getSpeed();
47
}
48
String text = NumberFormat.getInstance().format(speed) + " kbit/s";
49
Rectangle2D textBounds = g2d.getFontMetrics().getStringBounds(text, g2d);
50
textX = (int) (location.x + chartWidth - textBounds.getWidth() - 5);
51
g2d.drawString(text, textX, textY);
52
}
53
顯示效果如下:

另外,對(duì)連線的效果也進(jìn)行了一些處理。用直線連接無疑太土氣了,來點(diǎn)曲線增加一點(diǎn)趣味。曲線用一個(gè)對(duì)稱的拋物線來處理,根據(jù)不同的角度進(jìn)行自動(dòng)調(diào)整:
1
public GeneralPath getPath()
{
2
Point from = this.getFromPoint();
3
Point to = this.getToPoint();
4
Point middle = new Point((from.x + to.x) / 2, (from.y + to.y) / 2);
5
boolean wider = (Math.abs(from.x - to.x) > Math.abs(from.y - to.y));
6
GeneralPath myPath = new GeneralPath();
7
myPath.moveTo(from.x, from.y);
8
if (wider)
{
9
myPath.quadTo(middle.x, from.y, middle.x, middle.y);
10
myPath.quadTo(middle.x, to.y, to.x, to.y);
11
} else
{
12
myPath.quadTo(from.x, middle.y, middle.x, middle.y);
13
myPath.quadTo(to.x, middle.y, to.x, to.y);
14
}
15
16
return myPath;
17
}
18
下圖顯示了幾個(gè)這種path的效果:

接下來,再把SNMP獲得的數(shù)據(jù)放入link中的chart呈現(xiàn)。為了避免泄密的麻煩,附件的demo俺去掉了這些業(yè)務(wù)代碼,用一個(gè)thread模擬代替了:
1
Thread thread = new Thread()
{
2
3
private Vector links = null;
4
5
private Vector getLinks()
{
6
if (links == null)
{
7
links = new Vector();
8
Iterator it = network.getDataBox().iterator();
9
while (it.hasNext())
{
10
Object o = it.next();
11
if (o instanceof MyLink)
{
12
MyLink link = (MyLink) o;
13
links.add(link);
14
}
15
}
16
}
17
return links;
18
}
19
20
@Override
21
public void run()
{
22
while (true)
{
23
Iterator it = getLinks().iterator();
24
while (it.hasNext())
{
25
Object o = it.next();
26
if (o instanceof MyLink)
{
27
MyLink link = (MyLink) o;
28
createRandomValue(link);
29
if (TWaverUtil.getRandomInt(10) == 1)
{
30
link.setSpeed(TWaverUtil.getRandomInt(10000));
31
}
32
}
33
}
34
try
{
35
Thread.sleep(100);
36
} catch (Exception ex)
{
37
ex.printStackTrace();
38
}
39
}
40
}
41
42
private void createRandomValue(MyLink link)
{
43
int value = link.getLastChartValue();
44
int change = TWaverUtil.getRandomInt(3) - 1;
45
value = value + change;
46
47
value = Math.min(value, 100);
48
value = Math.max(value, 0);
49
50
link.addChartValue(value);
51
}
52
};
53
thread.start();
54
}
55
再到google上物色幾個(gè)清爽的圖標(biāo)。

對(duì)了,在結(jié)束之際,突然想起一件事:AP上的晃悠悠的電線絲,可不是icon的一部反,而是咱draw上去的!這個(gè)小亮點(diǎn)咱得說說:主要思路就是new一個(gè)path,模擬其曲線的路徑,然后在Swing的paint時(shí)候給附加上去。代碼如下:
1
@Override
2
public void paintBody(Graphics2D g2d)
{
3
super.paintBody(g2d);
4
5
if (((MyNode) getElement()).isWireVisible())
{
6
Object oldValue = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
7
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
8
g2d.setColor(wireColor);
9
g2d.setStroke(TWaverConst.BASIC_STROKE);
10
g2d.draw(createWireShape());
11
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, oldValue);
12
}
13
}
14
15
private Shape createWireShape()
{
16
Point point = this.getHotspot();
17
int x = point.x - 25;
18
int y = point.y + 23;
19
20
GeneralPath path = new GeneralPath();
21
path.moveTo(x, y);
22
path.curveTo(x + 20, y - 20, x + 50, y - 10, x + 48, y);
23
path.curveTo(x + 48, y + 15, x + 10, y + 10, x + 12, y - 5);
24
path.curveTo(x + 12, y - 20, x + 50, y - 20, x + 53, y);
25
path.quadTo(x + 53, y + 3, x + 51, y + 5);
26
return path;
27
}
28
這下終于完整了??纯?#8220;晃悠悠的鐵絲”效果:

接下來,在程序里面整合一下,整個(gè)效果就出來了:

為了和大家共同學(xué)習(xí)和交流,附上的源代碼是從項(xiàng)目中抽取了Swing展示部分,去掉了所有業(yè)務(wù)邏輯,僅僅為了和大家共享Swing的展示能力,以及拓?fù)鋱D的制作思路。