【问题标题】:labelField.getWidth() returns 0? Why does this happen?labelField.getWidth() 返回 0?为什么会这样?
【发布时间】:2012-07-29 15:50:00
【问题描述】:

我正在开发自己的自定义管理器,到目前为止我已经完成了它,但是它使用屏幕分辨率的百分比来设置边距。

我是这样称呼以下类的:

LabelIconCommandManager licm3 = new LabelIconCommandManager("Address blah bklahblah ", 0);
licm3.add(new ImageButtonField(b1, b2, b3, Field.FIELD_LEFT | ImageButtonField.CONSUME_CLICK));

这是类 [我在评论中标记了它返回 0 和返回 219 的位置。请告诉我为什么会发生这种情况:

public class LabelIconCommandManager extends HorizontalFieldManager implements  BCMSField
{
    LabelIconCommandManager me = this;
    EvenlySpacedHorizontalFieldManager buttonManager = new EvenlySpacedHorizontalFieldManager(0);
    LabelField labelField;
    int side = 0;
    int HPADDING = 3;
    int VPADDING = 4;
    int screenWidth = Display.getWidth();
    int labelField_width = 40;
    public LabelIconCommandManager()
    {
        this("", 0);
    }
    public LabelIconCommandManager(String label, long style)
    {
        super(USE_ALL_WIDTH| FOCUSABLE);
        this.setBorder(BorderFactory.createBitmapBorder(new XYEdges(15, 20, 15, 20),Bitmap.getBitmapResource( "border_edit.png" )));
        this.setMargin(1,10,1,10);
        labelField = new LabelField(label,LabelField.ELLIPSIS)
        {
            public void layout(int width, int height)
            {
                // Done because otherwise ellipses dont work with labelfields
                super.layout((int)(screenWidth * 0.61), getHeight());
                setExtent((int)(screenWidth * 0.61), getHeight());
                labelField_width = labelField.getWidth();
                DisplayDialog.alert("labelField_width = " + labelField_width); // returns 219
            }
        };
        // Top Right Bottom Left
        labelField.setMargin(VPADDING, HPADDING, VPADDING, 0);
        // super because we want this horizontalfieldManager to add it
        super.add(labelField);
        super.add(buttonManager);
    }
    public void alternateConstructor(Attributes atts)
    {
        labelField = new LabelField(atts.getValue("label"), 0);
    }
    public void onFocus(int direction)
    {
        this.setBorder(BorderFactory.createBitmapBorder(new XYEdges(15, 20, 15, 20),Bitmap.getBitmapResource( "border_edit_select.png" )));
        // uses the same color as listStyleButtonField selections
        this.setBackground(BackgroundFactory.createSolidBackground(0x186DEF));
        super.onFocus(direction);
    }
    //Invoked when a field loses the focus.
    public void onUnfocus()
    {
        //top, right,bottom,left
        this.setBorder(BorderFactory.createBitmapBorder(new XYEdges(15, 20, 15, 20),Bitmap.getBitmapResource( "border_edit.png" )));
        this.setBackground(BackgroundFactory.createSolidTransparentBackground(Color.GRAY, 0));
        super.onUnfocus();
        invalidate();
    }
    // Overrride this managers add function
    public void add(Field imageButton)
    {
        // Add a button to the evenly spaced manager
        buttonManager.add(imageButton);
        // Based on how many buttons there are, set the margin of where the manager holding the buttons start [offset from labelField]
        if(buttonManager.getFieldCount() == 1)
        {
            //side = (int)(screenWidth * 0.1388);
            side = screenWidth - labelField_width - 32 - 10 - 15;
            DisplayDialog.alert("Screen Width = " + screenWidth);
            DisplayDialog.alert("labelField_width2 = " + labelField_width); // returns 0
            DisplayDialog.alert("Side = " + side);
        }
        else side = (int)(screenWidth * 0.05);
        buttonManager.setMargin(0,0,0,side);
    }
    public int getLabelWidth()
    {
        return labelField_width;
    }
}  

为了更清楚,这里有一张图片:

【问题讨论】:

  • 这个边栏怎么用?
  • 感谢所有的答案 - 我会尽快尝试一切。我使用“side”变量来计算从 labelfield 末端到 buttonManager 开始所需的距离。为了更清楚,我贴了一张图片。

标签: blackberry horizontalfieldmanager


【解决方案1】:

请查看下面的代码。它是具有标签和按钮的经理。它把标签放在左边,按钮放在右边。

import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.decor.Border;

import java.util.Vector;

public class TabFieldManager extends Manager {

public TabFieldManager(long style) {
    super(style);
}

protected void sublayout(int width, int height) {
    LabelField label = null;

    Vector tabs = new Vector();
    int tabsWidth = 0;
    int tabHeight = 0;
    int tabPaddingTop = 0;
    int tabPaddingLeft = 0;

    for (int i=0; i < getFieldCount(); i++) {
        Field field = getField(i);
        if (field instanceof LabelField) {
            label = (LabelField) field;
        } else if (field instanceof ButtonField){
            tabs.addElement(field);

            layoutChild(field, width, height);

            int fieldwidth = field.getWidth() > 0 ? field.getWidth() : field.getPreferredWidth() ;
            tabsWidth += fieldwidth + getBorderAndPaddingWidth(field);

            int fieldHeight = field.getHeight() > 0 ? field.getHeight() : field.getPreferredHeight();
            if (fieldHeight > tabHeight) {
                tabHeight = getBorderAndPaddingHeight(field) + fieldHeight;
            }

            int fieldPaddingTop = field.getPaddingTop();
            if (fieldPaddingTop > tabPaddingTop) {
                tabPaddingTop = fieldPaddingTop;
            }

            int fieldPaddingLeft = field.getPaddingLeft();
            if (fieldPaddingLeft > tabPaddingLeft) {
                tabPaddingLeft = fieldPaddingLeft;
            }
        }
    }

    if (label != null) {
        layoutChild(label, width - tabsWidth, height);
        int y = tabHeight - label.getHeight() >> 1;
        setPositionChild(label, tabPaddingLeft , y);
    }
    for (int i = 0; i < tabs.size(); i++) {
        Field tabField = (Field) tabs.elementAt(i);
        setPositionChild(tabField, width - tabsWidth, getBorderAndPaddingHeight(tabField));
        tabsWidth -= tabField.getWidth() + getBorderAndPaddingWidth(tabField);
    }

    setExtent(width, tabHeight);
}

private int getBorderAndPaddingHeight( Field field ) {
    int height = field.getPaddingTop() + field.getPaddingBottom();
    Border border = field.getBorder();
    if( border != null ) {
        height += border.getTop() + border.getBottom();
    }

    return height;
}

private int getBorderAndPaddingWidth( Field field ){
    int width = field.getPaddingLeft() + field.getPaddingRight();
    Border border = field.getBorder();
    if( border != null ) {
        width += border.getLeft() + border.getRight();
    }
    return width;
}

protected int moveFocus(int amount, int status, int time) {
    if ((status & Field.STATUS_MOVE_FOCUS_VERTICALLY) == Field.STATUS_MOVE_FOCUS_VERTICALLY && amount > 0) {
        return amount;
    } else
        return super.moveFocus(amount, status, time);
}

protected int nextFocus(int amount, int axis) {
    if (amount > 0 && axis == Field.AXIS_VERTICAL)
        return -1;
    else
        return super.nextFocus(amount, axis);
}

}

【讨论】:

    【解决方案2】:

    来自 Nate 帖子的一些简短摘要。

    当您构建管理器并添加字段时,不要期望它会正确布局。经理不知道上下文 - 它将被放置在哪里。 所以只有当你将他的经理添加到屏幕时才会调用字段的布局方法(当经理的布局也会被调用时)。这是正确的。

    side 变量的计算移至layout 方法。

    如果您真的需要side 值,然后再将经理放到屏幕上。您可以使用Field.getPrefferedWidth() 预先计算它,它为标准字段返回有意义的值(getFont().getAdvance(text) 用于LabelField,可能还有边界,请自行检查)。但要小心这个值。

    【讨论】:

      【解决方案3】:

      注意:当我运行您的代码时,我实际上并没有看到 labelField_width 设置为 0。您在上面发布的代码中将值初始化为40。所以,我有时确实会看到它设置为 40 或 219(在 360 像素宽的屏幕上)。

      但是,问题在于我认为您正试图过早地访问 labelField_width 的值。唯一正确分配的位置是匿名LabelFieldlayout() 方法。仅仅因为您根据实例化声明和实现layout() 方法,并不意味着在创建LabelField 时调用它。这其实也是我不喜欢匿名类的原因之一。

      不管怎样,这段代码:

      LabelIconCommandManager licm3 = new LabelIconCommandManager("Address blah bklahblah ", 0); 
      licm3.add(new ImageButtonField(b1, b2, b3, Field.FIELD_LEFT | ImageButtonField.CONSUME_CLICK));
      

      将首先实例化LabelField(在LabelIconCommandManager 构造函数内)。正如我所说,这不会触发layout() 方法。上面的第二行 (add()) 将触发您覆盖的方法:

      // Overrride this managers add function 
      public void add(Field imageButton) 
      { 
      

      这是您看到 labelField_width 的错误值的地方。该方法在layout() 之前被调用。这就是问题所在。

      由于您似乎只使用该宽度来设置buttonManager 边距,因此您可以稍等片刻。如果您等到LabelIconCommandManager sublayout() 方法被调用,您的LabelField 将调用其layout() 方法,并正确分配labelField_width

      protected void sublayout(int maxWidth, int maxHeight) {
         // make sure to call superclass method first!
         super.sublayout(maxWidth, maxHeight);
      
         // now, we can reliably use the label width:
         side = screenWidth - labelField_width - 32 - 10 - 15; 
         buttonManager.setMargin(0,0,0,side); 
      }
      

      该方法位于LabelIconCommandManager 类中。然后,您可以删除您调用的另一个地方buttonManager.setMargin()

      【讨论】:

      • @Eugen,是的,我的意思不是像 C++ 这样的语言中的关键字 inline 那样的“内联”。但是,在一般英语意义上,“内联”一词的意思是“在一条线上”,或“共线”。因此,匿名类的声明和定义与其实例化是内联的,这与普通的 java 类不同,后者是在它实例化的其他地方声明和定义的。我要指出的问题是,对于初学者来说,这可能会产生误导,因为在这种情况下,它可能看起来像方法 layout() 可能会在实例化时调用,当然不是。
      • @Eugen,没问题。这实际上是一个很棒的评论。我稍微改变了措辞,希望能清楚地表明我指的不是其他语言中存在的 inline 概念。谢谢!
      猜你喜欢
      • 2012-09-25
      • 1970-01-01
      • 1970-01-01
      • 2023-02-24
      • 2013-08-09
      • 2015-08-18
      • 2020-01-07
      • 2011-10-23
      • 1970-01-01
      相关资源
      最近更新 更多