如何在Blackberry中使用Canvas上的文本旋转圆圈

时间:2012-12-01 05:58:08

标签: java blackberry touch

如何在TouchEvent或TrackBallMoveEvent上使用文本旋转圆圈。

  1. 如何制作此类圈子?

    我创建了一个圆圈并将其旋转,但它始终从0度开始。

  2. 是否还有其他选项来创建此类圈子?

  3. 每个圈子都有不同的文字,每个圈子可以独立移动

    enter image description here

1 个答案:

答案 0 :(得分:7)

所以,这绝对不完整,但我认为这是你需要的大部分内容。

限制/假设

  1. 到目前为止,我只实施了触摸处理,因为我认为这更难。如果我以后有时间,我会回来添加轨迹球处理。
  2. 我没有给旋转光盘任何动量。用户的手指离开光盘后,它会停止旋转。
  3. 我不确定光盘之间的焦点转换是否正确。你必须做一些测试。他们大多是对的,至少。
  4. 当您在标题中提到画布时,我认为这并不意味着您需要使用J2ME Canvas。使用RIM UI库编写BlackBerry应用程序几乎就是我所做的一切。
  5. 解决方案

    基本上,我创建了一个Field子类来表示每张光盘。您可以通过传入标签数组,围绕周长,半径和颜色来创建字段。每个DiscField中的硬编码是文本的边缘插入,这种假设在光盘之间存在一定的大小差异。你应该把它变得更有活力。

    public class DiscField extends Field {
    
       /** Used to map Manager's TouchEvents into our coordinate system */
       private int _offset = 0;
       private int _radius;
       private int _fillColor;
       private double _currentRotation = 0.0;
       private double _lastTouchAngle = 0.0;
       private boolean _rotating = false;
       private String[] _labels;
       /** Text inset from outer disc edge */
       private static final int INSET = 30;  
    
       private DiscField() {      
       }
    
       public DiscField(String[] labels, int radius, int fillColor) {
          super(Field.FOCUSABLE);
          _labels = labels;
          _radius = radius;
          _fillColor = fillColor;
       }    
    
       protected void layout(int width, int height) {
          setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
       }
    
       private void drawFilledCircle(Graphics g, int x, int y, int r) {
          // http://stackoverflow.com/a/1186851/119114
          g.fillEllipse(x, y, x + r, y, x, y + r, 0, 360);
       }
    
       private void drawCircle(Graphics g, int x, int y, int r) {
          g.drawEllipse(x, y, x + r, y, x, y + r, 0, 360);
       }
    
       protected void paint(Graphics graphics) {
          int oldColor = graphics.getColor();
          graphics.setColor(_fillColor);
          drawFilledCircle(graphics, _radius, _radius, _radius);
          graphics.setColor(Color.WHITE);
          drawCircle(graphics, _radius, _radius, _radius);
    
          // plot the text around the circle, inset by some 'padding' value
          int textColor = (_fillColor == Color.WHITE) ? Color.BLACK : Color.WHITE; 
          graphics.setColor(textColor);
          // equally space the labels around the disc
          double interval = (2.0 * Math.PI / _labels.length);
          for (int i = 0; i < _labels.length; i++) {
             // account for font size when plotting text
             int fontOffsetX = getFont().getAdvance(_labels[i]) / 2;
             int fontOffsetY = getFont().getHeight() / 2;
             int x = _radius + (int) ((_radius - INSET) * Math.cos(i * interval - _currentRotation)) - fontOffsetX;
             int y = _radius - (int) ((_radius - INSET) * Math.sin(i * interval - _currentRotation)) - fontOffsetY;
             graphics.drawText(_labels[i], x, y);
          }
    
          graphics.setColor(oldColor);
       }
    
       protected void drawFocus(Graphics graphics, boolean on) {
          if (on) {
             int oldColor = graphics.getColor();
             int oldAlpha = graphics.getGlobalAlpha();
             // just draw a white shine to indicate focus
             graphics.setColor(Color.WHITE);
             graphics.setGlobalAlpha(80);
             drawFilledCircle(graphics, _radius, _radius, _radius);
             // reset graphics context
             graphics.setColor(oldColor);
             graphics.setGlobalAlpha(oldAlpha);
          }
       }  
    
       protected void onUnfocus() {
          super.onUnfocus();
          _rotating = false;
       }
    
       protected boolean touchEvent(TouchEvent event) {
          switch (event.getEvent()) {
          case TouchEvent.MOVE: {
             setFocus();         
             // Get the touch location, within this Field
             int x = event.getX(1) - _offset - _radius;
             int y = event.getY(1) - _offset - _radius;
             if (x * x + y * y <= _radius * _radius) {
                double angle = MathUtilities.atan2(y, x);
                if (_rotating) {
                   // _lastTouchAngle only valid if _rotating
                   _currentRotation += angle - _lastTouchAngle;
                   // force a redraw (paint) with the new rotation angle
                   invalidate();
                } else {
                   _rotating = true;
                }         
                _lastTouchAngle = angle;
    
                return true;
             }
          }
          case TouchEvent.UNCLICK:
          case TouchEvent.UP: {
             _rotating = false;
             return true;      
          }  
          case TouchEvent.DOWN: {
             setFocus();                 
             int x = event.getX(1) - _offset - _radius;
             int y = event.getY(1) - _offset - _radius;
             if (x * x + y * y <= _radius * _radius) {
                _lastTouchAngle = MathUtilities.atan2(y, x);
                _rotating = true;
                return true;
             }
          }
          default:
             break;
          }           
          return super.touchEvent(event);
       }
    
       protected boolean trackwheelRoll(int arg0, int arg1, int arg2) {
          return super.trackwheelRoll(arg0, arg1, arg2);
          // TODO!
       }
    
       public int getPreferredHeight() {
          return getPreferredWidth();
       }
    
       public int getPreferredWidth() {
          return 2 * _radius;
       }
    
       public String[] getLabels() {
          return _labels;
       }
    
       public void setLabels(String[] labels) {
          this._labels = labels;
       }
    
       public int getRadius() {
          return _radius;
       }
    
       public void setRadius(int radius) {
          this._radius = radius;
       }
    
       public double getCurrentAngle() {
          return _currentRotation;
       }
    
       public void setCurrentAngle(double angle) {
          this._currentRotation = angle;
       }
    
       public int getOffset() {
          return _offset;
       }
    
       public void setOffset(int offset) {
          this._offset = offset;
       }
    }
    

    包含所有DiscField个对象的是DiscManager。它会对DiscFields中的孩子sublayout()进行对齐,并处理触摸事件的正确委派...因为字段重叠,并且在DiscField 范围内触摸也不应落入其半径范围内(即角落)应由更大的光盘处理。

       /** 
        * A DiscManager is a container for DiscFields and manages proper delegation
        * of touch event handling.
        */
       private class DiscManager extends Manager {
    
          private int _maxRadius = 0;
    
          public DiscManager(long style){
             super(style);
    
             DiscField outerDisc = new DiscField(new String[] { "1", "2", "3", "4", "5", "6" }, 
                   180, Color.BLUE);
             _maxRadius = outerDisc.getRadius();
             DiscField middleDisc = new DiscField(new String[] { "1", "2", "3", "4", "5" }, 
                   120, Color.GRAY);
             middleDisc.setOffset(_maxRadius - middleDisc.getRadius());
             DiscField innerDisc = new DiscField(new String[] { "1", "2", "3", "4" }, 
                   60, Color.RED);
             innerDisc.setOffset(_maxRadius - innerDisc.getRadius());
    
             // order matters here:
             add(outerDisc);
             add(middleDisc);
             add(innerDisc);
          }
    
          protected void sublayout(int width, int height) {
             setExtent(2 * _maxRadius, 2 * _maxRadius);
    
             // each disc needs to have the same x,y center to be concentric
             for (int i = 0; i < getFieldCount(); i++) {
                if (getField(i) instanceof DiscField) {
                   DiscField disc = (DiscField) getField(i);
                   int xCenter = _maxRadius - disc.getRadius();
                   int yCenter = _maxRadius - disc.getRadius();
                   setPositionChild(disc, xCenter, yCenter);
                   layoutChild(disc, 2 * _maxRadius, 2 * _maxRadius);
                }
             }
          }
    
          protected boolean touchEvent(TouchEvent event) {
             int eventCode = event.getEvent();
             // Get the touch location, within this Manager
             int x = event.getX(1);
             int y = event.getY(1);
    
             if ((x >= 0) && (y >= 0) && (x < getWidth()) && (y < getHeight())) {
                int field = getFieldAtLocation(x, y);
                if (field >= 0) {
                   DiscField df = null;
                   for (int i = 0; i < getFieldCount(); i++) {
                      if (getField(field) instanceof DiscField) {
                         int r = ((DiscField)getField(field)).getRadius();
                         // (_maxRadius, _maxRadius) is the center of all discs
                         if ((x - _maxRadius) * (x - _maxRadius) + (y - _maxRadius) * (y - _maxRadius) <= r * r) {
                            df = (DiscField)getField(field);
                         } else {
                            // touch was not within this disc's radius, so the one slightly bigger
                            // should be passed this touch event                        
                            break;
                         }
                      }
                   }
                   // Let event propagate to child field
                   return (df != null) ? df.touchEvent(event) : super.touchEvent(event);
                } else {
                   if (eventCode == TouchEvent.DOWN) {                    
                      setFocus();
                   }
                   // Consume the event
                   return true;
                }
             }
             // Event wasn't for us, let superclass handle in default manner
             return super.touchEvent(event);
          }
       }
    

    最后,使用它们的屏幕:

    public class DiscScreen extends MainScreen {
    
       public DiscScreen() {
          super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
    
          add(new DiscManager(Field.USE_ALL_WIDTH));
       }
    }
    

    结果

    enter image description here