EDIT Recursion is required for the counter increment.
I have a GUI that adds entered fields to a ListView, but also adds the name of the object to a TableView beside it and displays four substring counts. They are Plant objects, and it's supposed to display in the ListView (which it does), and then display the name with each occurrence of a certain substring:
See here:
I don't understand what I'm missing, because in my addButtonClick method, I call my recursive method. The logic seems correct to me in the method, so I must be missing something in my Integer properties, or a constructor.
Here is the method in the Controller for the add button click. There is a combo box where a user can choose Flower, Fungus, Weed, or Herb. And when the user clicks a respective plant type, respective radio buttons appear that are related to certain traits. All of that works. I will show the Flower section of code:
/*
Adds respective plant type and resets controls
*/
public void handleAddButtonClick(ActionEvent event) {
if (idInput != null && nameInput != null & colorInput != null) {
if (plantType.getValue().equals("Flower")) {
Flower flower = new Flower(ID, idNum, name, color, smell, thorns, edible, poisonous, flavor, medicine, seasonal);
flower.setID(idInput.getText());
flower.setName(nameInput.getText());
flower.setColor(colorInput.getText());
flower.setSmell(scentedRadio.isSelected());
flower.setThorns(thornyRadio.isSelected());
observablePlantList.add(flower);
//this is where the table information gets added.
//it adds it, just displays 0's.
flower.setPlantName(nameInput.getText());
Plant.substringCounter(name, "e"); //tried flower instead
Plant.substringCounter(name, "ar");//of Plant. still nothing.
Plant.substringCounter(name, "er");
Plant.substringCounter(name, "o");
observableAnalysisList.add(flower);
//just doing some debug printing. this prints 0
System.out.println(Plant.substringCounter(name, "e"));
//more debugging. this prints fine because of toString() method
System.out.println(flower);
Here is the relevant code in the main class and the Flower class:
//Plant Table properties ("e", "o", "ar", "er")
public StringProperty plantName = new SimpleStringProperty(this, "plantName", "");
public String getPlantName() {return plantName.get(); }
public StringProperty plantNameProperty() {return plantName; }
public void setPlantName(String plantName) {this.plantName.set(plantName); }
public IntegerProperty countLetterE = new SimpleIntegerProperty(this, "countLetterE", 0);
public int getLetterE() {return countLetterE.get();}
public IntegerProperty eProperty() {return countLetterE; }
public void setCountLetterE(int countLetterE) {this.countLetterE.set(countLetterE);}
public IntegerProperty countLetterO = new SimpleIntegerProperty(this, "countLetterO", 0);
public int getLetterO() {return countLetterO.get(); }
public IntegerProperty oProperty() {return countLetterO; }
public void setCountLetterO(int countLetterO) {this.countLetterO.set(countLetterO);}
public IntegerProperty countLetterER = new SimpleIntegerProperty(this, "countLetterER", 0);
public int getLetterER() {return countLetterER.get(); }
public IntegerProperty erProperty() {return countLetterER; }
public void setCountLetterER(int countLetterER) {this.countLetterER.set(countLetterER);}
public IntegerProperty countLetterAR = new SimpleIntegerProperty(this, "countLetterAR", 0);
public int getLetterAR() {return countLetterAR.get(); }
public IntegerProperty arProperty() {return countLetterAR; }
public void setCountLetterAR(int countLetterAR) {this.countLetterAR.set(countLetterAR);}
Recursive method:
public static int substringCounter(String plantName, String letters) {
plantName = plantName.toLowerCase();
if(plantName.isEmpty()) {
return 0;
}
if(plantName.indexOf(letters) == -1) {
return 0;
}
return 1 + substringCounter(plantName.substring(plantName.indexOf(letters) + 1), letters);
}
//toString method for Plant class to display in ListView. Works fine.
public String toString() {
return "ID: " + this.ID + "-" + this.idNum + ", Name: " + this.name + ", Color: " + this.color;
}
}
Flower class
public class Flower extends Plant {
public Flower(String ID, int idNum, String name, String color, boolean smell, boolean thorns, boolean edible, boolean poisonous, boolean flavor, boolean medicine, boolean seasonal) {
super(ID, idNum, name, color, smell, thorns, edible, poisonous, flavor, medicine, seasonal);
}
public void setSmell(boolean smell) {
this.smell = smell;
}
public void setThorns(boolean thorns) {
this.thorns = thorns;
}
//toString method for the ListView only. All works fine here
public String toString() {
return super.toString() + ", Scent? " + this.smell + ", Thorns? " + this.thorns;
}
}
I sincerely hope I either 1) gave you enough information, or 2) didn't give you too much information. Thank you all for any help offered.
You are invoking a static method on a string and return a number which effectively results in absolutely nothing when you call it like that:
Plant.substringCounter(name, "e");
You need to modify a property if you want some "action" or at least process the result that's being returned by substringCounter.
Besides, I have no idea why you use recursion. This does the same:
String text = "dandelion";
String search = "d";
int count = 0;
int pos = 0;
if (!search.isEmpty()) {
while ((pos = text.indexOf(search, pos)) != -1) {
count++;
pos++;
}
}
System.out.println(count);
Basically something like this:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
HBox box = new HBox();
box.setSpacing(10);
TextField sourceTextField = new TextField( "Dandelion");
Label result = new Label();
TextField searchTextField = new TextField();
// add listener for counting the number of substrings
searchTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String sourceText = sourceTextField.getText().toLowerCase();
String searchText = newValue.toLowerCase();
int count = 0;
int pos = 0;
if( !searchText.isEmpty()) {
while( (pos = sourceText.indexOf( searchText, pos)) != -1) {
count++;
pos++;
}
}
result.setText( String.valueOf(count));
}
});
box.getChildren().addAll( new Label( "Search:"), searchTextField, new Label( "Text:"), sourceTextField, new Label( "Count:"), result);
Scene scene = new Scene(box, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Or using your recursive method (you also need to check letters for empty string by the way):
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
HBox box = new HBox();
box.setSpacing(10);
TextField sourceTextField = new TextField( "Dandelion");
Label result = new Label();
TextField searchTextField = new TextField();
searchTextField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
String sourceText = sourceTextField.getText().toLowerCase();
String searchText = newValue.toLowerCase();
result.setText( String.valueOf( substringCounter( sourceText, searchText)));
}
});
box.getChildren().addAll( new Label( "Search:"), searchTextField, new Label( "Text:"), sourceTextField, new Label( "Count:"), result);
Scene scene = new Scene(box, 600, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
public static int substringCounter(String plantName, String letters) {
plantName = plantName.toLowerCase();
if(letters.isEmpty()) {
return 0;
}
if(plantName.isEmpty()) {
return 0;
}
if(plantName.indexOf(letters) == -1) {
return 0;
}
return 1 + substringCounter(plantName.substring(plantName.indexOf(letters) + 1), letters);
}
public static void main(String[] args) {
launch(args);
}
}
Instead of setting the label like I did in the example you of course have to change your integer properties.
Related
I am trying to replicate Gmail behavior in Javafx TableView. Row of new Unread message should be shown in bold. Here is what I was able to do so far:
I can change background of the whole row, and bold a cell, but can't bold the whole row.
How to explain Javafx to do this?
for each Cell cell in tableview:
get Message m corresponding to row.
String style = m.isUnread() ? "
cell.setStyle("-fx-font-weight: 800" : "-fx-font-weight: 100")
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class Message {
final static public ObservableList<Message> data = FXCollections.observableArrayList(
new Message("Bob", "Where are you?", true, true),
new Message("Elise", "Payment", false, false),
new Message("Charlie", "Read this book: 'Clean code'", true, true),
new Message("Oscar", "Golf class tonight", true, false),
new Message("Sam", "How is your TableView progress?", false, true),
new Message("Alice", "Latte", true, true)
);
final private String name;
final private String title;
private boolean isUnread;
private boolean isArchived;
public Message(String name, String title, boolean isUnread, boolean isArchived) {
this.name = name; this.title = title; this.isUnread = isUnread;this.isArchived = isArchived;
}
public String getName() { return name; }
public String getTitle() { return title; }
public boolean getIsUnread() { return isUnread; }
public boolean getisArchived() { return isArchived; }
public void setIsUnread(boolean isUnread) { this.isUnread = isUnread; }
}
MyTable.java
import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
public class MyTable extends Application {
public static void main(String[] args) throws Exception { launch(args); }
public void start(final Stage stage) throws Exception {
stage.setTitle("Inbox");
// create a table.
TableView<Message> table = new TableView(Message.data);
table.getColumns().addAll(makeStringColumn("Name", "name", 150), makeStringColumn("Title", "title", 300), makeBooleanColumn("New", "isUnread", 150));
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setPrefHeight(250);
stage.setScene(new Scene(table));
stage.getScene().getStylesheets().add(getClass().getResource("message.css").toExternalForm());
stage.show();
// highlight the table rows depending upon whether we expect to get paid.
int i = 0;
for (Node n: table.lookupAll("TableRow")) {
if (n instanceof TableRow) {
TableRow row = (TableRow) n;
if (table.getItems().get(i).getIsUnread()) {
row.getStyleClass().add("isReadRow");
} else {
row.getStyleClass().add("isUnreadRow");
}
i++;
if (i == table.getItems().size())
break;
}
}
}
private TableColumn<Message, String> makeStringColumn(String columnName, String propertyName, int prefWidth) {
TableColumn<Message, String> column = new TableColumn<>(columnName);
column.setCellValueFactory(new PropertyValueFactory<Message, String>(propertyName));
column.setCellFactory(new Callback<TableColumn<Message, String>, TableCell<Message, String>>() {
#Override public TableCell<Message, String> call(TableColumn<Message, String> soCalledFriendStringTableColumn) {
return new TableCell<Message, String>() {
#Override public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
}
}
};
}
});
column.setPrefWidth(prefWidth);
column.setSortable(false);
return column;
}
private TableColumn<Message, Boolean> makeBooleanColumn(String columnName, String propertyName, int prefWidth) {
TableColumn<Message, Boolean> column = new TableColumn<>(columnName);
column.setCellValueFactory(new PropertyValueFactory<Message, Boolean>(propertyName));
column.setCellFactory(new Callback<TableColumn<Message, Boolean>, TableCell<Message, Boolean>>() {
#Override public TableCell<Message, Boolean> call(TableColumn<Message, Boolean> soCalledFriendBooleanTableColumn) {
return new TableCell<Message, Boolean>() {
#Override public void updateItem(final Boolean item, final boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.toString());
this.getStyleClass().add(item ? "isUnreadCell" : "isReadCell");
}
}
};
}
});
column.setPrefWidth(prefWidth);
column.setSortable(false);
return column;
}
}
(Message.css)
.column-header-background { -fx-background-color: azure; }
.isReadRow { -fx-background-color: palegreen; }
.isUnreadRow { -fx-background-color: yellow; }
.isReadCell { -fx-font-weight: 100 ; -fx-text-fill: darkgreen;}
.isUnreadCell { -fx-font-weight: 800 ; -fx-text-fill: red;}
To bold a row associate a RowFactory as shown below.
table.setPrefHeight(250);
table.setRowFactory(new Callback<TableView<Message>, TableRow<Message>>() {
#Override
public TableRow<Message> call(TableView<Message> param) {
final TableRow<Message> row = new TableRow<Message>() {
#Override
protected void updateItem(Message row, boolean empty) {
super.updateItem(row, empty);
if (!empty)
styleProperty().bind(Bindings.when(row.selectedProperty())
.then("-fx-font-weight: bold; -fx-font-size: 16;")
.otherwise(""));
}
};
return row;
}
});
stage.setScene(new Scene(table));
In the above sample, selectedProperty() function has been called by the Message row. The selectedProperty() function returns the value of boolean variable isUnread. If the isUnread value is true then the whole row will be bolded else it won't be.
final private String title;
private boolean isUnread;
private boolean isArchived;
private BooleanProperty selected;
public boolean getSelected() {return selected.get();}
public BooleanProperty selectedProperty(){return selected;}
public Message(String name, String title, boolean isUnread, boolean isArchived) {
this.name = name; this.title = title; this.isUnread = isUnread;this.isArchived = isArchived;
this.selected = new SimpleBooleanProperty(isUnread);
}
Setting the font style as bold and size to 16 gives following output:
I'd recommend using PseudoClasses to denote read/unread rows. Use a rowFactory to set the PseudoClasses. Also using a property for the read/unread state would be preferable, since this allows you to update the rows without refreshing the whole table:
private final BooleanProperty unread;
public void setUnread(boolean value) {
this.unread.set(value);
}
public boolean isUnread() {
return this.unread.get();
}
public BooleanProperty unreadProperty() {
return unread;
}
public Message(String name, String title, boolean isUnread, boolean isArchived) {
this.name = name;
this.title = title;
this.unread = new SimpleBooleanProperty(isUnread);
this.isArchived = isArchived;
}
final PseudoClass read = PseudoClass.getPseudoClass("read");
final PseudoClass unread = PseudoClass.getPseudoClass("unread");
table.setRowFactory(tv -> new TableRow<Message>() {
private void setState(boolean readState, boolean unreadState) {
pseudoClassStateChanged(unread, unreadState);
pseudoClassStateChanged(read, readState);
}
private void setUnreadState(boolean unreadState) {
setState(!unreadState, unreadState);
}
private final ChangeListener<Boolean> unreadListener = (observable, oldValue, newValue) -> setUnreadState(newValue);
#Override
protected void updateItem(Message item, boolean empty) {
// remove listener from old item
Message oldItem = getItem();
if (oldItem != null) {
oldItem.unreadProperty().removeListener(unreadListener);
}
super.updateItem(item, empty);
if (empty || item == null) {
setState(false, false);
} else {
// set appropriate state & add listener
setUnreadState(item.isUnread());
item.unreadProperty().addListener(unreadListener);
}
}
});
stage.setScene(new Scene(table));
.table-row-cell:read {
-fx-background-color: palegreen;
}
.table-row-cell:unread {
-fx-background-color: yellow;
}
.table-row-cell:read>.table-cell {
-fx-font-weight: 100;
-fx-text-fill: darkgreen;
}
.table-row-cell:unread>.table-cell {
-fx-font-weight: 800;
-fx-text-fill: red;
}
Also make sure to set the text of TableCells even if they become empty. Otherwise you could see "ghost content":
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item);
} else {
setText("");
}
}
#Override
public void updateItem(final Boolean item, final boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.toString());
} else {
setText("");
}
}
I m creating a Table Model Adapter in Blackberry.(**This is a sample what i m doing****)I have added button field and two Strings.I m putting data in String from vector.Now on button click i want to delete the row against button.The Data is deleted from the database but not removed from Screen view when button is clicked.When i calld the Retrieve() function to call updated database and draw the Table model adapter again....it is adding new Table below old one....not refreshing it. Is there any solution to show the refreshed data in same table.
package mypackage;
import java.util.Vector;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.table.DataTemplate;
import net.rim.device.api.ui.component.table.TableController;
import net.rim.device.api.ui.component.table.TableModelAdapter;
import net.rim.device.api.ui.component.table.TableView;
import net.rim.device.api.ui.component.table.TemplateColumnProperties;
import net.rim.device.api.ui.component.table.TemplateRowProperties;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.decor.BackgroundFactory;
public final class MyScreen extends MainScreen implements FieldChangeListener
{
private DeviceTableModelAdapter _tableModel;
private Vector _cities;
private static final int NUM_ROWS = 1;
private static final int ROW_HEIGHT = 50;
private static final int NUM_COLUMNS = 3;
public ButtonField btn;
public MyScreen(){
super(Manager.NO_VERTICAL_SCROLL);
_cities = new Vector();
_tableModel = new DeviceTableModelAdapter();
Vector sample =new Vector();
sample.addElement("Newyork");
sample.addElement("NewDelhi");
sample.addElement("NewOrleans");
int ik = 0;
while(ik < sample.size())
{
String modelNumber = sample.elementAt(ik).toString();
String modelName = "-Earth-";
String ne = String.valueOf(ik);
Object[] row = {modelName, modelNumber, ne};
_tableModel.addRow(row);
ik++;
}
TableView tableView = new TableView(_tableModel);
tableView.setDataTemplateFocus(BackgroundFactory.createLinearGradientBackground(Color.WHITE, Color.WHITE, Color.BLUEVIOLET, Color.BLUEVIOLET));
TableController tableController = new TableController(_tableModel, tableView);
tableController.setFocusPolicy(TableController.ROW_FOCUS);
tableView.setController(tableController);
// Specify a simple data template for displaying 3 columns
DataTemplate dataTemplate = new DataTemplate(tableView, NUM_ROWS, NUM_COLUMNS)
{
public Field[] getDataFields(int modelRowIndex)
{
Object[] data = (Object[]) (_tableModel.getRow(modelRowIndex));
Field[] fields = {getButtonFieldObject((String)data[0]), new LabelField((String) data[1]), new LabelField((String) data[2])};
return fields;
}
};
dataTemplate.useFixedHeight(true);
// Define regions and row height
dataTemplate.setRowProperties(0, new TemplateRowProperties(ROW_HEIGHT));
for(int i = 0; i < NUM_COLUMNS; i++)
{
dataTemplate.createRegion(new XYRect(i, 0, 1, 1));
dataTemplate.setColumnProperties(i, new TemplateColumnProperties(Display.getWidth() / NUM_COLUMNS));
}
// Apply the template to the view
tableView.setDataTemplate(dataTemplate);
add(tableView);
}
public void fieldChanged(Field arg0, int arg1) {
/*** tableView.DeleteAll(); ****/
/**** calling Class again to draw the table Modal Adapter again with updated value *******/
}
private final static class City
{
private String _name;
private String _region;
private String _image;
City(String name, String region, String image)
{
_name = name;
_region = region;
_image = image;
}
public String getName()
{
return _name;
}
public String getRegion()
{
return _region;
}
public String getImage()
{
return _image;
}
}
private class DeviceTableModelAdapter extends TableModelAdapter
{
public int getNumberOfRows()
{
return _cities.size();
}
public int getNumberOfColumns()
{
return NUM_COLUMNS;
}
protected boolean doAddRow(Object row)
{
Object[] arrayRow = (Object[]) row;
_cities.addElement(new City((String) arrayRow[0], (String) arrayRow[1], (String) arrayRow[2]));
return true;
}
protected Object doGetRow(int index)
{
City city = (City) _cities.elementAt(index);
Object[] row = {city.getImage(), city.getRegion(), city.getName()};
return row;
}
}
public ButtonField getButtonFieldObject(String arg){
btn = new ButtonField(arg,ButtonField.CONSUME_CLICK);
btn.setChangeListener(this);
return btn;
}
}
What you have to consider is the fact that Blackberry table UI follows the MVC design pattern.
So it means that data are updated in the model.
Like for example:
Object yes = (Object)"Yes";
// gets the Model attached to this View
TableModel tm = (TableModel)view.getModel();
// updates the data attached to the row
tm.setElement(rowIndex, columnIndex, yes);
tm.modelReset();
In screen1 i have 2 buttons a and b.i have given field change listener for both such that each pushes corresponding screen .When i press button 'a' it pushes say screen2 where i have used a keywordFilter to search words from sqlite database and is listed.These all are perfect when i run the application ,but when i press the back(or previous key) and then press the button 'a' from screen1 again i dont find any results from database.same thing happens to button b also .What cud b the pblm pls help.
Thank u so much in advance
Below is the class called after button 'a' is clicked
import net.rim.device.api.ui.*;
import net.rim.device.api.io.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.system.*;
import java.util.*;
import net.rim.device.api.database.Database;
import net.rim.device.api.database.DatabaseFactory;
import net.rim.device.api.database.Row;
import net.rim.device.api.database.Statement;
public final class KeywordFilter
{
private KeywordFilterField _keywordFilterField;
private WordList _wordList;
private Vector _words;
public KeywordFilter()
{
_words = getDataFromDatabase();
if(_words != null)
{
_wordList = new WordList(_words);
_keywordFilterField = new KeywordFilterField();
_keywordFilterField.setSourceList(_wordList, _wordList);
CustomKeywordField customSearchField = new CustomKeywordField();
_keywordFilterField.setKeywordField(customSearchField);
KeywordFilterScreen screen = new KeywordFilterScreen(this);
screen.setTitle(_keywordFilterField.getKeywordField());
screen.add(_keywordFilterField);
UiApplication ui = UiApplication.getUiApplication();
ui.pushScreen(screen);
}
else
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Error reading data file.");
System.exit(0);
}
});
}
}
KeywordFilterField getKeywordFilterField()
{
return _keywordFilterField;
}
private Vector getDataFromDatabase()
{
Vector words = new Vector();
Database d;
for(;;)
{
try
{
URI myURI=URI.create("file:///SDCard/Databases/MyTestDatabase.db");
d=DatabaseFactory.open(myURI);
Statement st=d.createStatement("SELECT eng,mal FROM Malayalam m,English e where e.Ecode=m.Mcode");
st.prepare();
net.rim.device.api.database.Cursor c=st.getCursor();
Row r;
while(c.next())
{
r=c.getRow();
String w=r.getString(0);
String meaning=r.getString(1);
words.addElement(new Word(w,meaning));
}}
catch ( Exception e )
{
System.out.println( e.getMessage() );
e.printStackTrace();
}
return words;
}
}
void addElementToList(Word w)
{
_wordList.addElement(w);
_keywordFilterField.updateList();
}
final static class CustomKeywordField extends BasicEditField
{
CustomKeywordField()
{
super(USE_ALL_WIDTH|NON_FOCUSABLE|NO_LEARNING|NO_NEWLINE);
setLabel("Search: ");
}
protected boolean keyChar(char ch, int status, int time)
{
switch(ch)
{
case Characters.ESCAPE:
if(super.getTextLength() > 0)
{
setText("");
return true;
}
}
return super.keyChar(ch, status, time);
}
protected void paint(Graphics graphics)
{
super.paint(graphics);
getFocusRect(new XYRect());
drawFocus(graphics, true);
}
}
}
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.system.*;
final class KeywordFilterScreen extends MainScreen
{
private KeywordFilter _app;
private KeywordFilterField _keywordFilterField;
public KeywordFilterScreen(KeywordFilter app)
{
_app = app;
_keywordFilterField = _app.getKeywordFilterField();
}
protected boolean keyChar(char key, int status, int time)
{
if (key == Characters.ENTER)
{
displayInfoScreen();
return true;
}
return super.keyChar(key, status, time);
}
public boolean invokeAction(int action)
{
switch(action)
{
case ACTION_INVOKE:
displayInfoScreen();
return true;
}
return super.invokeAction(action);
}
private void displayInfoScreen()
{
Word w = (Word)_keywordFilterField.getSelectedElement();
if(w != null)
{
InfoScreen infoScreen = new InfoScreen(w);
UiApplication ui = UiApplication.getUiApplication();
ui.pushScreen(infoScreen);
ui.popScreen(this);
}
}
private final static class InfoScreen extends MainScreen
{
InfoScreen(Word w)
{
setTitle(w.toString());
BasicEditField popField = new BasicEditField(":",w.getMeaning(),20,Field.NON_FOCUSABLE);
add(popField);
}
}
}
public class Word
{
private String _word;
private String _meaning;
public Word(String word, String meaning)
{
_word = word;
_meaning = meaning;
}
String getMeaning()
{
return _meaning;
}
public String toString()
{
return _word;
}
}
import net.rim.device.api.ui.component .*;
import net.rim.device.api.collection.util.*;
import net.rim.device.api.util.*;
import java.util.*;
public class WordList extends SortedReadableList implements KeywordProvider
{
public WordList(Vector words)
{
super(new WordListComparator());
loadFrom(words.elements());
}
void addElement(Object element)
{
doAdd(element);
}
public String[] getKeywords( Object element )
{
if(element instanceof Word )
{
return StringUtilities.stringToWords(element.toString());
}
return null;
}
final static class WordListComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
if (o1 == null || o2 == null)
throw new IllegalArgumentException("Cannot compare null words");
return o1.toString().compareTo(o2.toString());
}
}
}
add st.close(); and d.close() after accessing db in private Vector getDataFromDatabase() method just before closing the try block
Plz give the code or function how to clear the ListField and update the ListField .
Suppose i want to display some multiple text( Project Name, Project Manager )extracted from JSON object , in a ListField.
I am able to display this strings in the ListField but one more feature i need to add ie.. above the ListField there should be a ButtonField and when the user clicks on the ButtonField the ListField should display the string in sorted manner base on Project Name. So i need to clear the ListField
Code for NetworkingMainScreen is
package src1;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.system.*;
import org.json.me.JSONArray;
import org.json.me.JSONException;
import org.json.me.JSONObject;
import java.util.Vector;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.UiApplication;
class NetworkingMainScreen extends MainScreen
{
private EditField urlField;
private BitmapField imageOutputField;
private RichTextField textOutputField;
private ListField prjctlist_Field;
private Vector prjct_list_v = new Vector();
VerticalFieldManager vfm;
private String prjts;
public int total_prjcts;
JSONArray data_json_array;
JSONObject outer;
ListField myList;
private Vector v_prj_title;
private Vector v_prj_mgr;
private Vector send_vector;
private Vector send_vector3;
private Vector send_vector4;
private String t1,t2;
public JSONArray jsArrPrjts;
ListCallBack callback;
ButtonField sort;
NetworkingMainScreen()
{
// Screen2 s = new Screen2();
// UiApplication.getUiApplication.pushScreen(s);
setTitle("Networking");
urlField = new EditField("URL:", "http://iphone.openmetrics.com/apps/mattson/api.html?action=login&user=Nathan&password=coffee00&server=exp.lcgpence.com;deviceside=true");
textOutputField = new RichTextField();
imageOutputField = new BitmapField();
add(urlField);
add(new SeparatorField());
add(new LabelField("Text retrieved:"));
add(textOutputField);
myList = new ListField();
callback = new ListCallBack();
myList.setRowHeight(80);
myList.setCallback(callback);
add(myList);
}
protected void makeMenu(Menu menu, int instance)
{
super.makeMenu(menu, instance);
menu.add(new MenuItem("Get", 10, 10) {
public void run() {
getURL();
}
});
}
private void getURL()
{
HttpRequestDispatcher dispatcher = new HttpRequestDispatcher(urlField.getText(),"GET", this);
dispatcher.start();
}
public void requestSucceeded(byte[] result, String contentType)
{
if (contentType.startsWith("text/")) {
synchronized (UiApplication.getEventLock())
{
String strResult = new String(result);
try
{
JSONObject joPrjt = new JSONObject(strResult);
String res_code = joPrjt.optString("responseCode");
if( res_code.equals("1"))
{
data_json_array = new JSONArray();
data_json_array = joPrjt.optJSONArray("data");
int s = data_json_array.length();
v_prj_title = new Vector();
v_prj_mgr = new Vector();
outer = new JSONObject();
for(int i=0; i<s; i++)
{
//outer = new JSONObject();
outer = data_json_array.getJSONObject(i);
String job_no = outer.optString("job_number");
String contract_date = outer.optString("contract_date");
String project_title = outer.optString("project_title");
String project_manager = outer.optString("project_manager");
String created_date = outer.optString("created_date");
String project_name = outer.optString("project_name");
v_prj_title.addElement(project_title);
v_prj_mgr.addElement(project_manager);
}
UiApplication.getUiApplication().pushScreen(new Screen2(v_prj_title,v_prj_mgr,0,v_prj_title,v_prj_mgr));
}
else
{
Dialog.alert("Web page connected but not the requested page");
}
}
catch(JSONException e)
{
e.printStackTrace();
System.out.println("key not found catched " + e);
}
}
}
else
{
synchronized (UiApplication.getEventLock()) {
Dialog.alert("Unknown content type: " + contentType);
}
}
}
public void requestFailed(final String message)
{
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert("Request failed. Reason: " + message);
}
});
}
}
Code for Screen2 is
package src1;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.LabelField;
import org.json.me.JSONArray;
import org.json.me.JSONException;
import org.json.me.JSONObject;
import java.util.Vector;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.component.ListField;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.UiApplication;
class Screen2 extends MainScreen implements FieldChangeListener
{
JSONArray j_array;
JSONObject j_object;
CustomButtonField bf1;
Vector v_prj_title,v_prj_mgr,v_job_no,v_created_date,v_prj_name,send_vector;
Vector main_v_prj_title,main_v_prj_mgr;
String job_no,contract_date,project_title,project_manager,created_date,project_name;
VerticalFieldManager vfm;
ListField myList;
ListCallBack callback;
int pic_status;
int b;
String t1,t2;
String temp1,temp2,f1,f2;
// ListField prjctlist_Field;
Screen2(Vector v_prj_title2,Vector v_prj_mgr2,int pic_status,Vector main_v_prj_title_o2,Vector main_v_prj_mgr_o2)
{
this.main_v_prj_title = main_v_prj_title_o2;
this.main_v_prj_mgr = main_v_prj_mgr_o2;
this.v_prj_title = v_prj_title2;
this.v_prj_mgr = v_prj_mgr2;
this.pic_status = pic_status;
bf1 = new CustomButtonField("Name",pic_status,0);
bf1.setChangeListener(this);
vfm = new VerticalFieldManager();
vfm.add(bf1);
int s = v_prj_title.size();
myList = new ListField();
callback = new ListCallBack();
myList.setRowHeight(80);
myList.setCallback(callback);
for(int i=0;i<s;i++)
{
myList.insert(i);
t1 = v_prj_title.elementAt(i).toString();
send_vector = new Vector(2);
send_vector.addElement(t1);
t2 = v_prj_mgr.elementAt(i).toString();
send_vector.addElement(t2);
callback.insert(send_vector,i);
}
vfm.add(myList);
add(vfm);
}
public void fieldChanged(Field field, int context)
{
if(field == bf1)
{
if(pic_status == 0)
{
b =1;
int s = v_prj_title.size();
for(int i=0;i<s;i++)
{
for(int t=i+1;t<s;t++)
{
temp1 = (String)v_prj_title.elementAt(i);
temp2 = (String)v_prj_title.elementAt(t);
if(temp1.compareTo(temp2)>0)
{
//System.out.println("Comparision Executed :"+temp1 + " is greater than " + temp2);
f1 = (String)v_prj_mgr.elementAt(i);
f2 = (String)v_prj_mgr.elementAt(t);
v_prj_title.setElementAt(temp1,t);
v_prj_title.setElementAt(temp2,i);
v_prj_mgr.setElementAt(f1,t);
v_prj_mgr.setElementAt(f2,i);
}
}
}
UiApplication.getUiApplication().pushScreen(new Screen2(main_v_prj_title,main_v_prj_mgr,b,main_v_prj_title,main_v_prj_mgr));
}
if(pic_status == 1)
{
b=0;
UiApplication.getUiApplication().pushScreen(new Screen2(main_v_prj_title,main_v_prj_mgr,b,main_v_prj_title,main_v_prj_mgr));
}
}
}
}
one more thing i need to clearify is that in my above code firstly i have parsed the JSON object in NetworkingMainScreen and if the JSON parsing is success i have push a new screen name Screen2 passing the stored Vector to the Screen2. The Screen2 performs ListField drawings or should i perform the ListField drawing in NetworkingMainScreen class only.
For details about the items i need to display plz look **http://iphone.openmetrics.com/apps/mattson/api.html?action=login&user=Nathan&password=coffee00&server=exp.lcgpence.com&output=data**
Implement ListFieldCallback in your screen, you can then handle the drawing of your rows however you want in drawListRow.
I have prepared a simple test case to demonstrate my problem.
It is just 1 file which will run instantly when added to a new project.
I would like to have a MainScreen displaying an editable list of items:
and when leaving this screen, the user should be asked - if she wants to save the modified list to persistent storage, by presenting the standard Save/Discard/Cancel-dialog:
I have added setDirty(true) to my menu items and the standard dialog does come up okay.
My problem is: I don't know how to clear the dirty flag after saving - in my current code the Save/Discard/Cancel-dialog comes again and again, even if I just view the ListField, without editing it.
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 implements FieldChangeListener {
MyScreen myScreen = new MyScreen();
public static void main(String args[]) {
MyList app = new MyList();
app.enterEventDispatcher();
}
public MyList() {
MainScreen titleScreen = new MainScreen();
titleScreen.setTitle("Click the button:");
ButtonField myButton = new ButtonField("Show the list", ButtonField.CONSUME_CLICK) ;
myButton.setChangeListener(this);
titleScreen.add(myButton);
pushScreen(titleScreen);
}
public void fieldChanged(Field field, int context) {
pushScreen(myScreen);
}
}
class MyScreen extends MainScreen {
ObjectListField myList = new ObjectListField();
static PersistentObject myStore;
static Vector myData;
static {
myStore = PersistentStore.getPersistentObject(0xb77f8e453754f37aL);
myData = (Vector) myStore.getContents();
if (myData == null) {
myData = new Vector();
myData.addElement("String 1");
myData.addElement("String 2");
myData.addElement("String 3");
myStore.setContents(myData);
}
}
public MyScreen() {
setTitle("Edit the list below:");
add(myList);
addMenuItem(addItem);
addMenuItem(editItem);
addMenuItem(removeItem);
}
// load data from persistent store into the ListField
private void loadData() {
// clear the ListField
myList.setSize(0);
// copy data from the Vector to the ListField
for (int i = myData.size() - 1; i >= 0; i--)
myList.insert(0, myData.elementAt(i));
}
// save data from the ListField into the persistent store
private void saveData() {
// clear the Vector
myData.removeAllElements();
// copy data from the ListField to the Vector
for (int i = myList.getSize() - 1; i >=0; i--)
myData.addElement(myList.get(myList, i));
synchronized(PersistentStore.getSynchObject()) {
myStore.commit();
}
}
protected void onUiEngineAttached(boolean attached) {
if (attached) {
loadData();
}
}
public void save() {
saveData();
// UPDATE: when I call setDirty(false); here, then
// the app starts displaying Save/Discard/Cancel dialog
// on its exit - so there must be a better way...
}
private final MenuItem addItem = new MenuItem("Add Item", 0, 0) {
public void run() {
String[] buttons = {"Add", "Cancel"};
Dialog myDialog = new Dialog("Add Item", buttons, null, 0, null);
EditField myEdit = new EditField("Item: ", "");
myDialog.add(myEdit);
if (myDialog.doModal() == 0) {
myList.insert(0, myEdit.getText());
setDirty(true);
}
}
};
private final MenuItem editItem = new MenuItem("Edit Item", 0, 0) {
public void run() {
String[] buttons = {"Save", "Cancel"};
Dialog myDialog = new Dialog("Edit Item", buttons, null, 0, null);
int index = myList.getSelectedIndex();
if (index == -1) {
return;
}
String selectedItem = (String) myList.get(myList, index);
EditField myEdit = new EditField("Item: ", selectedItem);
myDialog.add(myEdit);
if (myDialog.doModal() == 0) {
myList.set(index, myEdit.getText());
setDirty(true);
}
}
};
private final MenuItem removeItem = new MenuItem("Remove Item", 0, 0) {
public void run() {
String[] buttons = {"Delete", "Cancel"};
Dialog myDialog = new Dialog("Remove Item", buttons, null, 0, null);
int index = myList.getSelectedIndex();
if (index == -1) {
return;
}
String selectedItem = (String) myList.get(myList, index);
LabelField myLabel = new LabelField("Really delete " + selectedItem + "?");
myDialog.add(myLabel);
if (myDialog.doModal() == 0) {
myList.delete(index);
setDirty(true);
}
}
};
}
Please share your Blackberry 6 experience, advices in regard to persistent storage are also welcome.
In my real program I'm using KeywordFilterField for viewing a SortedReadableList, so from reading Blackberry docs I suppose, that I must always copy data between SortedReadableList and Vector - because the latter is persistable and the former is not?
setDirty(false) will clear the dirty flag if that is what you are after.