2012-06-08 1 views
1

Essayer de faire un simple numéro de contrôle de clicker pour BlackBerry 6/7, comme ceci:BlackBerry 6/7 Tableau mise en page avec ColSpan - Nombre de sélection Widget

enter image description here

Au cœur est juste un champ de texte et deux boutons, avec un gestionnaire pour les espacer.

Je connais le composant TableManager non pris en charge, mais il ne prend pas en charge les analyses de colonnes. Et, la notion d'utiliser des gestionnaires profondément imbriqués je trouve ... dérangeant.

Et, cela se produira plusieurs fois, donc je voulais un composant simple et réutilisable.

Donc, j'ai construit un gestionnaire simple pour contenir ces trois composants, vous permettant même de fournir votre propre champ de texte ou des boutons pour des raisons stylistiques. Le code est joint ci-dessous. Manifestement plus fantaisiste que nécessaire, mais le travail est entièrement réalisé en sublayout. Ce qui se passe réellement, c'est que la partie supérieure droite de chacun des 3 composants apparaît au bon endroit, mais les 3 composants sont "rétrécis" à la taille minimale requise pour afficher leur contenu, en ignorant les requêtes USE_ALL_WIDTH et USE_ALL_HEIGHT demandées. C'est probablement un goofup mineur, mais comment puis-je faire ces composants réellement utiliser toute la largeur et utiliser toute la hauteur? J'ai essayé plusieurs variantes sur USE_ALL_ * mais je n'ai pas encore trouvé le gagnant. Bien sûr, d'autres améliorations seraient également les bienvenues.

Merci.

package layout; 

import net.rim.device.api.system.Display; 
import net.rim.device.api.ui.Field; 
import net.rim.device.api.ui.Manager; 
import net.rim.device.api.ui.XYEdges; 
import net.rim.device.api.ui.component.ButtonField; 
import net.rim.device.api.ui.component.EditField; 

/** 
* XXX BROKEN DO NOT USE YET - layout fail, components get shrink-wrapped. 
* 
* NumberClicker Makes a layout with three components, like this: 
* <pre> 
* +-------------------+ +-------------------+ 
* |     | |   +  | 
* |   3   | |-------------------| 
* |     | |-------------------| 
* |     | |   -  | 
* |-------------------| |-------------------| 
* </pre> 
* Note that by default, the buttons are set to increment and decrement the number in the textfield! 
* @author Ian Darwin 
*/ 
public class NumberClicker extends Manager { 

    private static final long SUBCOMPONENT_STYLE = Field.USE_ALL_HEIGHT | Field.USE_ALL_WIDTH; 
    private static final long MANAGER_STYLE = Field.FIELD_HCENTER | Field.FIELD_VCENTER; 

    final XYEdges MARGINS = new XYEdges(10,10,10,10); 

    EditField number = new EditField(SUBCOMPONENT_STYLE); 
    ButtonField plus = new ButtonField("+", SUBCOMPONENT_STYLE); 
    ButtonField minus = new ButtonField("-", SUBCOMPONENT_STYLE); 

    public NumberClicker() { 
     this(MANAGER_STYLE); 
    } 
    public NumberClicker(long style) 
    { 
     this(null, null, null, style); 
    } 

    /** Constructor allows you to provide your own three fields */ 
    public NumberClicker(EditField number, ButtonField plus, ButtonField minus) { 
     this(number, plus, minus, MANAGER_STYLE); 
    } 

    /** Constructor allows you to provide your own three fields ANd override style. 
    * If any of the fields is null, the default value is used. 
    */ 
    public NumberClicker(EditField number, ButtonField plus, ButtonField minus, long style) { 
     super(style); 
     if (number != null) { 
      this.number = number; 
     } else { 
      this.number.setMargin(MARGINS); // set margins on our default, constructed above. 
     } 
     setValue(1); 
     add(this.number); // Nulls allowed, so must be careful to use "this." throughout this method. 

     if (plus != null) { 
      this.plus = plus; 
     } else { 
      this.plus.setMargin(MARGINS); 
     } 
     add(this.plus); 

     if (minus != null) { 
      this.minus = minus; 
     } else { 
      this.minus.setMargin(MARGINS); 
     } 
     add(this.minus); 

     this.plus.setRunnable(new Runnable() { 
      public void run() { 
       increment(); 
      }   
     }); 
     this.minus.setRunnable(new Runnable() { 
      public void run() { 
       decrement(); 
      }   
     }); 
    } 

    public void increment() { 
     number.setText(Integer.toString(Integer.parseInt(number.getText().trim()) + 1)); 
    } 

    public void decrement() { 
     number.setText(Integer.toString(Integer.parseInt(number.getText().trim()) - 1)); 
    } 

    /** Return the integer value of the clicker. Do not call if you are re-using this as a three-component layout manager! */ 
    public int getValue() { 
     return Integer.parseInt(number.getText().trim()); 
    } 

    public void setValue(int value) { 
     number.setText(Integer.toString(value)); 
    } 

    /** 
    * Compute sizes and positions of subfields. 
    * 
    * Required by Manager 
    */ 
    public void sublayout(int width, int height) { 
     int layoutWidth = width; 
     int layoutHeight = Math.min(height, Display.getHeight()); // no scrolling here 
System.err.println("Display:" + Display.getWidth() + "x" + Display.getHeight()); 

     int halfX = layoutWidth/2; 
     int halfY = layoutHeight/2; 
System.err.println("sublayout:" + width + "," + height + "; " + halfX + "," + halfY); 

     int numberWidth = halfX - number.getMarginLeft() - number.getMarginRight(); 
     int numberHeight = layoutHeight - number.getMarginTop() - number.getMarginBottom(); 
     layoutChild(number, numberWidth, numberHeight); 
     setPositionChild(number, 0 + number.getMarginLeft(), 0 + number.getMarginTop()); 
System.err.println(number + " " + numberWidth + "," + numberHeight + " " +number.getMarginLeft()); 

     int plusWidth = halfX - plus.getMarginLeft() - plus.getMarginRight(); 
     int plusHeight = halfY - plus.getMarginTop() - plus.getMarginBottom(); 
     layoutChild(plus, plusWidth, plusHeight); 
     setPositionChild(plus, halfX + plus.getMarginLeft(), plus.getMarginTop()); 

     int minusWidth = halfX - minus.getMarginLeft() - minus.getMarginRight(); 
     int minusHeight = halfY - minus.getMarginTop() - minus.getMarginBottom(); 
     layoutChild(minus, minusWidth, minusHeight); 
     // Use plus.getMarginHeight() for better alignment. 
     setPositionChild(minus, halfX + plus.getMarginLeft(), halfY + minus.getMarginTop()); 

     //setVirtualExtent(layoutWidth, height); 
     setExtent(layoutWidth, height); 
    } 

    public EditField getNumberField() { 
     return number; 
    } 
    public void setNumberField(EditField number) { 
     this.number = number; 
    } 
    public ButtonField getPlusField() { 
     return plus; 
    } 
    public void setPlusField(ButtonField plus) { 
     this.plus = plus; 
    } 
    public Field getMinusField() { 
     return minus; 
    } 
    public void setMinusField(ButtonField minus) { 
     this.minus = minus; 
    } 
} 

Répondre

2

La chose la plus proche de ce que vous essayez d'atteindre est

enter image description here

Quelques notes:

  1. EditField Utilisez toujours USE_ALL_WIDTH. Ce n'est pas grave si vous l'avez demandé ou non. Par conséquent, si vous souhaitez limiter sa largeur, vous devez remplacer sa méthode layout(). Dans mon extrait de code, sa largeur est limitée par les caractères maximum autorisés pour la valeur de ce champ (voir CustomEditField).

  2. ButtonField ignore USE_ALL_WIDTH et USE_ALL_HEIGHT. Son étendue dépend uniquement du texte dans le bouton. Afin d'obtenir l'effet de USE_ALL_WIDTH, vous devez ajouter un remplissage horizontal.

  3. Malheureusement, l'astuce de remplissage ne fonctionnera pas si vous souhaitez obtenir l'effet USE_ALL_HEIGHT. Lorsque vous ajoutez un rembourrage vertical à un bouton, il répète à un moment donné son arrière-plan verticalement. Si c'est nécessaire, vous devrez écrire un champ de bouton personnalisé pour cela.

Vérifiez également composants de l'interface utilisateur avancé de BlackBerryat this page.

Voici le code:

import net.rim.device.api.ui.Font; 
import net.rim.device.api.ui.FontMetrics; 
import net.rim.device.api.ui.Manager; 
import net.rim.device.api.ui.UiApplication; 
import net.rim.device.api.ui.XYEdges; 
import net.rim.device.api.ui.component.ButtonField; 
import net.rim.device.api.ui.component.EditField; 
import net.rim.device.api.ui.decor.Border; 
import net.rim.device.api.ui.decor.BorderFactory; 
import net.rim.device.api.ui.text.NumericTextFilter; 

public class NumberClicker extends Manager { 

    private class CustomEditField extends EditField { 
     public int getPreferredWidth() { 
      FontMetrics fontMetrics = new FontMetrics(); 
      getFont().getMetrics(fontMetrics); 
      return getMaxSize()*fontMetrics.getMaxCharWidth(); 
     }; 

     public int getPreferredHeight() { 
      // forcing the field to be single lined 
      return getFont().getHeight(); 
     } 

     protected void layout(int width, int height) { 
      super.layout(
       Math.min(width, getPreferredWidth()), 
       Math.min(height, getPreferredHeight()) 
      ); 
     } 
    } 

    final XYEdges MARGINS = new XYEdges(2,2,2,2); 

    EditField _number; 
    Manager _numberManager; 

    ButtonField _plus; 
    ButtonField _minus; 


    public NumberClicker() { 
     super(0); 

     Font font = getFont(); 
     font = font.derive(Font.BOLD, font.getHeight() + 10); 
     _number = new CustomEditField(); 
     _number.setFilter(new NumericTextFilter()); 
     _number.setMaxSize(1); 
     _number.setFont(font); 
     setValue(1); 

     _numberManager = new Manager(0) { 
      protected void sublayout(int width, int height) {   
       layoutChild(_number, width, height); 
       setPositionChild(_number, 
        Math.max(0, (width - _number.getWidth())/2), 
        Math.max(0, (height - _number.getHeight())/2) 
       ); 
       setExtent(width, height); 
      } 
     }; 

     _numberManager.setBorder(BorderFactory.createRoundedBorder(new XYEdges())); 
     _numberManager.setMargin(MARGINS); 
     _numberManager.add(_number); 
     add(_numberManager); 

     _plus = new ButtonField("+", 0); 
     _plus.setMargin(MARGINS); 
     add(_plus); 

     _minus = new ButtonField("-"); 
     _minus.setMargin(MARGINS); 
     add(_minus); 

     _plus.setRunnable(new Runnable() { 
      public void run() { 
       increment(); 
      }   
     }); 

     _minus.setRunnable(new Runnable() { 
      public void run() { 
       decrement(); 
      }   
     }); 
    } 

    private void increment() { 
     synchronized (UiApplication.getEventLock()) { //probably not needed here. overkill. 
      _number.setText(Integer.toString(Integer.parseInt(_number.getText().trim()) + 1)); 
     } 
    } 

    private void decrement() { 
     if (Integer.parseInt(_number.getText()) <= 0) { 
      return; 
     } 

     synchronized (UiApplication.getEventLock()) { //probably not needed here. overkill. 
      _number.setText(Integer.toString(Integer.parseInt(_number.getText().trim()) - 1)); 
     } 
    } 

    public void setValue(int value) { 
     if (value < 0) { 
      return; 
     } 

     synchronized (UiApplication.getEventLock()) { // MUST. can be called from non UI thread. 
      _number.setText(Integer.toString(value)); 
     } 
    } 

    /** 
    * Compute sizes and positions of subfields. 
    */ 
    public void sublayout(int width, int height) { 
     int heightUsed = 0; 
     int halfX = width/2; 

     Border border = _plus.getBorder(); 
     int plusWidth = halfX - _plus.getMarginLeft() - _plus.getMarginRight(); 
     int plusHeight = height - _plus.getMarginTop() - _plus.getMarginBottom(); 

     // calculate horizontal padding so the button will look like USE_ALL_WIDTH 
     int plusHPadding = (Math.max(0, plusWidth - _plus.getPreferredWidth() - border.getLeft() - border.getRight()))/2; 
     _plus.setPadding(0, plusHPadding, 0, plusHPadding); 

     layoutChild(_plus, plusWidth, plusHeight); 
     setPositionChild(_plus, halfX + _plus.getMarginLeft(), _plus.getMarginTop()); 
     heightUsed += _plus.getHeight() + _plus.getMarginTop() + _plus.getMarginBottom(); 

     border = _minus.getBorder(); 
     int minusWidth = halfX - _minus.getMarginLeft() - _minus.getMarginRight(); 
     int minusHeight = height - _plus.getHeight() - _minus.getMarginTop() - _minus.getMarginBottom(); 

     // calculate horizontal padding so the button will look like USE_ALL_WIDTH 
     int minusHPadding = (Math.max(0, minusWidth - _minus.getPreferredWidth() - border.getLeft() - border.getRight()))/2; 
     _minus.setPadding(0, minusHPadding, 0, minusHPadding); 

     layoutChild(_minus, minusWidth, minusHeight); 
     setPositionChild(_minus, halfX + _plus.getMarginLeft(), heightUsed + _minus.getMarginTop()); 
     heightUsed += _minus.getHeight() + _minus.getMarginTop() + _minus.getMarginBottom(); 

     int numberWidth = halfX - _numberManager.getMarginLeft() - _numberManager.getMarginRight(); 
     int numberHeight = heightUsed - _numberManager.getMarginTop() - _numberManager.getMarginBottom(); 
     layoutChild(_numberManager, numberWidth, numberHeight); 
     setPositionChild(_numberManager, _numberManager.getMarginLeft(), _numberManager.getMarginTop()); 

     setExtent(width, heightUsed); 
    } 
} 
+0

Impressionnant, merci! Je pensais que cela impliquerait des complexités des différents composants.Nous serons heureux quand nous aurons une API GUI cohérente, raisonnablement complète et plus prévisible à utiliser, mais triste qu'elle ne sera pas basée sur Java (du moins pas sur la plateforme BlackBerry). – idarwin

+0

@idarwin Glad je pourrais aider. – mrvincenzo

Questions connexes