1. /**
  2. * <p>Copyright: Copyright (c) 2002-2004</p>
  3. * <p>Company: JavaResearch(http://www.javaresearch.org)</p>
  4. * <p>最后更新日期:2003年4月30日
  5. * @author cherami
  6. */
  7. package org.jr.swing;
  8. import javax.swing.*;
  9. import java.awt.*;
  10. import java.awt.event.*;
  11. import java.util.ArrayList;
  12. import org.jr.util.*;
  13. /**
  14. * 多行走马灯。
  15. * 垂直方向滚动显示多行文本。
  16. * 每行文本的颜色、显示对齐方式以及字体都可以不同。
  17. * @since 0.6
  18. */
  19. public class MultiLineHorseLight
  20. extends JLabel {
  21. ArrayList texts=new ArrayList(); //文本行数组
  22. int interval; //刷新间隔
  23. int startLine=0; //开始显示的行
  24. int endLine; //最后显示的行
  25. int showLines=1; //一屏显示的行数
  26. int lineIndex=1;//开始行的位置
  27. Timer timer;
  28. private static final int INTERVAL=1000;
  29. /**
  30. * 构造一个空的MultiLineHorseLight。
  31. */
  32. public MultiLineHorseLight() {
  33. interval = INTERVAL;
  34. init();
  35. }
  36. /**
  37. * 以指定的文本数组构造一个MultiLineHorseLight。
  38. * @param texts 文本
  39. */
  40. public MultiLineHorseLight(String texts[]) {
  41. this(texts, INTERVAL);
  42. }
  43. /**
  44. * 以指定的文本数组构造一个MultiLineHorseLight。
  45. * @param texts 具有属性的文本
  46. */
  47. public MultiLineHorseLight(TextLine texts[]) {
  48. this(texts, INTERVAL);
  49. }
  50. /**
  51. * 以指定的文本数组以及时间间隔构造一个MultiLineHorseLight。
  52. * @param texts 文本
  53. * @param interval 时间间隔
  54. */
  55. public MultiLineHorseLight(String texts[], int interval) {
  56. for (int i=0;i<texts.length ;i++ ) {
  57. TextLine text=new TextLine(texts[i]);
  58. this.texts.add(text);
  59. }
  60. if (interval > 0) {
  61. this.interval = interval;
  62. }
  63. else {
  64. interval = INTERVAL;
  65. }
  66. init();
  67. }
  68. /**
  69. * 以指定的文本数组以及时间间隔构造一个MultiLineHorseLight。
  70. * @param texts 具有属性的文本
  71. * @param interval 时间间隔
  72. */
  73. public MultiLineHorseLight(TextLine texts[], int interval) {
  74. ListUtil.addArrayToList(texts,this.texts);
  75. if (interval > 0) {
  76. this.interval = interval;
  77. }
  78. else {
  79. interval = INTERVAL;
  80. }
  81. init();
  82. }
  83. /**
  84. * 初始化。生成定时器以及监听组件大小改变事件。
  85. */
  86. private void init() {
  87. timer = new Timer(interval, new ActionListener() {
  88. public void actionPerformed(ActionEvent e) {
  89. repaint();
  90. }
  91. });
  92. timer.start();
  93. addComponentListener(new ComponentAdapter() {
  94. public void componentResized(ComponentEvent e) {
  95. startLine=0;
  96. lineIndex=1;
  97. showLines=1;
  98. }
  99. });
  100. }
  101. /**
  102. * 在走马灯后面附加一个新行。
  103. * @param text 文本
  104. */
  105. public void appendText(String text) {
  106. texts.add(new TextLine(text));
  107. }
  108. /**
  109. * 在走马灯后面附加一个新行。
  110. * @param text 具有属性的文本
  111. */
  112. public void appendText(TextLine text) {
  113. texts.add(text);
  114. }
  115. /**
  116. * 添加一个空行。
  117. */
  118. public void addSpaceLine() {
  119. appendText(" ");
  120. }
  121. /**
  122. * 设置刷新间隔。
  123. * @param interval 刷新间隔
  124. */
  125. public void setInterval(int interval) {
  126. if (interval > 0) {
  127. this.interval = interval;
  128. timer.setDelay(interval);
  129. }
  130. }
  131. /**
  132. * 得到组件的最佳大小。
  133. * 最佳宽度为文本中的最大字符串长度加10,最佳高度为文字高度的三倍。
  134. * @return 组件的最佳大小
  135. */
  136. public Dimension getPreferredSize() {
  137. Graphics g = getGraphics();
  138. FontMetrics fontMetrics = g.getFontMetrics();
  139. int height = fontMetrics.getHeight();
  140. int maxTextWidth=0;
  141. for (int i=0;i<texts.size() ;i++ ) {
  142. int width=fontMetrics.stringWidth(((TextLine)texts.get(i)).text);
  143. if (width>maxTextWidth) {
  144. maxTextWidth=width;
  145. }
  146. }
  147. return new Dimension(maxTextWidth+10,height*3);
  148. }
  149. /**
  150. * 重新绘制组件。
  151. * @param g 图形设备
  152. */
  153. protected void paintComponent(Graphics g) {
  154. FontMetrics fontMetrics = g.getFontMetrics();
  155. int fontheight = fontMetrics.getHeight();
  156. int height = getSize().height;
  157. int lines = height / fontheight;
  158. int positionY;
  159. if (lines>=texts.size()) {
  160. endLine = startLine + showLines;
  161. positionY = height - lineIndex * fontheight+10;
  162. for (int i=startLine;i<endLine ;i++ ) {
  163. TextLine line=(TextLine)texts.get(i);
  164. drawLine(line,positionY,g,fontMetrics);
  165. positionY+=fontheight;
  166. }
  167. if (lineIndex<lines) {
  168. showLines++;
  169. }
  170. if (showLines>texts.size()) {
  171. showLines=texts.size();
  172. }
  173. lineIndex++;
  174. if (lineIndex>lines) {
  175. lineIndex=lines;
  176. startLine++;
  177. showLines--;
  178. if (startLine==texts.size()) {
  179. startLine=0;
  180. lineIndex=1;
  181. showLines=1;
  182. }
  183. }
  184. }
  185. else {
  186. endLine = startLine + showLines;
  187. positionY = height - lineIndex * fontheight+10;
  188. for (int i=startLine;i<endLine ;i++ ) {
  189. TextLine line=(TextLine)texts.get(i);
  190. drawLine(line,positionY,g,fontMetrics);
  191. positionY+=fontheight;
  192. }
  193. showLines++;
  194. lineIndex++;
  195. if (lineIndex>lines) {
  196. lineIndex=lines;
  197. startLine++;
  198. showLines--;
  199. if (startLine+showLines>texts.size()) {
  200. showLines--;
  201. }
  202. if (startLine==texts.size()) {
  203. startLine=0;
  204. lineIndex=1;
  205. showLines=1;
  206. }
  207. }
  208. }
  209. }
  210. /**
  211. * 绘制一行文本。
  212. * @param text 具有属性的文本。
  213. * @param positionY 绘制的垂直坐标
  214. * @param g 图形设备
  215. * @param fontMetrics 字体信息
  216. */
  217. private void drawLine(TextLine text,int positionY,Graphics g,FontMetrics fontMetrics) {
  218. int width = getSize().width;
  219. int positionX;
  220. g.setColor(text.color);
  221. g.setFont(text.font);
  222. switch (text.align) {
  223. case TextLine.LEFT:
  224. positionX=0;
  225. break;
  226. case TextLine.CENTER:
  227. positionX = (width - fontMetrics.stringWidth(text.text)) / 2;
  228. break;
  229. case TextLine.RIGHT:
  230. positionX = (width - fontMetrics.stringWidth(text.text));
  231. break;
  232. default:
  233. positionX=0;
  234. break;
  235. }
  236. g.drawString(text.text, positionX, positionY);
  237. }
  238. /**
  239. * 重新开始运动显示。
  240. */
  241. public void start() {
  242. startLine=0;
  243. lineIndex=1;
  244. showLines=1;
  245. timer.start();
  246. }
  247. /**
  248. * 停止运动。
  249. */
  250. public void stop() {
  251. timer.stop();
  252. }
  253. }