带提示的JTextField

转自 一文online


 接着昨天的MyJTextField,我们继续为JTextField增强,今天我们为MyJTextField增加一个泡泡提示。先看图片:

当输入第三个字符'a'时,由于昨天我们的MyJTextField做了处理,所以'a'不能被输入,而且弹出泡泡提示你下次不要了哟!
同样的,下一张图片:


为MyJTextField增加泡泡提示功能要做以下几件事情:
1. 泡泡窗口
2. 显示的时候计算位置

这里我使用了Bernhard Pauler的BalloonTip包的BalloonBorder代码,改造了BalloonTip代码,好废话不说,放上完整代码后再解释:
  1  /**
  2   * @(#)MyJTextField.java  0.1.1  2007-9-8
  3    */
  4  package  ruislan;
  5 
  6  import  java.awt.BorderLayout;
  7  import  java.awt.Color;
  8  import  java.awt.Component;
  9  import  java.awt.Container;
 10  import  java.awt.Font;
 11  import  java.awt.Point;
 12  import  java.awt.event.ComponentAdapter;
 13  import  java.awt.event.ComponentEvent;
 14  import  java.awt.event.KeyAdapter;
 15  import  java.awt.event.KeyEvent;
 16 
 17  import  javax.swing.Icon;
 18  import  javax.swing.ImageIcon;
 19  import  javax.swing.JDialog;
 20  import  javax.swing.JFrame;
 21  import  javax.swing.JLabel;
 22  import  javax.swing.JLayeredPane;
 23  import  javax.swing.JPanel;
 24  import  javax.swing.JTextField;
 25  import  javax.swing.border.EmptyBorder;
 26 
 27  import  net.java.balloontip.BalloonBorder;
 28 
 29 
 30  /**
 31   * Custom JTextField.
 32   * 
 33   *  @version  0.1.1, 2007-9-9
 34   *  @author  ruislan <a href="mailto:z17520@126.com"/>
 35    */
 36  public   class  MyJTextField  extends  JTextField {
 37       private   static   final  Color TIP_COLOR  =   new  Color( 255 255 225 );
 38       private   int  limit  =  Integer.MAX_VALUE;
 39       private   boolean  numberOnly;
 40       private  CoolToolTip numberTip;
 41       private  CoolToolTip limitTip;
 42       private  ImageIcon tipIcon;
 43 
 44       public  MyJTextField() {
 45          initComponents();
 46          initEventListeners();
 47      }
 48 
 49       private   void  initComponents() {
 50          tipIcon  =   new  ImageIcon(MyJTextField. class .getResource( " tip.gif " ));
 51 
 52          numberTip  =   new  CoolToolTip( this , TIP_COLOR, getColumns(),  10 );
 53          numberTip.setText( " 只能输入数字! " );
 54          numberTip.setIcon(tipIcon);
 55          numberTip.setIconTextGap( 10 );
 56 
 57          limitTip  =   new  CoolToolTip( this , TIP_COLOR, getColumns(),  10 );
 58          limitTip.setIcon(tipIcon);
 59          limitTip.setIconTextGap( 10 );
 60      }
 61 
 62       private   void  initEventListeners() {
 63          addKeyListener( new  KeyAdapter() {
 64              @Override
 65               public   void  keyTyped(KeyEvent e) {
 66                   if  (getText().length()  +   1   >  limit) {
 67                      deleteInputChar(e);
 68                      limitTip.setVisible( true );
 69                       return ;
 70                  }  else  {
 71                      limitTip.setVisible( false );
 72                  }
 73                   if  (numberOnly) {
 74                       char  input  =  e.getKeyChar();
 75                       if  ( ! Character.isDigit(input)) {
 76                          numberTip.setVisible( true );
 77                          deleteInputChar(e);
 78                      }  else  {
 79                          numberTip.setVisible( false );
 80                      }
 81                  }
 82              }
 83 
 84               private   void  deleteInputChar(KeyEvent source) {
 85                  source.setKeyChar(( char ) KeyEvent.VK_CLEAR);
 86              }
 87          });
 88      }
 89 
 90       public   void  setMaxTextLength( int  limit) {
 91           if  (limit  <   0 ) {
 92               return ;
 93          }
 94           this .limit  =  limit;
 95          limitTip.setText(String.format( " 超过最大长度 / " % d/ "" , limit));
 96      }
 97 
 98       public   int  getMaxTextLength() {
 99           return  limit;
100      }
101 
102       public   void  setNumberOnly( boolean  numberOnly) {
103           this .numberOnly  =  numberOnly;
104      }
105 
106       public   boolean  isNumberOnly() {
107           return   this .numberOnly;
108      }
109 
110       private   class  CoolToolTip  extends  JPanel {
111           private  JLabel label  =   new  JLabel();
112           private   boolean  haveShowPlace;
113 
114           private  Component attachedComponent;
115 
116           public  CoolToolTip(Component attachedComponent, Color fillColor,
117                   int  borderWidth,  int  offset) {
118               this .attachedComponent  =  attachedComponent;
119 
120              label.setBorder( new  EmptyBorder(borderWidth, borderWidth,
121                      borderWidth, borderWidth));
122              label.setBackground(fillColor);
123              label.setOpaque( true );
124              label.setFont( new  Font( " system " 0 12 ));
125 
126              setOpaque( false );
127               this .setBorder( new  BalloonBorder(fillColor, offset));
128               this .setLayout( new  BorderLayout());
129              add(label);
130 
131              setVisible( false );
132 
133               //  if the attached component is moved while the balloon tip is
134               //  visible, we need to move as well
135              attachedComponent.addComponentListener( new  ComponentAdapter() {
136                   public   void  componentMoved(ComponentEvent e) {
137                       if  (isShowing()) {
138                          determineAndSetLocation();
139                      }
140                  }
141              });
142 
143          }
144 
145           private   void  determineAndSetLocation() {
146              Point location  =  attachedComponent.getLocation();
147              setBounds(location.x, location.y  -  getPreferredSize().height,
148                      getPreferredSize().width, getPreferredSize().height);
149          }
150 
151           public   void  setText(String text) {
152              label.setText(text);
153          }
154 
155           public   void  setIcon(Icon icon) {
156              label.setIcon(icon);
157          }
158 
159           public   void  setIconTextGap( int  iconTextGap) {
160              label.setIconTextGap(iconTextGap);
161          }
162 
163           public   void  setVisible( boolean  show) {
164               if  (show) {
165                  determineAndSetLocation();
166                  findShowPlace();
167              }
168               super .setVisible(show);
169          }
170 
171           private   void  findShowPlace() {
172               if  (haveShowPlace) {
173                   return ;
174              }
175               //  we use the popup layer of the top level container (frame or
176               //  dialog) to show the balloon tip
177               //  first we need to determine the top level container
178              Container parent  =  attachedComponent.getParent();
179              JLayeredPane layeredPane;
180               while  ( true ) {
181                   if  (parent  instanceof  JFrame) {
182                      layeredPane  =  ((JFrame) parent).getLayeredPane();
183                       break ;
184                  }  else   if  (parent  instanceof  JDialog) {
185                      layeredPane  =  ((JDialog) parent).getLayeredPane();
186                       break ;
187                  }
188                  parent  =  parent.getParent();
189              }
190              layeredPane.add( this , JLayeredPane.POPUP_LAYER);
191              haveShowPlace  =   true ;
192          }
193      }
194  }
195 

测试代码:
 1  package  ruislan.examples;
 2 
 3  import  java.awt.Container;
 4  import  java.awt.Dimension;
 5  import  java.awt.GridBagLayout;
 6  import  java.awt.Toolkit;
 7 
 8  import  javax.swing.JFrame;
 9 
10  import  ruislan.MyJTextField;
11 
12  public   class  MyJTextFieldTest {
13 
14       public   static   void  main(String[] args) {
15          JFrame frame  =   new  JFrame();
16          Container contentPane  =  frame.getContentPane();
17          contentPane.setLayout( new  GridBagLayout());
18           final  MyJTextField textField  =   new  MyJTextField();
19          textField.setNumberOnly( true );
20          textField.setColumns( 15 );
21          textField.setMaxTextLength( 5 );
22          contentPane.add(textField);
23 
24          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
25          frame.setSize( 320 240 );
26          centerWindow(frame);
27          frame.setTitle( " MyJTextField " );
28          frame.setVisible( true );
29      }
30 
31       public   static   void  centerWindow(Container window) {
32           //  get the size of the screen
33          Dimension dim  =  Toolkit.getDefaultToolkit().getScreenSize();
34 
35           //  determine the new location of the window
36           int  w  =  window.getSize().width;
37           int  h  =  window.getSize().height;
38           int  x  =  (dim.width  -  w)  /   2 ;
39           int  y  =  (dim.height  -  h)  /   2 ;
40 
41           //  move the window
42          window.setLocation(x, y);
43      }
44  }
45 

就以上代码解释一下
1. 为什么CoolToolTip不使用JWindow而使用JPanel?
不错,JWindow可以放置在屏幕的任意位置,而且也是我的首选,但是JWindow是调用native代码来绘图,没有提供可以改变形状的API(我 们需要泡泡嘛),所以使用了JPanel,那么这就具有了局限性,第一个就是我们在显示泡泡的时候必须找到最高级的组件来显示,以便覆盖到其下的所有子组 件,第二个就是显示的区域受到了最高级组件的局限,例如JFrame上只有一个MyJTextField,而JFrame.pack了之后大小刚好是 MyJTextField的大小,这样就看不到CoolToolTip了。

2. 为什么CoolToolTip在setVisible的时候才找一个要show的地方?
这个操作在Bernhard Pauler的BalloonTip代码中是由构造方法来完成的,但是这里就会出现一个问题,对,NullPointer,因为Swing不像SWT,是 在component.add(child)方法调用的时候才设置child的Parent,而非在构造child的时候将component放入,所以 我们只有懒加载来避免这个情况发生。说到懒加载我发表一下一个题外意见,在下认为懒加载在swing中不要用得太过频繁,用户体验是第一位的,在下宁愿在 启动程序的时候看进度条也不愿在启动某个视图的时候突然卡死一小会。

3. 还有什么没有做的?
例如当输入Esc、Backspace、Enter等等按键的时候CoolToolTip也会跳出来show一把,我们必须过滤掉它们!

今天就到这里吧,下一次我们让MyJTextField更酷一点,我们为它加上Beep声音,当我们输入了非法字符的时候就beep、beep的叫唤,没有声音也没有泡泡提示的话有些人很可能是以为自己的键盘坏掉了。

本人就对QQ的登录窗口很有意见,每次我开机都是Eclipse和QQ一起打开的,一般操作都是先登录QQ,但是有一天我QQ后打开的,我正在happy coding,突然输入的字符全乱了套,我以为是输入的问题,结果是英文也,然后我认为可能是eclipse的问题(因为有的时候eclipse的代码编 辑区就无端不让操作了),换成了记事本,结果也是这个情况,然后就有点慌以为键盘坏掉了,毕竟换一个笔记本键盘很贵的说(在找问题其间多次路过QQ的登录 窗口,我还嫌其碍事最小化了),维修部电话打过之后他们叫我拿过去,我就准备关电脑,也不知道怎的,在我关闭了一系列的程序包括QQ登录窗口之后,我突然 又想最后确定一下,当然结果很明显又好了,这个时候我就像修复程序BUG一样,找到恢复正常前的最后一个动作,重复操作直到又不正常为止,终于发现是QQ 登录框的问题,气煞我也,差点就花钱换一个键盘了... 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值