List does not scroll while adding images in container. I have a list that extends container. I have used two containers for setting image field(left) and text filed(right). while I am adding text filed container list scrolls properly but while adding images in left field it did not scroll please help me . Thank you for your help.
//List declaration
orgNames = new List(tempName);
WidgetRenderer listCheckBoxRenderer = new WidgetRenderer();
orgNames.setListCellRenderer(listCheckBoxRenderer);
orgNames.setFixedSelection(List.FIXED_TRAIL);
organizationDetailsForm.addComponent(orgNames);
OrganizationNameListener orgNameList = new OrganizationNameListener();
orgNames.addActionListener(orgNameList);
//List renderer class
class WidgetRenderer extends Container implements ListCellRenderer {
private Image[] images;
private Button orgImgButton;
private Image orgImg;
private Container contImage, contDet;
private Label orgNameLabel, locationLabel, ratingLabel;
public WidgetRenderer() {
super();
try {
setLayout(new BorderLayout());
contDet = new Container(new BoxLayout(BoxLayout.Y_AXIS));
contImage = new Container();
contDet.setScrollableY(true);
contImage.setScrollable(true);
contDet.setScrollable(true);
contImage.setScrollable(true);
contDet.setSmoothScrolling(true);
contImage.setSmoothScrolling(true);
setScrollable(true);
setScrollableY(true);
orgImgButton = new Button();
orgNameLabel = new Label();
locationLabel = new Label();
Style orgStyle = new Style();
Style locStyle = new Style();
Font font = Font.createSystemFont(Font.FACE_MONOSPACE,
Font.STYLE_BOLD, Font.SIZE_MEDIUM);
orgStyle.setFont(font);
orgNameLabel.setSelectedStyle(orgStyle);
orgNameLabel.setPressedStyle(orgStyle);
orgNameLabel.setUnselectedStyle(orgStyle);
Font font1 = Font.createSystemFont(Font.FACE_MONOSPACE,
Font.STYLE_PLAIN, Font.SIZE_SMALL);
locStyle.setFont(font1);
locationLabel.setSelectedStyle(locStyle);
locationLabel.setPressedStyle(locStyle);
locationLabel.setUnselectedStyle(locStyle);
ratingLabel = new Label();
contImage.addComponent(orgImgButton);
contDet.addComponent(orgNameLabel);
contDet.addComponent(locationLabel);
addComponent(BorderLayout.WEST, contImage);
addComponent(BorderLayout.CENTER, contDet);
} catch (Exception ex) {
System.out.println("ex" + ex.getMessage());
}
}
public Component getListCellRendererComponent(List list, Object value,
int index, boolean isSelected) {
// System.out.println("adding names & loc");
setFocus(isSelected);
for (int i = 0; i < list.size(); i++) {
if (index == i) {
orgNameLabel.setText(tempName[i]);
locationLabel.setText(districtDesc[i] + "," + townDesc[i]);
orgImgButton.setIcon(DefaultLayout.CreateScaledImage(loadImage(thumbnailURL), DefaultLayout.screenWidth()*10/100, DefaultLayout.screenHeight()*9/100));
}
}
if (isSelected) {
getStyle().setBgColor(0x00BFFF);
getStyle().setBgTransparency(100);
} else {
getStyle().setBgTransparency(30);
}
return this;
}
You are invoking scaled() which is a VERY slow and expensive operation within a renderer which must be REALLY fast. Not a good idea. Not sure if that answers your issue but I suggest investigating whether the TRAIL flag is the cause of your issue.
Related
I have a fixed-length List that is used in the "build" function. I want to replace one element in that List with another. Both elements in the List are Containers. I replace the element in the List and do a setState(). The build function uses the List in the body of the Scaffold. I get no error, however when the rebuild is done, nothing has changed.
To my knowledge this is not breaking any rules and as far as I know should cause no problems.
While I could code around the issue, I think that with something as fundamental as this, I need to find the reason for it.
Any ideas as to why this is happening?
Code added below:
Below is the code that DOES NOT work
if (_lwDisplay[iNdxDisplay] == null) /*INITIAL DISPLAY */ {
_lwDisplay[iNdxDisplay] = wContainer;
} else {
setState(() {
_tfDataHasChanged = true;
_lwDisplay[iNdxDisplay] = wContainer;
});
}
Below is the code that DOES work
if (_lwDisplay[iNdxDisplay] == null) /*INITIAL DISPLAY */ {
_lwDisplay[iNdxDisplay] = wContainer;
} else {
_tfDataHasChanged = _fnHasDataChanged() /* FOR FAB */;
List<Widget> lwDisplay2 = List(_lwDisplay.length);
for (int iNdx = 0; iNdx < lwDisplay2.length; iNdx++) {
if (iNdx != iNdxDisplay) {
lwDisplay2[iNdx] = _lwDisplay[iNdx];
}
}
lwDisplay2[iNdxDisplay] = wContainer;
_lwDisplay = lwDisplay2;
setState(() {});
}
Without seeing the entirety of code, and according to this SO question,
Move the instantiation of the list of widgets to the build method of your main widget.
I.E.
class MainWidgetState extends State<MainWidget> {
List<YOUR_WIDGET> _lwDisplay = new List();
Widget build(BuildContext context) {
//Create your list
}
}
Also, add a key to each item in your widget (if you haven't done so already).
I am trying to make a guessing game where the program will display a sequence of a number one at a time. I have the sequence randomly generated from a list but I have not been able to display the values in the list one at a time. I want to change the label using bind but I can't seem to make it work.
public class Tutorial extends Application {
Stage window;
Scene scene1, scene2;
Label label;
public static void main(String[] args) {
launch(args);
}
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
//Scene 1
Label welcome = new Label("Welcome to the Guessing Game. Press Start to Enter");
Button start = new Button("Start");
VBox firstlayout = new VBox(10);
firstlayout.getChildren().addAll(welcome, start);
firstlayout.setAlignment(Pos.CENTER);
start.setOnAction(e -> window.setScene(scene2));
scene1 = new Scene(firstlayout, 450, 300);
window.setScene(scene1);
ArrayList<Integer> guessList = numbergen();
Label label = new Label(Integer.toString(getValues(guessList)));
label.setStyle("-fx-text-fill: red; -fx-padding: 10px; -fx-font-size: 50px");
FadeTransition fader = createFader(label);
SequentialTransition Fader = new SequentialTransition(
label,
fader
);
StackPane layout = new StackPane();
layout.getChildren().addAll(label);
scene2 = new Scene(layout, 250, 300);
Fader.play();
window.setTitle("Program Close");
window.setScene(scene1);
window.show();
}
private FadeTransition createFader(Node node) {
FadeTransition fade = new FadeTransition(Duration.seconds(5), node);
fade.setFromValue(1);
fade.setToValue(0);
return fade;
}
public ArrayList<Integer> numbergen(){
ArrayList<Integer> numb = new ArrayList<Integer>();
Random rand = new Random();
for(int i = 0; i<4; i++){
int n = rand.nextInt(5) + 1;
numb.add(n);
}
return numb;
}
public boolean result(ArrayList<Integer> solnList, ArrayList<Integer> guessList){
if(solnList.size() != guessList.size()){
return false;
}else{
for(int i = 0; i<solnList.size(); i++){
if(solnList.get(i) != guessList.get(i)){
return false;
}
}
return true;
}
}
public int getValues(ArrayList<Integer> list){
for(int i = 0; i<list.size(); i++){
return list.get(i);
}
return 0;
}
}
If you want a binding to an integer list element, you can use:
Bindings.integerValueAt(observableList, observableIndex)
For example:
label.textProperty().bind(
Bindings.integerValueAt(observableList, observableIndex).asString()
);
where observableIndex in an IntegerProperty which refers to the current index of an element in the list whose value you wish to be bound to.
When you call observableIndex.add(1), then the binding value will change appropriately.
I am using Google place API in my application for searching location. When user input text in edit field then the API called and resulted output will shown in a list.
I implemented it successfully but the problem is that each time edit field text changes, the list is not repainting and output is added to the end of the list. I want every time the text changes in the edit text field, the list must remove its previous content that are invalid.
This can be seen in pictures:
For Implementing this, I have written this code:
public final class MyScreen extends MainScreen {
/**
* Creates a new MyScreen object
*/
private Vector _listElements;
ListField list;
JSONObject[] jsonobject;
EditField editfield;
String url = "https://maps.googleapis.com/maps/api/place/autocomplete/json?input=";
String[] locationName;
VerticalFieldManager verticalFieldManager = new VerticalFieldManager();
public MyScreen() {
ButtonField search = new ButtonField("Search");
_listElements = new Vector();
list = new ListField();
ListCallback _callback = new ListCallback(this);
// Set the displayed title of the screen
setTitle("Search Edit Field");
editfield = new EditField();
editfield.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
list.invalidate();
createField();
}
});
}
});
list.setCallback(_callback);
add(editfield);
add(new SeparatorField());
verticalFieldManager.add(list);
add(verticalFieldManager);
}
protected void createField() {
ShowList();
reloadList();
}
private void reloadList() {
list.setSize(_listElements.size());
}
class ListCallback implements ListFieldCallback {
MyScreen listDemoScreen;
public ListCallback(MyScreen listDemoScreen) {
this.listDemoScreen = listDemoScreen;
}
public void drawListRow(ListField list, Graphics g, int index, int y,
int w) {
String text = (String) _listElements.elementAt(index);
list.setRowHeight(getFont().getHeight());
g.drawText(text, 0, y, 0, -1);
}
public Object get(ListField list, int index) {
return _listElements.elementAt(index);
}
public int indexOfList(ListField list, String prefix, int string) {
return _listElements.indexOf(prefix, string);
}
public int getPreferredWidth(ListField list) {
return Display.getWidth();
}
}
protected void ShowList() {
HttpConnection httpConn;
InputStream in;
ConnectionFactory connFact = new ConnectionFactory();
ConnectionDescriptor connDesc;
String response;
String fieldText = editfield.getText();
connDesc = connFact.getConnection(url + fieldText
+ "%#&sensor=true&key=xxxxxxxxxxxxx"
+ ConnectionType.getConnectionType());
if (connDesc != null) {
httpConn = (HttpConnection) connDesc.getConnection();
try {
int responseCode = httpConn.getResponseCode();
if (responseCode == HttpConnection.HTTP_OK) {
in = httpConn.openInputStream();
StringBuffer buf = new StringBuffer();
int read = -1;
while ((read = in.read()) != -1)
buf.append((char) read);
response = buf.toString();
try {
JSONObject object = new JSONObject(response);
JSONArray ar = object.getJSONArray("predictions");
jsonobject = new JSONObject[ar.length()];
locationName = new String[ar.length()];
list.invalidate();
for (int i = 0; i < ar.length(); i++) {
jsonobject[i] = ar.getJSONObject(i);
_listElements.addElement(jsonobject[i]
.getString("description"));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
} else {
Dialog.alert("Connection not succeded");
}
}
protected boolean onSavePrompt() {
return true;
}
}
Update and Solution:
only modify this and this rest is working fine. As Peter Suggests, we can also put a Thread.sleep(time); in order to get the UI not blocked:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_listElements.removeAllElements();
createField();
}
});
I think your problem is simply that you do not clear the _listElements Vector when you request more data. So _listElements just gets bigger.
However there is a bigger problem here and that is that your code appears to be running networking operations on the Event Thread. What your should do in your changeListener. is start a Thread that requests the data, then repopulate the ListField when this tread gets data.
As a result of this change, the UI will not be blocked, and the List updates will become asynchronous, so your user could in fact enter another character into the EditField before the first Thread response comes back. To prevent this looking silly, you could delay the Thread processing for a fraction of second to see if another character is entered, and/or you could make sure that the EditField content was still the same as the requested characters before you repopulate it.
I personally prefer this asynchronous approach, but if it bothers you, you could put a 'please wait - loading' type screen to block the user until the response comes back.
Update
Remember that if you start a background Thread, you need to get back onto the Event Thread to do Ui Processing. Typically this is done simply by including your UI code within the run method of a Runnable that is invoked later, for example:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// Ui Code in here
}
});
You should only put Ui Updating code in the runnable. Networking processing, or any other blocking action, should NOT be included.
I'm new to iphone development but I have done android before. The following is something I have done in java and I want to convert this over to iphone.
public class RelationshipTipsActivity extends Activity implements
OnClickListener {
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
String facts[] = {"Coming soon",
"Coming soon", };
TextView display, display1;
TextView counter;
Button begin;
Button next;
Button previous;
Button random;
Random myRandom;
int index = facts.length;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(starting.rt.R.layout.relationship);
AdView ad = (AdView) findViewById(R.id.ad);
ad.loadAd(new AdRequest());
display1 = (TextView) findViewById(starting.rt.R.id.Begin);
display = (TextView) findViewById(starting.rt.R.id.tvResults);
counter = (TextView) findViewById(starting.rt.R.id.tvCounter);
next = (Button) findViewById(starting.rt.R.id.Next);
previous = (Button) findViewById(starting.rt.R.id.Previous);
random = (Button) findViewById(starting.rt.R.id.Random);
next.setOnClickListener(this);
previous.setOnClickListener(this);
random.setOnClickListener(this);
// display.setOnTouchListener(this.gestureListener);
myRandom = new Random();
// gestureDetector = new GestureDetector(new MyGestureDetector());
// gestureListener = new View.OnTouchListener() {
// public boolean onTouch(View v, MotionEvent event) {
// return gestureDetector.onTouchEvent(event);
// }
// };
}
private void showDisplay() {
display.setText(facts[index]);
counter.setText(String.valueOf(index + 1) + "/"
+ String.valueOf(facts.length));
}
public void onClick(View arg0) {
// TODO Auto-generated method stub
switch (arg0.getId()) {
case starting.rt.R.id.Next:
index++;
if (index > facts.length - 1) {
index = 0;
}
showDisplay();
break;
case starting.rt.R.id.Previous:
index--;
if (index < 0) {
index = facts.length - 1;
}
showDisplay();
break;
case starting.rt.R.id.Random:
index = (myRandom.nextInt(facts.length) - 1);
if (index < 0) {
index = facts.length - 1;
}
showDisplay();
break;
}
}
}
How would you convert something along the lines of that code from android to iphone.
I have this code so far for iphone, I just don't know where to go from there.
(IBAction) clicked:(id)sender{
NSArray *titleOfButton = [sender titleForState:UIControlStateNormal];
//NSString *newLabelText = [[NSString alloc]initWithFormat:#"%#", titleOfButton];
NSArray *initializedNSArray = [NSArray arrayWithObjects: #"red",
#"blue",
#"green",
#"yellow",
nil];
labelsText.text = initializedNSArray;
[initializedNSArray release];
}
I want to be able to display those strings within the Iphone View. And be able to click a next or previous button to go to the next or previous string which could be from blue to red or red to blue. Basically if there are any tutorials out there that help me with that or if you know how to help I would appreciate. Thanks!
Why not have a int variable with the current position of the string from the array and two methods goPrev - goNext that increments and decrements the int variable.
In the interface:
UIButton *btn;
int step;
NSArray *titles;
And in the implementation:
-(void)setup {
titles = [NSArray arrayWithObjects:#"Title 1",#"Title 2",#"Title 3",#"Title 4", nil];
btn = [UIButton buttonWithType:UIButtonTypeCustom];
}
-(void)goPrev {
if (step>0) {
step--;
}
[btn setTitle:[titles objectAtIndex:step] forState:UIControlStateNormal];
}
-(void)goNext {
if (step<titles.count-1) {
step++;
}
[btn setTitle:[titles objectAtIndex:step] forState:UIControlStateNormal];
}
A 2-sash sashform. A 3-level TreeViewer in one and a TableViewer in the other. When it starts no item is selected in the TreeViewer
and the TableViewer shows a list of all the first level objects available. To achieve this, the TreeViewerContainer instantiates the TableViewerContainer and then calls its showFirstLevelItemList( ) method :
public class TableViewerContainer {
private Table table;
private TableViewer tableViewer;
private TableColumnLayout layout;
public TableViewerContainer(SashForm sashForm) {
Composite composite = new Composite(sashForm, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
tableViewer = new TableViewer(composite, SWT.BORDER
| SWT.FULL_SELECTION);
table = tableViewer.getTable();
table.setHeaderVisible(true);
table.setLinesVisible(true);
// Add TableColumnLayout
layout = new TableColumnLayout();
composite.setLayout(layout);
}
public void showFirstLevelItemList( FirstLevelItemListContainer obj ) {
// Add the only column
TableViewerColumn tableViewerColumn = new TableViewerColumn(
tableViewer, SWT.NONE);
TableColumn tblclmnFirst = tableViewerColumn.getColumn();
layout.setColumnData(tblclmnFirst, new ColumnWeightData(10,
ColumnWeightData.MINIMUM_WIDTH, false));
tblclmnFirst.setText("Description");
// assign providers and show the table
tableViewer.setLabelProvider(new FirstLevelItemLabelProvider());
tableViewer.setContentProvider(new FirstLevelItemContentProvider());
tableViewer.setInput(obj);
}
This works fine.
Next, selecting an item in the TreeViewer causes the tableViewer to update the data accordingly. To effect this I added a SelectionChangedListener():
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event
.getSelection();
Object obj = selection.getFirstElement();
if (obj instanceof firsLevelDetail ) {
FirstLevelDetail fld = (FirstLevelDetail) obj;
tableViewer.showFirstLevelDetail(fld);
} else if (obj instanceof SecondLevelDetail )
SecondLevelDetail sld = (SecondLevelDetail) obj;
tableViewer.showSecondLevelDetail(sld);
else if (obj instanceof ThirdLevelDetail)
ThirdLevelDetail tld = (ThirdLevelDetail) obj;
tableViewer.showSecondLevelDetail(tld);
}
});`
So that when the user selects a firstLevelItem the TableViewer shows the corresponding data. All the methods called follow the following pattern :
private void showFirstLevelDetail( FirstLevelDetailObj obj ) {
Table tbl = tableViewer.getTable();
tbl.setRedraw(false);
// Dispose former columns
while (tbl.getColumnCount() > 0) {
tbl.getColumns()[0].dispose();
}
// add new columns
TableViewerColumn tableViewerColumn = new TableViewerColumn(
tableViewer, SWT.NONE);
TableColumn tblclmn = tableViewerColumn.getColumn();
layout.setColumnData(tblclmn, new ColumnWeightData(1,
ColumnWeightData.MINIMUM_WIDTH, true));
tblclmn.setText("Code FL Item");
tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
tblclmn = tableViewerColumn.getColumn();
layout.setColumnData(tblclmn, new ColumnWeightData(1,
ColumnWeightData.MINIMUM_WIDTH, true));
tblclmn.setText("Description FL Item");
tbl.setRedraw(true);
// to avoid an Exception
tableViewer.setInput(null);
// Assign new providers and show the data
tableViewer.setLabelProvider(new FirstLevelDetailLabelProvider());
tableViewer.setContentProvider(new FirstLevelDetailContentProvider());
tableViewer.setInput(obj);
}
The ContentProviders' getElements() methods follow the next patern:
public Object[] getElements(Object inputElement) {
return ((FirstLevelDetail)inputElement).getArrayItems();
}
My problem is after this process the table doesn't show a header or any data until it is resized. Then it works normally until another item is selected, no matter what level the item is.
tableViewer.refresh() does not work.
tableViewer.getTable().redraw() does not work.
All the showXxxxLevelDetail () work properly if they are called in the first place, instead of showFirstLevelItemList() method, provided tableViewer.setInput(null) is commented out.
I'm running Eclipse Indigo, jface 3.8, Windows XP.
I would try to call
composite.layout();
after calling any of those showXXXLevelDetail() methods.