Пользовательская ошибка BitmapField при расфокусировке и прокрутке (BlackBerry)

У меня была эта досадная проблема при попытке реализовать галерею изображений на BlackBerry 6.

Все работает, однако, когда фокус изменяется от верхних кнопок, чтобы сказать картинки дальше по экрану, изображения, кажется, сбои и не правильно рисуют себя. Пожалуйста, смотрите изображения ниже для примера:

(Фокус на верхней части экрана (не показан))начальный экран

(Фокус теперь на левом нижнем изображении, обратите внимание, что верхнее изображение теперь пусто по неизвестной причине)

после экрана прокрутки

И это происходит независимо от того, сколько фотографий я добавляю в галерею миниатюр.

Теперь вот мой код (часть, касающаяся рисования миниатюр)

public ProductImage(String productName){
    super(VERTICAL_SCROLL|VERTICAL_SCROLLBAR);

    currentProduct = productName;

    createGUI(); 
}
public void createGUI(){
    deleteAll();
    try{
        Storage.loadPicture();
    }catch(NullPointerException e){
        e.printStackTrace();
    }
    this.setTitle(new LabelField(_resources.getString(PRODUCT_IMAGE), Field.FIELD_HCENTER));
    if(ToolbarManager.isToolbarSupported())
    {
        Toolbar tb = new Toolbar();
        setToolbar(tb.createToolBar());
    }
    else{
        Toolbar tb = new Toolbar();
        add(tb.createNavBar());
    }

    picVector = Storage.getPicture(currentProduct);

    EncodedImage enc = EncodedImage.getEncodedImageResource("camera.png");
    EncodedImage sizeEnc = ImageResizer.sizeImage(enc, Display.getHeight(), Display.getHeight());

    takenPicture = new BitmapField(enc.getBitmap());

    vfMain = new VerticalFieldManager();
    vfMain.add(logo);
    vfMain.add(new SeparatorField());
    add(vfMain);
    prepareBmpFields();
}   

 private void prepareBmpFields() {

        System.out.println("This is the vector size: " + picVector.getPicVector().size());

        LayoutManager manager = new LayoutManager();


        FieldChangeListener itemListener = new ButtonListener(); 


        mBmpFields = new ImageButtonField[picVector.getPicVector().size()];

        for (int i = 0; i < picVector.getPicVector().size(); i++) {
                /*EncodedImage image = EncodedImage
                                .getEncodedImageResource((String)imageVector.elementAt(i));*/
            byte[] data = getData((String)picVector.getPicVector().elementAt(i));
            //Encode and Resize image 
            EncodedImage  eImage = EncodedImage.createEncodedImage(data,0,data.length);

             eImage = ImageResizer.resizeImage(eImage, mImgWidth, mImgHeight);
             ImageButtonField currentImage = new ImageButtonField(eImage.getBitmap());
             currentImage.setAssociatedPath((String)picVector.getPicVector().elementAt(i));
             mBmpFields[i] = currentImage;
             mBmpFields[i].setChangeListener(itemListener);
             manager.add(mBmpFields[i]);

        }
        vfMain.add(manager);
    }

    private class LayoutManager extends VerticalFieldManager {
        public LayoutManager() {
            super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
        }

        protected void sublayout(int width, int height) {
            int columns = mScrWidth / (mImgWidth + 2 * mImgMargin);

            int scrWidth = Display.getWidth();

              int rows = mBmpFields.length / columns
                + (mBmpFields.length % columns > 0 ? 1 : 0);
              int counter = 0;
              for (int i = 0; i < rows; i++) {
               for (int j = 0; j < columns; j++) {
                int posX = j * (mImgWidth + 2 * mImgMargin) + mImgMargin;
                int posY = i * (mImgHeight + 2 * mImgMargin) + mImgMargin;

                if(mBmpFields.length > counter){
                    Field field = mBmpFields[counter];
                    layoutChild(field, mImgWidth, mImgHeight);
                    setPositionChild(field, posX, posY);
                    counter++;
                };
               }  
             }
              if(Display.getWidth() < Display.getHeight()){
                setExtent(mScrWidth, (int)(mScrHeight*1.25));
                }
              else{
                  setExtent(mScrWidth, (int)(mScrHeight*2)); 
              }
        }


        public int getPreferredWidth() {
            return mScrWidth;
        }
        public int getPreferredHeight() {
            return mScrHeight;
        }
    }
}

Я удалил много несоответствующих частей кода, но необходимый код есть.

Кто-нибудь знает, что может быть причиной этой проблемы? Спасибо за вашу помощь!

Редактировать: по запросу, вот моя реализация класса ImageButtonField:

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.BitmapField;

public class ImageButtonField extends BitmapField{

String associatedPath ="";
BitmapField image2;

public ImageButtonField(Bitmap image) {
    super(image);
}
public void setAssociatedPath(String path){
    associatedPath = path;
}
public String getAssociatedPath(){
    return associatedPath;
}
public boolean isFocusable() {
    return true;
}
protected void applyTheme(Graphics arg0, boolean arg1) {
}

protected void drawFocus(Graphics graphics, boolean on) {
}
protected void onFocus(int direction) {
      // only change appearance if this button is enabled (aka editable)
      if (isEditable()) {
         invalidate();  // repaint
      } 
      super.onFocus(direction);
   }

   public void onUnfocus() {
      invalidate();  // repaint
      super.onUnfocus();
   }
protected boolean navigationClick(int status, int time) {
    fieldChangeNotify(0);
    return true;
}

protected boolean trackwheelClick(int status, int time) {
    fieldChangeNotify(0);
    return true;
}

protected void paint(Graphics graphics) {
    super.paint(graphics);
    if (isFocus()) {
        graphics.setGlobalAlpha(128);
        graphics.setColor(0x888888);
        graphics.fillRect(0, 0, getWidth(), getHeight());
    }else{
        graphics.setGlobalAlpha(0);
        graphics.setColor(0x000000);
        graphics.fillRect(0, 0, getWidth(), getHeight());
        //graphics.drawBitmap(0, 0, getWidth(), getHeight(), image2.getB, 0, 0);
    }
}

protected boolean keyChar(char character, int status, int time) {
    if(Characters.ENTER == character || Characters.SPACE == character) {
        fieldChangeNotify(0);
        return true;
    }
    return super.keyChar(character, status, time);
}

}

2 ответа

Решение

Итак, вы можете не обращать внимания на мой первый ответ, но так как у меня не было вашего ImageButtonField код в то время, я не хочу выбрасывать его... может быть, кто-то найдет это полезным.

В конце концов, мне не нужно было вносить какие-либо изменения в ImageButtonField, но я изменил ваш LayoutManager учебный класс. Я понял, что это проблема, и начал заменять ваши пользовательские классы пользовательского интерфейса на встроенные. Я заменил ImageButtonField с BitmapField, Это не исправило это. Затем я заменил LayoutManager с FlowFieldManager и это исправило. Итак, я знал, где проблема.

Мое решение:

private class LayoutManager extends Manager {
  public LayoutManager() {
     super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
  }

  protected void sublayout(int width, int height) {
     setExtent(width, height);
     // TODO: maybe always set the same virtual extent?
     if (Display.getWidth() < Display.getHeight()) {
        setVirtualExtent(mScrWidth, (int) (mScrHeight * 1.25));
     } else {
        setVirtualExtent(mScrWidth, (int) (mScrHeight * 2));
     }

     int columns = mScrWidth / (mImgWidth + 2 * mImgMargin);
     // int scrWidth = Display.getWidth();

     int rows = mBmpFields.length / columns + (mBmpFields.length % columns > 0 ? 1 : 0);
     int counter = 0;
     for (int i = 0; i < rows; i++) {
        for (int j = 0; j < columns; j++) {
           int posX = j * (mImgWidth + 2 * mImgMargin) + mImgMargin;
           int posY = i * (mImgHeight + 2 * mImgMargin) + mImgMargin;

           if (mBmpFields.length > counter) {
              Field field = mBmpFields[counter];
              layoutChild(field, mImgWidth, mImgHeight);
              setPositionChild(field, posX, posY);
              counter++;
           }
        }
     }
  }

  public int getPreferredWidth() {
     return mScrWidth;
  }

  public int getPreferredHeight() {
     return mScrHeight;
  }
}

Я не могу точно сказать, что понимаю, почему ваш исходный код не работал, но я могу сказать, что я не сделал бы несколько вещей в исходном коде:

  1. Исходный код расширялся VerticalFieldManager но делал всю работу сам, в sublayout(), Так что я не думаю, что было какое-то расширение VerticalFieldManager, Я изменил его, чтобы просто продлить Manager,

  2. Оригинальный код звонил setExtent() с разными размерами. Я не думаю, что это то, что вы хотели. Степень - это фактический размер Field, Виртуальный экстент - это виртуальный размер, который вы хотите установить большим, чем фактический экстент, чтобы включить прокрутку. Вам не нужно динамически вычислять различные экстенты для портрета и ландшафта, потому что width а также height параметры переданы sublayout() уже будет отражать это. Я не уверен, что вам действительно нужно устанавливать разные виртуальные экстенты. Я думаю, что вам, вероятно, следует всегда устанавливать высоту виртуального экстента равной количеству строк, умноженному на высоту изображения, с учетом полей.

  3. У вас была неиспользованная переменная scrWidth в вашем оригинальном коде. Я прокомментировал это выше.

Вы также недавно опубликовали этот вопрос, верно? Я прав, если предположить, что ImageButtonField Вы ссылаетесь здесь на тот же, над которым вы работали в другом вопросе?

Я не вижу вашей полной реализации ImageButtonField, который вы, вероятно, должны опубликовать здесь тоже. Однако, глядя на ответы на ваш другой вопрос, я чувствую, что вы выполняете некоторую пользовательскую обработку фокуса в ImageButtonFieldи, возможно, это не совсем правильно. В любом случае, этот класс может быть там, где проблема.

У меня похожий Field мой собственный подкласс, и вот методы обработки фокуса, которые я определяю:

public class CustomButtonField extends Field {

   private Bitmap _button;    // the currently displayed button image
   private Bitmap _on;        // image for 'on' state (aka in-focus)
   private Bitmap _off;       // image for 'off' state (aka out-of-focus)

   protected void onFocus(int direction) {
      // only change appearance if this button is enabled (aka editable)
      if (isEditable()) {
         _button = _on;
         invalidate();  // repaint
      } 
      super.onFocus(direction);
   }

   protected void onUnfocus() {
      _button = _off;
      invalidate();  // repaint
      super.onUnfocus();
   }

   protected void drawFocus(Graphics graphics, boolean on) {
      // override superclass implementation and do nothing
   }

   public boolean isFocusable() {
      return true;
   }

У меня также есть пользовательская реализация paint(), Я не буду показывать все это здесь, потому что большая часть кода, вероятно, не имеет ничего общего с вашей проблемой, но мой paint() действительно включает этот вызов:

graphics.drawBitmap(_padding, _padding, _fieldWidth, _fieldHeight, _button, 0, 0);

Возможно, вас не волнует тот факт, что у меня есть отдельные изображения для сфокусированных и несфокусированных состояний... может быть, вы всегда показываете одно и то же изображение.

Но, наверное, стоит проверить onFocus() а также onUnfocus() методы. Вам может понадобиться добавить вызов invalidate() как и у меня.

Глядя на ответ Рупака на ваш другой вопрос, было бы также хорошо проверить ваш ImageButtonField.paint() метод, и убедитесь, что вы не пренебрегаете делать важные шаги рисования, если поле не в фокусе.

Другие вопросы по тегам