I'm trying to create a Help/About screen for my application, but I've discovered that, well, my code sucks. (I know it could use a little refactoring, but when working with a new framework I get the code working first then immediately go back and refactor to do things "properly").
First, what I'm doing doesn't "feel" like the right way of doing it. I'm not sure about just stuffing a bunch of text fields into the layout - is there a better way of doing so?
Second, the VFM is taking up the bulk of the screen and pushing my 'Close' button off the bottom. What I'm trying to do is keep the title and 'Close' button visible but just scroll the VFM.
How can I solve these problems?
public class HelpScreen extends PopupScreen {
public HelpScreen() {
super(new VerticalFieldManager(), Field.FOCUSABLE);
/* Construct the Close button */
FieldChangeListener listener = new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
ok();
}
};
ButtonField b = new ButtonField("Close", Field.FIELD_HCENTER);
b.setChangeListener(listener);
/* Construct the text box containing the help */
VerticalFieldManager vfm = new VerticalFieldManager(VERTICAL_SCROLL);
TextField f;
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("My application does stuff. This part is the description of what it does.");
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("Commands:");
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("N - New Widget");
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("R - Rename Widget");
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("D - Duplicate Widget");
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("C - Clear Widget");
vfm.add(f = new TextField(FIELD_LEFT | READONLY));
f.setText("Shift-Delete - Delete Widget");
/* Construct the screen */
add(new LabelField("About Widget Wiffleball", Field.FIELD_HCENTER));
add(new SeparatorField());
add(vfm);
add(b);
}
public void ok() {
UiApplication.getUiApplication().popScreen(this);
}
}
For the code not 'feeling right' - functionally it seems fine, but a bit of refactoring could clean it up a bit - maybe make a method to create and populate the TextFields
private TextField createTextField(String content) {
TextField textField = new TextField(
}
Then that portion of the constructor becomes:
VerticalFieldManager vfm = new VerticalFieldManager(VERTICAL_SCROLL);
vfm.add(createTextField("My application does stuff. This part is the description of what it does."));
vfm.add(createTextField("Commands:"));
vfm.add(createTextField("N - New Widget"));
vfm.add(createTextField("R - Rename Widget"));
vfm.add(createTextField("D - Duplicate Widget"));
vfm.add(createTextField("C - Clear Widget"));
vfm.add(createTextField("Shift-Delete - Delete Widget"));
You solve the layout problem using a custom field manager - really not difficult, you just have to subclass Manager and implement sublayout. Define a 'top', 'bottom', and 'middle' field, and layout accordingly (some code left out as an exercise to the reader, but basically when adding fields to the manager you'll need to be able to specify one as top and one as bottom. The following logic will make sure the bottom field is always stuck to the bottom, and the top 2 fields don't push it off the bottom:
protected void sublayout(int width, int height) {
// retrieve the top, middle and bottom fields
int heightRemaining = height;
layoutChild(topField, width, heightRemaining);
setPositionChild(topField, 0, 0);
heightRemaining -= topField.getHeight();
layoutChild(bottomField, width, heightRemaining);
setPositionChild(bottomField, 0, height - bottomField.getHeight());
heightRemaining -= bottomField.getHeight();
layoutChild(middleField, width, heightRemaining);
setPositionChild(middleField, 0, topField.getHeight());
}
Again, just a framework - no error checking or anything in there. Then set your delegate to be this new manager, set your vertical field manager to be the middle field (you'll probably want a designated setter), your button field to the bottom field (again, designated getter).
Related
I am an an Android Developer, developing an Blackberry application.
I have created a button of full width of screen. Getting problem in shifting the text to the center of the button area.
Used below code :
ButtonField _contactButton = new ButtonField(Constants.contactButtonTitle,Field.FIELD_HCENTER|Field.USE_ALL_WIDTH |
Field.ACTION_INVOKE | Field.FOCUSABLE | ButtonField.CONSUME_CLICK){
protected void layout(int width, int height) {
super.layout(width, height);
HARD_CODED_HEIGHT = this.getHeight()/2 + 6;
this.setExtent(contactButtonWidth, HARD_CODED_HEIGHT);
}
public int getPreferredWidth() {
return contactButtonWidth;
}
};
Now using the below code :
ButtonField _contactButton = new ButtonField(Constants.contactButtonTitle,Field.FIELD_VCENTER|Field.USE_ALL_WIDTH |
Field.ACTION_INVOKE | Field.FOCUSABLE | ButtonField.CONSUME_CLICK){
protected void layout(int width, int height) {
super.layout(getPreferredWidth(), height);
}
public int getPreferredWidth() {
return (Display.getWidth()-60);
}
};
Still getting the issue .. text of my button align to right corner. Please suggest
ButtonField appears to be a little 'broken'. But it also appears to be consistently broken in all the OS Levels that I have tested (OS 5.0 to OS 7.1), so I think we can achieve what you want by working round the broken bits and be confident the workaround will work in all levels you want.
As has been noted, ButtonField ignores USE_ALL_WIDTH, but does respect preferredWidth. So if you want to set the width of your ButtonField, then just override getPreferredWidth(). You should not do anything with width in layout.
Now you are using the styles for ButtonField already. Given that we have discarded USE_ALL_WIDTH as a useful style, I note that you also use FIELD_HCENTER. You should be aware that this is actually a directive to the Manager that is positioning this Field - telling the Manager to position the Field in the centre of the width the Manager has available. This style does not relate to how the contents of the ButtonField are drawn.
For that, you can look to use DrawStyle. By default, ButtonField uses DrawStyle.RIGHT. And it respects DrawStyle.Left - the text will be drawn on the left. It does not however, respect DrawStyle.HCENTER. So to get centred text, we need to paint the text ourselves.
There is one more complication. ButtonField passes a Context area into its paint() method, not the full Field canvas - presumably it does not pass in the edges because these are painted by a border. So to centre the text appropriately, we have to use the clipping region that has been passed in.
Here is the final, hopefully working, ButtonField. I appreciate you will have to spend some time creating a class for this, I'm sorry, I've been lazy and done in it 'in-line'. Please publish your CenteredTextButtonField class if you create one....
final String buttonText = "Test";
ButtonField _contactButton = new ButtonField(" ",
Field.ACTION_INVOKE | Field.FOCUSABLE | ButtonField.CONSUME_CLICK){
public int getPreferredWidth() {
return contactButtonWidth;
}
protected void paint(Graphics graphics) {
super.paint(graphics);
XYRect clippingRect = graphics.getClippingRect();
int centreY = (clippingRect.height - graphics.getFont().getHeight()) / 2;
graphics.drawText(buttonText, 0, centreY, DrawStyle.HCENTER, clippingRect.width);
}
};
USE_ALL_WIDTH is our instruction to the field. Surprisingly, ButtonField ignores such instructions. Even more surprisingly, it honors its own getPreferredWidth (as illogical as it sounds).
So drop that USE_ALL_WIDTH and define your ButtonField like this:
ButtonField testBtn = new ButtonField("Button") {
public int getPreferredWidth() {
return Display.getWidth();
}
};
I am facing lot of issues while implement the auto suggest :I will tell you my issues .
1) Focus is always comes on auto suggest /complete field.First there is button .But focus is also on autosuggest field as shown in figure
2) When I write m on auto suggest field monday is display when I click the track pad it display monday on autosuggest field But Monday of pop up is not hide.
3) what is this encircle .How to change is gray color (or remove this color).some times it display on whole field and some time on half field
4) I just want a auto suggest with fix width not whole width .Like this on a screen with black background and autosuggest (edit field have white background no gray when focus comes on auto suggest)
Example
Label Auto suggest
Days Auto-complete of days
public final class MyScreen extends MainScreen implements JsonObserver
{
/**
* Creates a new MyScreen object
*/
public MyScreen()
{
// Set the displayed title of the screen
setTitle("Drop-down List Demo");
VerticalFieldManager vfm=new VerticalFieldManager(){
protected void sublayout(int maxWidth, int maxHeight) {
// TODO Auto-generated method stub
super.sublayout(maxWidth, maxHeight);
setExtent(maxWidth, maxHeight/2);
}
protected void paint(Graphics graphics) {
// TODO Auto-generated method stub
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, Display.getWidth(), Display.getHeight()/2);
super.paint(graphics);
}
};
vfm.add(new ButtonField("add"));
BasicFilteredList filterList = new BasicFilteredList();
String[] days = {"Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday","Sunday"};
filterList.addDataSet(1,days,"days",BasicFilteredList.COMPARISON_IGNORE_CASE);
AutoCompleteField autoCompleteField = new AutoCompleteField(filterList);
vfm.add(autoCompleteField);
vfm.add(new ButtonField("addpppp"));
add(vfm);
}
}
I am using ObjectChoiceField example. it is showing drop down at the end of right side, but i need to show some margin on the left side .
how we can achieve this ?
String choices[] = {"Monday","Tuesday","Wednesday","Thursday","Friday", "Saturday", "Sunday"};
int iSetTo = 0;
VerticalFieldManager vfm=new VerticalFieldManager(){
protected void paint(Graphics graphics) {
graphics.setBackgroundColor(Color.BLACK);
graphics.clear();
super.paint(graphics);
}
};
vfm.add(new ObjectChoiceField("Day of the week",choices,iSetTo){
protected void paint(Graphics graphics) {
graphics.setColor(Color.WHITE);
super.paint(graphics);
}
});
I am using this example:
![enter image description here][1]
You can do this with many fields by setting their margin. Field#setMargin() has been available since BBOS 6.0 officially, but was undocumented and usable in 5.0 (at least), too. So, at this point, I consider it perfectly acceptable to use in 5.0+ apps.
For example:
public ChoiceMarginScreen() {
super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
String choices[] = {"Monday","Tuesday","Wednesday","Thursday","Friday", "Saturday", "Sunday"};
int iSetTo = 0;
VerticalFieldManager vfm = new VerticalFieldManager();
vfm.setBackground(BackgroundFactory.createSolidBackground(Color.BLACK));
ObjectChoiceField days = new ObjectChoiceField("Day of the week", choices, iSetTo) {
protected void paint(Graphics graphics) {
graphics.setColor(Color.WHITE);
super.paint(graphics);
}
};
// set margin XYEdges(top, right, bottom, left):
days.setMargin(new XYEdges(0, 150, 0, 0));
vfm.add(days);
add(vfm);
}
Note that you also don't need to override the VerticalFieldManager#paint() method just to set a solid background color. You can use setBackground() for that. For setting the white font color on your object choice field, though, overriding paint() is a fine solution.
Also: I just went off your screen shot, and assumed you wanted the choice field moved to the left, but with no other field to the right of it. If you want the choice field to the left to make room for another field on its right, then you probably want to put both those fields in a HorizontalFieldManager, representing a row, and then add that HorizontalFieldManager to your VerticalFieldManager. But, that's not what you showed, so I offer my answer above.
I'm getting the following error when a screen should appear:
"WARNING: Cannot layout field, insufficient height or width".
Working with BB 5.0.
This screen es called from 3 different screen, and its shows 50% of the screen or 80%, depending on which screen is pushing it.
This one only have one banner at the top (field), some BasicEditField, one DateField, a vew ObjectChoiceField and at the end 2 buttons.
Why is this error showing up now? (2 days ago it didnt and is the same screen that worked fine before). Where should i check for errors?
Also, is there some limit of height or width that a screen can manage?
Code for the banner,
public static Field getBanner() {
Background bg = BackgroundFactory.createSolidBackground(Color.WHITE);
HorizontalFieldManager hfm = new HorizontalFieldManager(Field.USE_ALL_WIDTH | Field.FIELD_VCENTER);
final Bitmap logo = Bitmap.getBitmapResource("logo_40px.png");
BitmapField _bitmap1 = new BitmapField(logo);
int i = Display.getWidth();
i = i - logo.getWidth();
i = i / 2;
_bitmap1.setSpace(i, 5);
hfm.add(_bitmap1);
hfm.setBackground(bg);
return hfm;
}
Regards.
update:
on the screen creation i have this:
super(MainScreen.VERTICAL_SCROLL_MASK | MainScreen.VERTICAL_SCROLLBAR)
Without this, its works fine the screen. But i wont be able to scroll down, right?
You are adding both _bitmap1 and vfm to hfm, and vfm has Field.USE_ALL_WIDTH set. It would work better, I think, to add _bitmap1 to vfm.
EDIT
It may be that your logo (with the added space) is too big for the banner area on the screen. Perhaps something like this would work:
public static Field getBanner() {
Background bg = BackgroundFactory.createSolidBackground(Color.WHITE);
final Bitmap logo = Bitmap.getBitmapResource("logo_40px.png");
final BitmapField _bitmap1 = new BitmapField(logo);
_bitmap1.setSpace((Display.getWidth() - logo.getWidth()) / 2, 5);
HorizontalFieldManager hfm = new HorizontalFieldManager(Field.USE_ALL_WIDTH | Field.FIELD_VCENTER) {
protected void sublayout(int width, int height) {
super.sublayout(width, height);
setExtent(width, Math.min(_bitmap1.getPreferredHeight(), height));
}
}
hfm.add(_bitmap1);
hfm.setBackground(bg);
return hfm;
}
I want to know how to create VerticalFieldManager and i want to add some components also.
Couple of options:
A basic vertical field manager:
VerticalFieldManager vfm = new VerticalFieldManager();
// add your fields
vfm.add(new LabelField("First Label");
vfm.add(new LabelField("Second Label");
// etc
// then don't forget to add your vertical field manager to your screen
// assuming you're in the screen's constructor:
add(vfm);
The labels will appear top to bottom in the order you add them.
If you're going to add more fields than will fit vertically on a screen, you may want to make your manager scrollable:
VerticalFieldManager vfm = new VerticalFieldManager(Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR);
// the rest is the same as above
You can omit VERTICAL_SCROLLBAR if you don't want to see the up/down arrows.
But finally, if you just want a bunch of fields vertically on a screen, MainScreen by default uses a scrolling VerticalFieldManager as its delegate so you can just add fields directly and get the same effect:
class MyScreen extends MainScreen {
public MyScreen() {
add(new LabelField("Label 1");
add(new LabelField("Label 2");
// etc
}
}
Creation :
VerticalFieldManager vfm = new VerticalFieldManager();
Add different fields to it:
vfm.add(somefield);