1

上部に「ライブ検索」フィールドがあるアイテムのリストの上部にいくつかの余分な行を表示するアプリを作成しようとしています:

リスト

もちろん、最初はオーバーライドされた setSize() で KeywordFilterField を使用してみました。しかし、これはうまくいきませんでした - setSize() がいつどのように KeywordFilterField によって呼び出されたかを制御できなかったため、描画の問題が発生しました (キーワードを入力して新しい項目を追加したときに、行が描画されませんでした)。リストなどへ)

そこで、setSize() がいつ、どのように呼び出されるかを自分で制御できるので、今度は「根元に戻って」ListField (および上部の BasicEditField) を使用しようとしています。

以下は私の簡略化されたテストコードです - src\mypackage\MyList.javaborder.png

以下で説明するフィルタリングの問題を除いて、コードはうまく機能します。

ボーダー.png

package mypackage;

import java.util.*;
import net.rim.device.api.collection.*;
import net.rim.device.api.collection.util.*; 
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.decor.*;
import net.rim.device.api.util.*;


public class MyList extends UiApplication {
    public static void main(String args[]) {
        MyList app = new MyList();
        app.enterEventDispatcher();
    }

    public MyList() {
        pushScreen(new MyScreen());
    }
} 

class MyScreen extends MainScreen {
    static final int EXTRA_ROWS = 3;

    BasicFilteredList myFilter = new BasicFilteredList();

    Background myBg = BackgroundFactory.createSolidBackground(0x111111);
    StringProvider myProvider = new StringProvider("Search");
    BasicEditField myFind = new BasicEditField(USE_ALL_WIDTH) {
        protected void paint(Graphics g) {
            if (getTextLength() == 0) {
                g.setColor(Color.LIGHTGRAY);
                g.drawText(myProvider.toString(), 0, 0);
            }

            g.setColor(Color.BLACK);
            super.paint(g);
        }
    };

    MyItemList myItems = new MyItemList();

    // add 1 row for the "* Empty *" string
    ListField myList = new ListField(EXTRA_ROWS + 1) {
        protected boolean navigationClick(int status, int time) {
            int index = getSelectedIndex();
            if (index >= EXTRA_ROWS && myItems.size() > 0) {
                String str = ((MyItem) myItems.getAt(
                    index - EXTRA_ROWS)).toString();
                Status.show("You have clicked - " + str);
            }
            return true;
        }
    };

    Border myBorder = BorderFactory.createBitmapBorder(
        new XYEdges(12, 12, 12, 12),
        Bitmap.getBitmapResource("border.png"));

    public MyScreen() {
        getMainManager().setBackground(myBg);

        myFind.setBorder(myBorder);
        setTitle(myFind);

        myItems.doAdd(new MyItem(1, "Eins"));
        myItems.doAdd(new MyItem(2, "Zwei"));
        myItems.doAdd(new MyItem(3, "Drei"));
        myItems.doAdd(new MyItem(4, "Vier"));

        myList.setCallback(new MyListFieldCallback());
        add(myList);

        myFilter.addDataSet(1, myItems.getElements(), "Test",
            BasicFilteredList.COMPARISON_IGNORE_CASE);
    }

    protected boolean keyChar(char key, int status, int time) {
        if (key == Characters.BACKSPACE && myFind.getTextLength() == 0) {
            Status.show("Kill kill kill!");
            return true;
        }

        if (myFind.getTextLength() > 0) {
            System.err.println("XXX filter for " + myFind.getText());
        }

        return super.keyChar(key, status, time);
    }

    private class MyListFieldCallback implements ListFieldCallback {

        public void drawListRow(ListField list, Graphics g, int index, int y, int width) {
            Font i = getFont().derive(Font.ITALIC);

            g.setColor(Color.DIMGRAY);
            g.drawLine(0, y-9, width, y-9);
            g.setColor(Color.WHITE);

            if (index < EXTRA_ROWS) {
                g.setFont(i);
                g.drawText("Add Item", 0, y, DrawStyle.ELLIPSIS|DrawStyle.HCENTER, width);
                return;
            } 

            if (myItems.size() == 0) {
                g.setFont(i);
                g.drawText(list.getEmptyString(), 0, y, DrawStyle.ELLIPSIS|DrawStyle.HCENTER, width);
                return;
            }

            MyItem item = (MyItem) myItems.getAt(index - EXTRA_ROWS);
            g.drawText(item.toString(), 0, y, DrawStyle.ELLIPSIS|DrawStyle.HCENTER, width);
        }

        public Object get(ListField list, int index) { 
            return myItems.getAt(index); 
        }

        public int getPreferredWidth(ListField list) { 
            return Display.getWidth(); 
        }

        public int indexOfList(ListField list, String prefix, int start) { 
            return 0; 
        }
    }

    class MyItemList extends SortedReadableList {
        public MyItemList() {
            super(new MyItem.MyComparator());        
        } 

        protected void doAdd(Object obj) {
            super.doAdd(obj);
            myList.setSize(size() + EXTRA_ROWS);  
        }

        protected boolean doRemove(Object obj) {
            // if the list is empty, add 1 row for "* Empty *" string
            int size = (size() == 0 ? EXTRA_ROWS + 1 : size() - 1 + EXTRA_ROWS);
            myList.setSize(size);
            return super.doRemove(obj);        
        }

        protected Object[] getElements() {
            return super.getElements();
        }
    }
}

class MyItem {
    int _num;
    String _name;

    public MyItem(int num, String name) {
        _num = num;
        _name = name;
    }

    public String toString() {
        return _num + ": " + _name;
    }

    static class MyComparator implements Comparator {
        public int compare(Object obj1, Object obj2) {
            MyItem item1 = (MyItem) obj1;
            MyItem item2 = (MyItem) obj2;

            return item1.toString().compareTo(item2.toString());
        }
    }

    static class MyProvider implements KeywordProvider {
        public String[] getKeywords(Object obj) {
            MyItem item = (MyItem) obj;
            return new String[]{ Integer.toString(item._num), item._name };
        }
    }
}

私の問題は、フィルタリングを追加する方法がわからないことです。

たとえば、ユーザーが myFind に「E」を入力すると、私のコードは keyChar() でこのイベントを検出し、フィルタリングされた結果が 1 つあるため、myList.setSize(EXTRA_ROWS + 1) を呼び出す必要があることも理解しています。

しかし、myList によって表示される項目をどのようにフィルター処理すればよいのでしょうか。これを実装するにはどうすればよいでしょうか?

多分私はBasicFilteredListとそのメソッドを使うことができます

public void addDataSet(int id,
                       Object[] objects,
                       String name,
                       long style)

しかし、ここでそれを適用する方法がわかりませんか?

アップデート:

上記のテスト コードに BasicFilteredList を追加しましたが、それを ListField と結合する方法がまだわかりません。

4

2 に答える 2

2

コードのどこかでフィルタリングを実行してから、結果を保存する必要があります。myFind.update(int)をオーバーライドして、フィルタリングテキストが変更されたときにフィルタリングを実行します。myItemsに加えて、myFilteredItemsを保存する必要があります。フィルタリング後、リストフィールドでsetSize()を呼び出します。リストフィールドの描画コードも、フィルタリングされたコレクションから描画する必要があります。次に、設定する必要があります。

于 2011-05-17T18:15:46.217 に答える
2

私にとってはうまくいくと思われるこのコードになりました(以下にリストされている2つの小さな問題を除く)。緑色の回答マークは、貴重な提案のためにMichael Donohueに送られます。

myData と myFilteredData の 2 つのベクトルを使用します。UI には、ListField と BasicEditField を使用します。

リスト

ボーダー.png:

ボーダー.png

src\mypackage\MyList.java:

package mypackage;

import java.util.*;
import net.rim.device.api.collection.*;
import net.rim.device.api.collection.util.*; 
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.ui.decor.*;
import net.rim.device.api.util.*;


public class MyList extends UiApplication {
    public static void main(String args[]) {
        MyList app = new MyList();
        app.enterEventDispatcher();
    }

    public MyList() {
        pushScreen(new MyScreen());
    }
} 

class MyScreen extends MainScreen {
    static final int EXTRA_ROWS = 3;

    Background myBg = BackgroundFactory.createSolidBackground(0x111111);
    StringProvider myProvider = new StringProvider("Search");
    BasicEditField myFind = new BasicEditField(USE_ALL_WIDTH|TextField.NO_NEWLINE) {
        protected void paint(Graphics g) {
            if (getTextLength() == 0) {
                g.setColor(Color.LIGHTGRAY);
                g.drawText(myProvider.toString(), 0, 0);
            }

            g.setColor(Color.BLACK);
            super.paint(g);
        }

        protected void update(int delta) {
            filterData(getText());
        }
    };

    Vector myData = new Vector();
    final static SimpleSortingVector myFilteredData = new SimpleSortingVector();

    // add 1 row for the "* Empty *" string
    ListField myList = new ListField(EXTRA_ROWS + 1) {
        protected boolean navigationClick(int status, int time) {
            int index = getSelectedIndex();
            if (index >= EXTRA_ROWS && myFilteredData.size() > 0) {
                String str = ((MyItem) myFilteredData.elementAt(index - EXTRA_ROWS)).toString();
                Status.show("You have clicked - " + str);
            }
            return true;
        }
    };

    Border myBorder = BorderFactory.createBitmapBorder(
        new XYEdges(12, 12, 12, 12),
        Bitmap.getBitmapResource("border.png"));

    public MyScreen() {
        getMainManager().setBackground(myBg);

        myFind.setBorder(myBorder);
        setTitle(myFind);

        myData.addElement(new MyItem(1, "Eins"));
        myData.addElement(new MyItem(2, "Zwei"));
        myData.addElement(new MyItem(3, "Drei"));
        myData.addElement(new MyItem(4, "Vier"));

        myFilteredData.setSortComparator(new MyItem.MyComparator());
        filterData("");

        myList.setCallback(new MyListFieldCallback());
        add(myList);
    }

    private void filterData(String prefix) {
        myFilteredData.removeAllElements();
        if (prefix == null || prefix.length() == 0) {
            // no prefix specified - copy everything
            for (int i = myData.size() - 1; i >= 0; i--) {
                MyItem item = (MyItem) myData.elementAt(i);
                myFilteredData.addElement(item);
            }
        } else {
            // copy only strings starting with prefix
            for (int i = myData.size() - 1; i >= 0; i--) {
                MyItem item = (MyItem) myData.elementAt(i);
                String name = item.name.toLowerCase();

                if (name.startsWith(prefix.toLowerCase())) {
                    myFilteredData.addElement(item);
                }
            }
        }
        myFilteredData.reSort();

        // if the list is empty, add 1 row for "* Empty *" string
        int size = (myFilteredData.size() == 0 ? EXTRA_ROWS + 1 : myFilteredData.size() + EXTRA_ROWS);
        myList.setSize(size);
    }

    protected boolean keyChar(char key, int status, int time) {
        if (key == Characters.BACKSPACE && myFind.getTextLength() == 0) {
            int index = myList.getSelectedIndex();
            if (index >= EXTRA_ROWS && myFilteredData.size() > 0) {
                String str = ((MyItem) myFilteredData.elementAt(index - EXTRA_ROWS)).toString();
                Status.show("You're deleting - " + str);
            }
            return true;
        }

        return super.keyChar(key, status, time);
    }

    static class MyListFieldCallback implements ListFieldCallback {
        public void drawListRow(ListField list, Graphics g, int index, int y, int width) {
            Font i = g.getFont().derive(Font.ITALIC);

            g.setColor(Color.DIMGRAY);
            g.drawLine(0, y-9, width, y-9);
            g.setColor(Color.WHITE);

            if (index < EXTRA_ROWS) {
                g.setFont(i);
                g.drawText("Add Item", 0, y, DrawStyle.ELLIPSIS|DrawStyle.HCENTER, width);
                return;
            } 

            if (myFilteredData.size() == 0) {
                g.setFont(i);
                g.drawText(list.getEmptyString(), 0, y, DrawStyle.ELLIPSIS|DrawStyle.HCENTER, width);
                return;
            }

            MyItem item = (MyItem) myFilteredData.elementAt(index - EXTRA_ROWS);
            g.drawText(item.toString(), 0, y, DrawStyle.ELLIPSIS|DrawStyle.HCENTER, width);
        }

        public Object get(ListField list, int index) { 
            return myFilteredData.elementAt(index); 
        }

        public int getPreferredWidth(ListField list) { 
            return Display.getWidth(); 
        }

        public int indexOfList(ListField list, String prefix, int start) { 
            return myFilteredData.indexOf(prefix, start);
        }
    }
}

class MyItem {
    int num;
    String name;

    public MyItem(int num, String name) {
        this.num = num;
        this.name = name;
    }

    public String toString() {
        return num + ": " + name;
    }

    static class MyComparator implements Comparator {
        public int compare(Object obj1, Object obj2) {
            MyItem item1 = (MyItem) obj1;
            MyItem item2 = (MyItem) obj2;

            String name1 = item1.toString().toLowerCase();
            String name2 = item2.toString().toLowerCase();

            return name1.compareTo(name2);
        }
    }
}

私の小さな問題は次のとおりです。

  1. 線を描画するために drawListRow() で 9 を引く必要があるのはなぜですか?
  2. 使用後に BasicEditField でキャレットが消えるのはなぜですか?

スクリーンショット

于 2011-05-18T11:55:54.473 に答える