Swing:高性能控件——MessagePane,可用于显示系列信息
2012-06-09 02:04
399 查看
这一个自上而下依条显示信息的控件
最新的信息显示在最上面一条
正常情况下,刷新数据时,CPU 占用率极低
运行效果图:
测试用例中,同时起了 4 个线程,刷新数据
在 sleep(10) 并且全屏的模式下,CPU 占用率依然接近于 0
有 BUG 可以报告给我
最新的信息显示在最上面一条
正常情况下,刷新数据时,CPU 占用率极低
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.lang.reflect.InvocationTargetException; import java.util.LinkedList; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JScrollBar; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class MessagePane<T> extends JComponent { /** * 允许最大数据行数 */ private static final int MAXLINE = 10000; /** * 数据队列 */ private LinkedList<T> datas = new LinkedList<T>(); /** * 本次绘制,需要绘制的行数,正数向下偏移,负数向上偏移 */ private int add = 0; /** * 每行数据的绘制高度 */ private int lineH = 1; /** * 滚动条 */ private JScrollBar bar = new JScrollBar(JScrollBar.VERTICAL); /** * 滚动条当前值 */ private int barValue = 0; /** * 绘制任务 */ private Runnable paintRunnable = new Runnable() { @Override public void run() { add = 1; paintImmediately(0, 0, getWidth(), getHeight()); add = 0; } }; /** * 滚动条更新任务 */ private Runnable barRunnable = new Runnable() { @Override public void run() { bar.setValues(barValue, getHeight() / lineH, 0, datas.size() + 1); } }; /** * 构造一个新的 MessagePane */ public MessagePane() { initialize(); } /** * 初始化 */ private void initialize() { setOpaque(true); setBackground(Color.WHITE); setLayout(new BorderLayout()); add(bar, BorderLayout.EAST); bar.addAdjustmentListener(new AdjustmentListener() { @Override public void adjustmentValueChanged(AdjustmentEvent e) { int newValue = bar.getValue(); if (newValue != barValue) { add = barValue - newValue; barValue = newValue; MessagePane.this.paintImmediately(0, 0, MessagePane.this.getWidth(), MessagePane.this.getHeight()); add = 0; } } }); addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { //控件大小变化时,更新滚动条 updateBar(); } }); setFont(UIManager.getFont("Panel.font")); lineH = getFontMetrics(getFont()).getHeight() + 2; updateBar(); } @Override public void setFont(Font font) { super.setFont(font); if (font != null) { lineH = getFontMetrics(font).getHeight() + 2; } } /** * 根据当前数据量,更新滚动条属性 */ private void updateBar() { if (SwingUtilities.isEventDispatchThread()) { barRunnable.run(); } else { SwingUtilities.invokeLater(barRunnable); } } /** * 标准的添加数据接口,在事件指派线程中调用该方法,可以获得最大的性能优化 * * @param data - 数据 */ public synchronized void addData(T data) { datas.addFirst(data); if (datas.size() > MAXLINE) { //数据超出限定范围时,移除最旧的一条数据 datas.pollLast(); } else { //数据长度变化时,更新滚动条 updateBar(); } if (SwingUtilities.isEventDispatchThread()) { paintRunnable.run(); } else { try { SwingUtilities.invokeAndWait(paintRunnable); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } /** * 标准的清除数据接口 */ public synchronized void clearDate() { datas.clear(); //清除数据后,滚动条值归零 barValue = 0; repaint(); //清除数据后,更新滚动条 updateBar(); } /** * 获得真实的绘制宽度(减去滚动条宽度) * * @return */ private int getPaintWidth() { return getWidth() - bar.getWidth(); } @Override protected void paintComponent(Graphics g) { //当调用 repaint 进入该方法时,add 为 0 ,会将整个控件完整绘制一遍。 //而当设置了 add 然后调用 paintImmediately 进入该方法时, //会进行 copyArea,然后只绘制 copy 后的脏区域。 int w = getPaintWidth(); int h = getHeight(); if (add > 0) { int move = lineH * add; //add 大于 0 表示需要向下整体位移,因此向下 copy //重新设置 clip,限制需要绘制的区域 g.copyArea(0, 0, w, h - move, 0, move); g.setClip(0, 0, w, move); } else if (add < 0) { int move = -lineH * add; //add 小于 0 表示需要向上整体位移,因此向上 copy //重新设置 clip,限制需要绘制的区域 g.copyArea(0, move, w, h - move, 0, -move); g.setClip(0, h - move, w, move); } Rectangle clip = g.getClipBounds(); int clipY = clip.y; int clipX = clip.x; int clipH = clip.height; int y = 0; g.setColor(getBackground()); g.fillRect(clipX, clipY, w, clipH); for (int i = barValue; i < datas.size(); i++) { y += lineH; if (y < clipY) { //小于绘制区域上沿时,不需要绘制该条数据 continue; } if (y - lineH > clipY + clipH) { //由于是从上往下绘制,因此大于绘制区域下沿时,终止绘制 break; } g.setColor(getForeground()); g.drawString(datas.get(i).toString(), 0, y); } } static long show = 0; public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { JFrame frame = new JFrame(); final MessagePane<Long> messagePane = new MessagePane<Long>(); frame.setContentPane(messagePane); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); Runnable runnable = new Runnable() { @Override public void run() { while (true) { messagePane.addData(show); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } show++; } } }; new Thread(runnable).start(); new Thread(runnable).start(); new Thread(runnable).start(); new Thread(runnable).start(); } }); } }
运行效果图:
测试用例中,同时起了 4 个线程,刷新数据
在 sleep(10) 并且全屏的模式下,CPU 占用率依然接近于 0
有 BUG 可以报告给我
相关文章推荐
- OutputArea,用于模拟控制台输出信息的 Swing 控件
- 安卓控件使用系列1:TextView显示各种格式的文本
- 使用ToolTip控件显示提示信息
- 安卓控件使用系列34:ListView列表控件显示表单的使用方法1
- Android ListView控件显示信息
- 封装一个Win32弹出提示框的函数(用于STATIC等控件显示Tooltip)
- Dev系列控件之XtraChart高级应用(模拟flash鼠标移动,点击实现相关信息提示)
- windows下设备信息管理系列函数——用于设备枚举
- android控件之TextView显示聊天室信息
- 鼠标停在控件上就显示提示信息
- 用QT实现的用于显示输入IP的LineEdit控件
- Java Swing控件桌面程序 显示托盘图标
- 自定义文字滚动控件,用于单行文本的显示,当文字过长的时候,就会自动的向左滚动
- 第八篇: UpdateProgress 控件--显示正在处理中的信息
- 如何获取taskflow的id值,用于控制当前页面的控件显示或隐藏
- ASP.NET基础教程-DataList数据列表控件-选择DataList列表中的一行显示明细信息
- Android-Color State List用于控件在各状态下的文本颜色显示
- 用FormView控件显示登录成功的用户信息
- 在编辑框控件中多行显示文本信息
- QT5-控件-QScrollArea-可以用于把一个窗口分割为多个-比如根据图片大小显示滚动条