SWT nested composite layout issue - nested

I am new to SWT but have plenty of experience w/ other GUI layout managers.
I have run in to a weird problem when nesting a composite inside of another composite.
http://www.swooby.com/swt/nestedcontrolproblem.png
If I run the audiocontrol as a standalone bean it works fine.
If I run it nested in another composite it starts to act funny.
When I add this composite to a more complex parent (6 columns), the nested composite does not seem to be honoring its own class defined horizontal span correctly.
The audiocontrol lays out fine in a lesser complex parent (total of 2 columns).
I am using Eclipse Visual Editor to lay these out, so I have not written any of my own code to alter the layout (except to change a Composite type to CompositeAudio).
Code to repro this:
Parent.java
package com.twistpair.qa;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
public class Parent extends Composite {
private AudioControl compositeAudio = null;
public Parent(Composite parent, int style) {
super(parent, style);
initialize();
}
private void initialize() {
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 2;
this.setLayout(gridLayout);
createCompositeAudio();
setSize(new Point(97, 673));
}
/**
* This method initializes compositeAudio
*
*/
private void createCompositeAudio() {
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.CENTER;
gridData.grabExcessHorizontalSpace = false;
gridData.grabExcessVerticalSpace = false;
gridData.horizontalSpan = 2;
gridData.verticalAlignment = GridData.CENTER;
compositeAudio = new AudioControl(this, SWT.NONE);
compositeAudio.setLayout(new GridLayout());
compositeAudio.setLayoutData(gridData);
}
} // #jve:decl-index=0:visual-constraint="36,7"
AudioControl.java:
package com.twistpair.qa;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Display;
public class AudioControl extends Composite {
private CLabel cLabelAudio = null;
private Button checkBoxRunning = null;
private CLabel cLabelVolume = null;
private Scale scaleVolumeLeft = null;
private CLabel cLabelVuMeter = null;
private Canvas canvasVuMeterLeft = null;
private Button checkBoxMuteRx = null;
private Button checkBoxMuteTx = null;
private Button checkBoxMuteBoth = null;
private Scale scaleVolumeRight = null;
private Canvas canvasVuMeterRight = null;
public AudioControl(Composite parent, int style) {
super(parent, style);
initialize();
}
private void initialize() {
GridData gridData31 = new GridData();
gridData31.horizontalAlignment = GridData.CENTER;
gridData31.verticalAlignment = GridData.CENTER;
GridData gridData21 = new GridData();
gridData21.horizontalAlignment = GridData.CENTER;
gridData21.verticalAlignment = GridData.CENTER;
GridData gridData11 = new GridData();
gridData11.horizontalSpan = 2;
GridData gridData5 = new GridData();
gridData5.horizontalSpan = 2;
gridData5.verticalAlignment = GridData.CENTER;
gridData5.horizontalAlignment = GridData.CENTER;
GridData gridData4 = new GridData();
gridData4.horizontalSpan = 2;
gridData4.verticalAlignment = GridData.CENTER;
gridData4.horizontalAlignment = GridData.CENTER;
GridData gridData3 = new GridData();
gridData3.horizontalSpan = 2;
gridData3.verticalAlignment = GridData.CENTER;
gridData3.horizontalAlignment = GridData.CENTER;
GridData gridData2 = new GridData();
gridData2.horizontalSpan = 2;
GridData gridData1 = new GridData();
gridData1.horizontalSpan = 2;
GridData gridData = new GridData();
gridData.horizontalSpan = 2;
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 2;
cLabelAudio = new CLabel(this, SWT.NONE);
cLabelAudio.setText("Audio");
cLabelAudio.setFont(new Font(Display.getDefault(), "Segoe UI", 9, SWT.BOLD));
cLabelAudio.setLayoutData(gridData5);
checkBoxRunning = new Button(this, SWT.CHECK);
checkBoxRunning.setText("Running");
checkBoxRunning.setLayoutData(gridData11);
cLabelVolume = new CLabel(this, SWT.NONE);
cLabelVolume.setText("Volume");
cLabelVolume.setFont(new Font(Display.getDefault(), "Segoe UI", 9, SWT.BOLD));
cLabelVolume.setLayoutData(gridData4);
scaleVolumeLeft = new Scale(this, SWT.VERTICAL);
scaleVolumeLeft.setLayoutData(gridData21);
scaleVolumeRight = new Scale(this, SWT.VERTICAL);
scaleVolumeRight.setLayoutData(gridData31);
cLabelVuMeter = new CLabel(this, SWT.NONE);
cLabelVuMeter.setText("VU Meter");
cLabelVuMeter.setFont(new Font(Display.getDefault(), "Segoe UI", 9, SWT.BOLD));
cLabelVuMeter.setLayoutData(gridData3);
createCanvasVuMeterLeft();
this.setLayout(gridLayout);
this.setSize(new Point(151, 415));
createCanvasVuMeterRight();
checkBoxMuteRx = new Button(this, SWT.CHECK);
checkBoxMuteRx.setText("Mute RX");
checkBoxMuteRx.setLayoutData(gridData);
checkBoxMuteTx = new Button(this, SWT.CHECK);
checkBoxMuteTx.setText("Mute TX");
checkBoxMuteTx.setLayoutData(gridData1);
checkBoxMuteBoth = new Button(this, SWT.CHECK);
checkBoxMuteBoth.setText("Mute Both");
checkBoxMuteBoth.setLayoutData(gridData2);
}
/**
* This method initializes canvasVuMeterLeft
*
*/
private void createCanvasVuMeterLeft() {
canvasVuMeterLeft = new Canvas(this, SWT.BORDER);
}
/**
* This method initializes canvasVuMeterRight
*
*/
private void createCanvasVuMeterRight() {
canvasVuMeterRight = new Canvas(this, SWT.BORDER);
}
} // #jve:decl-index=0:visual-constraint="10,10"
My other problem was that the audiocontrol initially had the three "Mute *" checkboxes underneath the two VU (left/right) canvases. In a lesser complex parent the layout was mostly behaving, but the three checkboxes below the VU canvases were not being created.
I used a spy program to browse the running UI, and the controls were indeed not there. The code did have valid objects that I could manipulate.
I thought this was weird, and seem to have temporarily solved the problem by just moving the checkboxes, but I think this could be an indicator that there is something wrong w/ my audiocontrol.
Has anyone seen anything like these two problems? I searched the net and stackoverflow and didn't see anything directly related.
Thanks!
Pv

Related

Error:(66, 27) error: constructor LineData in class LineData cannot be applied to given types; required: ILineDataSet[] found: String[],

I was following the example on youtube, https://www.youtube.com/watch?v=TNeE9DJoOMY&t=614s, Creating a Line Graph with multiple data sets in Android Studio. I believe the code is correct... but still getting error: constuctor LineData error.. Another post on stackoverflow suggested that maybe the MPandroidChart library may have changed requiring a different input? The full error is:
Error:(66, 27) error: constructor LineData in class LineData cannot be applied to given types;
required: ILineDataSet[]
found: String[],LineDataSet
reason: varargs mismatch; String[] cannot be converted to ILineDataSet
Here is my main code:
package com.example.rj.linegraph1;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
LineChart lineChart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lineChart = (LineChart) findViewById(R.id.lineChart);
ArrayList<String> xAXIS = new ArrayList<>();
ArrayList<Entry> yAXISsin = new ArrayList<>();
ArrayList<Entry> yAXIScos = new ArrayList<>();
double x = 0;
int numDataPoints = 1000;
for (int i = 0; i < numDataPoints; i++) {
float sinFunction = Float.parseFloat(String.valueOf(Math.sin(x)));
float cosFunction = Float.parseFloat(String.valueOf(Math.cos(x)));
x = x + 0.1;
yAXISsin.add(new Entry(sinFunction,i));
yAXIScos.add(new Entry(cosFunction,i));
xAXIS.add(i, String.valueOf(x));
}
String[] xaxis = new String[xAXIS.size()];
for(int i = 0; i < xAXIS.size(); i++) {
xaxis[i] = xAXIS.get(i).toString();
}
ArrayList<ILineDataSet> lineDataSets = new ArrayList<>();
LineDataSet lineDataSet1 = new LineDataSet(yAXIScos,"cos");
lineDataSet1.setDrawCircles(false);
lineDataSet1.setColors(Color.BLUE);
LineDataSet lineDataSet2 = new LineDataSet(yAXISsin,"sin");
lineDataSet2.setDrawCircles(false);
lineDataSet2.setColors(Color.RED);
lineDataSets.add(lineDataSet1);
lineDataSets.add(lineDataSet2);
lineChart.setData(new LineData(xaxis,lineDataSets));
lineChart.setVisibleXRangeMaximum(65f);
}
}
I think this is how the library requires you to do it now:
for (int i = 0; i < numDataPoints; i++) {
float sinFunction = Float.parseFloat(String.valueOf(Math.sin(x)));
float cosFunction = Float.parseFloat(String.valueOf(Math.cos(x)));
x = x + 0.1;
yAXISsin.add(new Entry(x, sinFunction));
yAXIScos.add(new Entry(x, cosFunction));
//dont use strings anymore
//xAXIS.add(i, String.valueOf(x));
}
ArrayList<ILineDataSet> lineDataSets = new ArrayList<>();
LineDataSet lineDataSet1 = new LineDataSet(yAXIScos,"cos");
LineDataSet lineDataSet2 = new LineDataSet(yAXISsin,"sin");
lineDataSet1.setDrawCircles(false);
lineDataSet1.setColors(Color.RED);
lineDataSet2.setDrawCircles(false);
lineDataSet2.setColors(Color.BLUE);
lineDataSets.add(lineDataSet1);
lineDataSets.add(lineDataSet2);
lineChart.setData(new LineData(lineDataSets));
lineChart.setVisibleXRangeMaximum(65f);
Pretty sure it's something like that. You no longer add the X-Axis values like before. Now the X-Axis values just get added as Entry's.
Let me know if this works. I didn't try it myself.
It might be because you need 'x' to be a double for the math operations but you need to convert it to a float for each Entry.
I also added some logs in here so you can debug it might easily.
public class MainActivity extends AppCompatActivity {
//added for debugging
private static final String TAG = "MainActivity";
LineChart lineChart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lineChart = (LineChart) findViewById(R.id.lineChart);
ArrayList<Entry> yAXISsin = new ArrayList<>();
ArrayList<Entry> yAXIScos = new ArrayList<>();
double x = 0.0;
int numDataPoints = 1000;
for (int i = 0; i < numDataPoints; i++) {
float sinFunction = Float.parseFloat(String.valueOf(Math.sin(x)));
float cosFunction = Float.parseFloat(String.valueOf(Math.cos(x)));
x = x + 0.1;
float xEntry = Float.parseFloat(String.valueOf(x));
yAXISsin.add(new Entry(xEntry, sinFunction));
yAXIScos.add(new Entry(xEntry, cosFunction));
Log.d(TAG, "Populating Arrays with Data: yAXISsin = " + sinFunction);
Log.d(TAG, "Populating Arrays with Data: yAXIScos = " + cosFunction);
Log.d(TAG, "Populating Arrays with Data: xEntry = " + xEntry);
}
ArrayList<ILineDataSet> lineDataSets = new ArrayList<>();
LineDataSet lineDataSet1 = new LineDataSet(yAXIScos,"cos");
LineDataSet lineDataSet2 = new LineDataSet(yAXISsin,"sin");
lineDataSet1.setDrawCircles(false);
lineDataSet1.setColors(Color.RED);
lineDataSet2.setDrawCircles(false);
lineDataSet2.setColors(Color.BLUE);
lineDataSets.add(lineDataSet1);
lineDataSets.add(lineDataSet2);
lineChart.setData(new LineData(lineDataSets));
lineChart.setVisibleXRangeMaximum(65f);
//can also try calling invalidate() to refresh the graph
lineChart.invalidate();

Converting from Timeline to Thread

I am trying to create a program that runs off of a thread instead of a timeline. Here is my modified program down below. I am not sure why it will not work. Any tips would be appreciated. The thread uses a task in order to start the animation. Thanks for your help.
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Arc;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class ch30 extends Application {
#Override // Override the start method in the Application class
public void start(Stage primaryStage) {
FanPane fan = new FanPane();
HBox hBox = new HBox(5);
Button btPause = new Button("Pause");
Button btResume = new Button("Resume");
Button btReverse = new Button("Reverse");
hBox.setAlignment(Pos.CENTER);
hBox.getChildren().addAll(btPause, btResume, btReverse);
BorderPane pane = new BorderPane();
pane.setCenter(fan);
pane.setBottom(hBox);
// Create a scene and place it in the stage
Scene scene = new Scene(pane, 200, 200);
primaryStage.setTitle("Exercise15_28"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
Runnable first = new Begin();
Thread t1 = new Thread(first);
t1.start();
//Timeline animation = new Timeline(
//new KeyFrame(Duration.millis(100), e -> fan.move()));
//animation.setCycleCount(Timeline.INDEFINITE);
//animation.play(); // Start animation
scene.widthProperty().addListener(e -> fan.setW(fan.getWidth()));
scene.heightProperty().addListener(e -> fan.setH(fan.getHeight()));
//btPause.setOnAction(e -> first.wait());
btResume.setOnAction(e -> first.run());
btReverse.setOnAction(e -> fan.reverse());
}
/**
* The main method is only needed for the IDE with limited
* JavaFX support. Not needed for running from the command line.
*/
public static void main(String[] args) {
launch(args);
}
}
class FanPane extends Pane {
private double w = 200;
private double h = 200;
private double radius = Math.min(w, h) * 0.45;
private Arc arc[] = new Arc[4];
private double startAngle = 30;
private Circle circle = new Circle(w / 2, h / 2, radius);
public FanPane() {
circle.setStroke(Color.BLACK);
circle.setFill(Color.WHITE);
getChildren().add(circle);
for (int i = 0; i < 4; i++) {
arc[i] = new Arc(w / 2, h / 2, radius * 0.9, radius * 0.9, startAngle + i * 90, 35);
arc[i].setFill(Color.RED); // Set fill color
arc[i].setType(ArcType.ROUND);
getChildren().addAll(arc[i]);
}
}
private double increment = 5;
public void reverse() {
increment = -increment;
}
public void move() {
setStartAngle(startAngle + increment);
}
public void setStartAngle(double angle) {
startAngle = angle;
setValues();
}
public void setValues() {
radius = Math.min(w, h) * 0.45;
circle.setRadius(radius);
circle.setCenterX(w / 2);
circle.setCenterY(h / 2);
for (int i = 0; i < 4; i++) {
arc[i].setRadiusX(radius * 0.9);
arc[i].setRadiusY(radius * 0.9);
arc[i].setCenterX(w / 2);
arc[i].setCenterY(h / 2);
arc[i].setStartAngle(startAngle + i * 90);
}
}
public void setW(double w) {
this.w = w;
setValues();
}
public void setH(double h) {
this.h = h;
setValues();
}
}
class Begin implements Runnable {
private int times = 1000;
FanPane fan = new FanPane();
public Begin(){
// times = t;
}
#Override
public void run(){
//for (int i = 0; i < times; i++)
//{
fan.move();
}
}
Your thread needs a loop, that repeatedly pauses and then updates the UI. If you want to use an explicit thread instead of the more obvious Timeline, you need to write the code for that loop yourself.
The update of the UI cannot be called from the background thread you are creating: to update the UI on the FX Application thread you must wrap the call to the method(s) that update the UI in Platform.runLater(...).

MvvmCross - MvxTabBarViewController does not show the "More" button when using a Storyboard

In my application, I'm using the MvxTabBarViewController to display some tabs (the MvxTabBarViewController is loaded using a Storyboard):
public partial class RootView : MvxTabBarViewController
{
private int _tabIndex = 0;
private Dictionary<int, SectionBase> _sectionBaseForConfig;
public new RootViewModel ViewModel
{
get { return (RootViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
public RootView(IntPtr handle)
: base(handle)
{
}
UIViewController tab1, tab2, tab3, tab4, tab5, tab6, tab7;
public override async void ViewDidLoad()
{
base.ViewDidLoad();
if (ViewModel == null)
return;
tab1 = new UIViewController();
tab1.Title = "1";
tab1.View.BackgroundColor = UIColor.Green;
tab2 = new UIViewController();
tab2.Title = "2";
tab2.View.BackgroundColor = UIColor.Orange;
tab3 = new UIViewController();
tab3.Title = "3";
tab3.View.BackgroundColor = UIColor.Red;
tab4 = new UIViewController();
tab4.Title = "4";
tab4.View.BackgroundColor = UIColor.Blue;
tab5 = new UIViewController();
tab5.Title = "5";
tab5.View.BackgroundColor = UIColor.Brown;
tab6 = new UIViewController();
tab6.Title = "6";
tab6.View.BackgroundColor = UIColor.Brown;
tab7 = new UIViewController();
tab7.Title = "7";
tab7.View.BackgroundColor = UIColor.Brown;
var tabs = new UIViewController[] {
tab1, tab2, tab3, tab4, tab5, tab6, tab7
};
ViewControllers = tabs;
CustomizableViewControllers = null;
SelectedViewController = ViewControllers[0];
}
}
Unfortunately, even if there are 7 tabs, only 5 are displayed and the "More" button does not show. Anyone got an idea ? I stuck on this problem since 2 hrs now, without any clues :(
Thanks!

SWT: GridLayout column span

I've been using SWT for a few years, but i can't seem to figure this one out:
I need to SPLIT a VIEW into 2 "zones": LEFT and RIGHT
So i use a Composite with GridLayout with 2 columns to do it.
Inside the RIGHT composite i have a FIXED number of columns (created inside another GridLayout composite) but inside the LEFT composite i need to create a DYNAMIC number of columns that spans on the composite limit...
Is there a way to achieve this?
I tried a RowLayout inside left composite, but these 2 don't match :-\
Thanks
As it is not clear what you mean by
columns that spans on the composite limit
I tried a RowLayout inside left composite, but these 2 don't match
Therefore I am assuming that you want a dynamically changing gridlayout for your left composite. See the code below, specially the button.addSelectionListener().
import java.util.Random;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
public class DynamicComposite
{
public static void main(String[] args) {
new DynamicComposite().start();
}
private Composite compositeLeft;
private Composite compositeRight;
private Random rand;
public void start()
{
rand = new Random(System.currentTimeMillis());
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, true));
shell.setText("Dynamic Columns");
createRightComposite(shell);
createLeftComposite(shell);
createButtonComposite(shell);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
private void createButtonComposite(Shell shell)
{
Label l = new Label(shell, SWT.SEPARATOR|SWT.HORIZONTAL);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
gridData.horizontalSpan = 2;
l.setLayoutData(gridData);
Button button = new Button(shell, SWT.PUSH);
gridData = new GridData(SWT.CENTER, SWT.CENTER, true, false);
gridData.horizontalSpan = 2;
button.setLayoutData(gridData);
button.setText("Change Columns !!");
button.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if(compositeLeft == null || compositeLeft.isDisposed())
return;
GridLayout layout = (GridLayout)compositeLeft.getLayout();
int col = rand.nextInt(7);
if(col == 0)
col = 1;
layout.numColumns = col;
//compositeLeft.setLayout(layout);
compositeLeft.layout(); // You need to re-layout your composite
}
});
}
private void createRightComposite(Shell shell)
{
compositeLeft = new Composite(shell, SWT.NONE);
GridLayout gridLayout = new GridLayout(3, true);
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
gridLayout.marginLeft = 0;
gridLayout.marginRight= 0;
gridLayout.marginTop = 0;
gridLayout.marginBottom = 0;
gridLayout.horizontalSpacing = 0;
gridLayout.verticalSpacing = 0;
gridLayout.horizontalSpacing = 0;
compositeLeft.setLayout(gridLayout);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
compositeLeft.setLayoutData(gridData);
int counter = 17;
for(int i=0; i<counter; i++)
{
Button button = new Button(compositeLeft, SWT.PUSH);
button.setText("Button " + (i+1));
GridData bData = new GridData(SWT.FILL, SWT.FILL, true, false);
button.setLayoutData(bData);
}
}
private void createLeftComposite(Shell shell)
{
compositeRight = new Composite(shell, SWT.NONE);
GridLayout gridLayout = new GridLayout(3, true);
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
gridLayout.marginLeft = 0;
gridLayout.marginRight= 0;
gridLayout.marginTop = 0;
gridLayout.marginBottom = 0;
gridLayout.horizontalSpacing = 0;
compositeRight.setLayout(gridLayout);
GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
compositeRight.setLayoutData(gridData);
int counter = 7;
for(int i=0; i<counter; i++)
{
Button button = new Button(compositeRight, SWT.PUSH);
button.setText("Button " + (i+1));
GridData bData = new GridData(SWT.FILL, SWT.FILL, true, false);
button.setLayoutData(bData);
}
}
}

Why the Dialog is not shown in this situation?

I want to display a Dialog when I click on a userdefined component that I have created : I named its class name to ListBox. I want to simulate a LWUIT ComboBox with my user defined component which will accepts the blank area ; because LWUIT ComboBox doesn't accept the blank area.
The problem is that when my ListBox is at a coordinate such that there is no more space below it to display the Dialog then the Dialog is not shown ; but if there are more space below then the Dialog is shown.
Here is the captured image when the Dialog is not shown :
In the captured image the user defined ListBox is the component just above the two Buttons at the bottom of the phone screen.
And here are the codes :
public class ListBox extends Container implements ActionListener
{
private Container cListBox = new Container(new BorderLayout());
private Label[] tLabel;
private int[] tLabelW;
private int largestLabelW;
private Label libelle = new Label();
private Label arrow = new Label((MenuPrincipalForm.r).getImage("listboxarrow"));
private int preferredWidth, preferredHeight, screenWidth, screenHeight;
private Vector vData = new Vector();
private final int leftPadding = 3;
private CListCellListBox listRenderer;
private List list;
private Dialog dialog;
private String selectedData;
public ListBox(String[] lData, int prefHeight, int formWidth, int formHeight, int topMargin, int bottomMargin)
{
super(new FlowLayout(Component.CENTER));
setFocusable(true);
screenWidth = formWidth;
screenHeight = formHeight;
tLabel = new Label[lData.length + 1];
tLabelW = new int[lData.length + 1];
for (int i = 0 ; i < lData.length + 1 ; i++)
{
if (i < lData.length)
{
vData.addElement(new String(lData[i]));
tLabel[i] = new Label(lData[i]);
tLabelW[i] = tLabel[i].getPreferredW();
}
else
{
vData.addElement(new String(""));
tLabel[i] = new Label("");
tLabelW[i] = 0;
}
}
largestLabelW = Comparator.max(tLabelW);
preferredWidth = leftPadding + largestLabelW + arrow.getPreferredW();
preferredHeight = prefHeight - 2 ;
selectedData = String.valueOf(vData.lastElement());
libelle.setText(String.valueOf(vData.lastElement()));
libelle.setTextPosition(Label.LEFT);
libelle.setPreferredW(preferredWidth);
libelle.setPreferredH(preferredHeight);
arrow.setAlignment(Label.CENTER);
arrow.setPreferredH(preferredHeight);
listRenderer = new CListCellListBox(false);
list = (new CList(vData, false)).createList(listRenderer, this);
list.setItemGap(0);
list.setSelectedIndex(vData.indexOf(vData.lastElement()));
list.getUnselectedStyle().setPadding(0, 0, 0, 0);
list.getSelectedStyle().setPadding(0, 0, 0, 0);
list.setPreferredW(leftPadding+preferredWidth+arrow.getPreferredW());
dialog = new Dialog();
dialog.setScrollableY(false);
dialog.getContentPane().getSelectedStyle().setPadding(0, 0, leftPadding, 0);
dialog.getContentPane().getUnselectedStyle().setPadding(0, 0, leftPadding, 0);
dialog.addComponent(list);
cListBox.addComponent(BorderLayout.WEST, libelle);
cListBox.addComponent(BorderLayout.EAST, arrow);
cListBox.setPreferredH(preferredHeight);
getUnselectedStyle().setPadding(Component.LEFT, leftPadding);
getSelectedStyle().setPadding(Component.LEFT, leftPadding);
getUnselectedStyle().setBorder(Border.createLineBorder(1));
getSelectedStyle().setBorder(Border.createLineBorder(1));
addComponent(cListBox);
setPreferredH(preferredHeight);
getUnselectedStyle().setMargin(Component.TOP, topMargin);
getSelectedStyle().setMargin(Component.TOP, topMargin);
getUnselectedStyle().setMargin(Component.BOTTOM, bottomMargin);
getSelectedStyle().setMargin(Component.BOTTOM, bottomMargin);
}
public void actionPerformed(ActionEvent ae)
{
if ( (ae.getSource() instanceof List) && ((List)ae.getSource()).equals(list) )
{
dialog.dispose();
if (list.getSelectedItem() instanceof Content)
{
Content valeur = (Content)list.getSelectedItem();
selectedData = valeur.getEnreg();
libelle.setText(selectedData);
repaint();
}
}
}
public void setSelectedIndex(int idx)
{
list.setSelectedIndex(idx);
selectedData = String.valueOf(vData.elementAt(idx));
libelle.setText(String.valueOf(vData.elementAt(idx)));
repaint();
}
public String getSelectedData()
{
return selectedData;
}
public void pointerPressed(int x, int y)
{
int espaceVertRestant, top, bottom, left, right;
espaceVertRestant = screenHeight - ( libelle.getAbsoluteY() + preferredHeight );
if (espaceVertRestant > list.getPreferredH())
{
top = getAbsoluteY() + preferredHeight - 1 ;
bottom = screenHeight - ( getAbsoluteY() + preferredHeight + list.getPreferredH() ) ;
}
else
{
top = screenHeight - ( list.getPreferredH() + preferredHeight + espaceVertRestant ) ;
bottom = getAbsoluteY() ;
}
left = getAbsoluteX() ;
right = screenWidth - ( getAbsoluteX() + getPreferredW() );
dialog.show(top, bottom, left, right, false, true);
}
}
Here is the code of the Form where I add this ListBox component :
public class ModifierEcheanceForm extends Form implements ActionListener, DataChangedListener {
private VirtualKeyboard vkNombre = new VirtualKeyboard();
private String textFieldStatus, listBoxStatus;
private Container cntnr = new Container();
private Container c = new Container();
private Container c1 = new Container();
private Container c2 = new Container();
private Container c3 = new Container();
private Container c4 = new Container();
private Container c5 = new Container();
private Container c6 = new Container();
private Container c7 = new Container();
private Container c8 = new Container();
private Container c9 = new Container();
private Container c10 = new Container(new FlowLayout(Component.CENTER));
private Container cz1 = new Container();
private Container cz2 = new Container();
private Container cz3 = new Container();
private Container cz4 = new Container();
private Container cz5 = new Container();
private TextField t1=new TextField("zzz"),t2=new TextField("zzz"),t3=new TextField("zzz"),t4=new TextField("zzz"),t5=new TextField("zzz");
private Button modifierBtn, reset;
private BoxLayout bxl = new BoxLayout(BoxLayout.Y_AXIS);
private BoxLayout bxltx = new BoxLayout(BoxLayout.X_AXIS);
private boolean isMenuShown;
private Command annulerCmd;
private Command listeMenu, listeClientCmd, listeCreditCmd, ppalCmd;
private Command ficheMenu, backCmd;
private SmartPhoneBanking controler;
private Form backForm, OldbackForm;
private EcheanceDB echeancedb;
private Vector listecheance = new Vector();
private int idEcheance;
private Label echedatelbl, montantlbl, eche_payelbl, eche_retardlbl, ecehe_nbretardlbl, eche_crdlbl, eche_rembourselbl, eche_interetlbl,flagPayelbl;
private TextField echedatetxt, montanttxt, eche_payetxt, eche_retardtxt, ecehe_nbretardtxt, eche_crdtxt, eche_remboursetxt, eche_interettxt;
private ListBox flagPayetxt; // here is the ListBox
private CreditDB creditdb = new CreditDB();
private Vector listeCredit = new Vector();
private String idClient, idCredit;
public static int listEcheanceSelectedRow;
public ModifierEcheanceForm(SmartPhoneBanking ctrl, int idEcheance, Form prevForm)
{
super("Modification échéance");
vkNombre.setInputModeOrder(new String[]{VirtualKeyboard.NUMBERS_SYMBOLS_MODE});
this.controler = ctrl;
this.idEcheance = idEcheance;
backForm = prevForm;
OldbackForm = FicheCreditForm.backForm;
echeancedb = new EcheanceDB();
listecheance = echeancedb.echeanceParId(String.valueOf(idEcheance));
idCredit = String.valueOf(listecheance.elementAt(5));
listeCredit = creditdb.listCredit(Integer.parseInt(idCredit));
idClient = String.valueOf(listeCredit.elementAt(12));
c.setLayout(bxl);
c1.setLayout(bxltx);
c2.setLayout(bxltx);
c3.setLayout(bxltx);
c4.setLayout(bxltx);
c5.setLayout(bxltx);
c6.setLayout(bxltx);
c7.setLayout(bxltx);
c8.setLayout(bxltx);
c9.setLayout(bxltx);
echedatelbl = new Label("Date d'échéance");
echedatelbl.setUIID("FicheLibelle");
echedatetxt = new TextField();
echedatetxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(echedatetxt, vkNombre);
montantlbl = new Label("Montant(Ar)");
montantlbl.setUIID("FicheLibelle");
montanttxt = new TextField();
montanttxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(montanttxt, vkNombre);
eche_payelbl = new Label("Payé (Ar)");
eche_payelbl.setUIID("FicheLibelle");
eche_payetxt = new TextField();
eche_payetxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(eche_payetxt, vkNombre);
eche_retardlbl = new Label("Retard");
eche_retardlbl.setUIID("FicheLibelle");
eche_retardtxt = new TextField();
eche_retardtxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(eche_retardtxt, vkNombre);
ecehe_nbretardlbl = new Label("Nombre de retard");
ecehe_nbretardlbl.setUIID("FicheLibelle");
ecehe_nbretardtxt = new TextField();
ecehe_nbretardtxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(ecehe_nbretardtxt, vkNombre);
eche_crdlbl = new Label("Crédit (Ar)");
eche_crdlbl.setUIID("FicheLibelle");
eche_crdtxt = new TextField();
eche_crdtxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(eche_crdtxt, vkNombre);
eche_rembourselbl = new Label("Remboursé (Ar)");
eche_rembourselbl.setUIID("FicheLibelle");
eche_remboursetxt = new TextField();
eche_remboursetxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(eche_remboursetxt, vkNombre);
eche_interetlbl = new Label("Intérêt (Ar)");
eche_interetlbl.setUIID("FicheLibelle");
eche_interettxt = new TextField();
eche_interettxt.addDataChangeListener(this);
VirtualKeyboard.bindVirtualKeyboard(eche_interettxt, vkNombre);
flagPayelbl = new Label("Payé");
flagPayelbl.setUIID("FicheLibelle");
flagPayetxt = new ListBox(new String[]{"oui","non","aaaaaa","bbbb"},echedatetxt.getPreferredH(),getPreferredW(),getPreferredH(),eche_interettxt.getSelectedStyle().getMargin(Component.TOP),eche_interettxt.getSelectedStyle().getMargin(Component.BOTTOM));
c10.getStyle().setPadding(Component.LEFT, 0);
c10.getStyle().setPadding(Component.RIGHT, 0);
reset = new Button("Rétablir les données");
reset.addActionListener(this);
reset.getUnselectedStyle().setMargin(0, 0, 0, 0);
reset.getSelectedStyle().setMargin(0, 0, 0, 0);
reset.setAlignment(Label.CENTER);
reset.setUIID("btnDetailCreditFieldset");
c10.addComponent(reset);
modifierBtn = new Button("Valider");
modifierBtn.addActionListener(this);
modifierBtn.getUnselectedStyle().setMargin(0, 0, 0, 0);
modifierBtn.getSelectedStyle().setMargin(0, 0, 0, 0);
modifierBtn.setAlignment(Label.CENTER);
modifierBtn.setUIID("btnDetailCreditFieldset");
c1.addComponent(echedatelbl);
c1.addComponent(echedatetxt);
c2.addComponent(montantlbl);
c2.addComponent(montanttxt);
c3.addComponent(eche_payelbl);
c3.addComponent(eche_payetxt);
c4.addComponent(eche_retardlbl);
c4.addComponent(eche_retardtxt);
c5.addComponent(ecehe_nbretardlbl);
c5.addComponent(ecehe_nbretardtxt);
c6.addComponent(eche_crdlbl);
c6.addComponent(eche_crdtxt);
c7.addComponent(eche_rembourselbl);
c7.addComponent(eche_remboursetxt);
c8.addComponent(eche_interetlbl);
c8.addComponent(eche_interettxt);
c9.addComponent(flagPayelbl);
c9.addComponent(flagPayetxt);
cz1.addComponent(t1);
cz2.addComponent(t2);
cz3.addComponent(t3);
cz4.addComponent(t4);
cz5.addComponent(t5);
int[] labelW = new int[]{echedatelbl.getPreferredW(), montantlbl.getPreferredW(), eche_payelbl.getPreferredW(), eche_retardlbl.getPreferredW(), ecehe_nbretardlbl.getPreferredW(), eche_crdlbl.getPreferredW(), eche_rembourselbl.getPreferredW(), eche_interetlbl.getPreferredW(),flagPayelbl.getPreferredW()};
int largeW = Comparator.max(labelW);
echedatelbl.setPreferredW(largeW);
montantlbl.setPreferredW(largeW);
eche_payelbl.setPreferredW(largeW);
eche_retardlbl.setPreferredW(largeW);
ecehe_nbretardlbl.setPreferredW(largeW);
eche_crdlbl.setPreferredW(largeW);
eche_rembourselbl.setPreferredW(largeW);
eche_interetlbl.setPreferredW(largeW);
flagPayelbl.setPreferredW(largeW+2);
c10.addComponent(modifierBtn);
c.addComponent(c1);
c.addComponent(c2);
c.addComponent(c3);
c.addComponent(c4);
c.addComponent(c5);
c.addComponent(c6);
c.addComponent(c7);
c.addComponent(c8);
c.addComponent(cz1);
c.addComponent(cz2);
c.addComponent(cz3);
c.addComponent(cz4);
c.addComponent(cz5);
c.addComponent(c9);
c.addComponent(c10);
cntnr.addComponent(c);
this.setScrollableY(true);
this.addComponent(cntnr);
echedatetxt.setText(listecheance.elementAt(0).toString());
montanttxt.setText(listecheance.elementAt(1).toString());
eche_payetxt.setText(listecheance.elementAt(6).toString());
eche_retardtxt.setText(listecheance.elementAt(7).toString());
ecehe_nbretardtxt.setText(listecheance.elementAt(8).toString());
eche_crdtxt.setText(listecheance.elementAt(9).toString());
eche_remboursetxt.setText(listecheance.elementAt(10).toString());
eche_interettxt.setText(listecheance.elementAt(11).toString());
textFieldStatus = "NORMAL";
if (String.valueOf(listecheance.elementAt(2)).toLowerCase().startsWith("o"))
flagPayetxt.setSelectedIndex(0);
else if (String.valueOf(listecheance.elementAt(2)).toLowerCase().startsWith("n"))
flagPayetxt.setSelectedIndex(1);
listeMenu = new Command("Liste");
listeClientCmd = new Command("Clients");
listeCreditCmd = new Command("Crédits");
ppalCmd = new Command("Menu principal");
ficheMenu = new Command("Fiche");
backCmd = new Command("Retour");
annulerCmd = new Command("Annuler");
isMenuShown = false;
this.addCommand(listeMenu);
this.addCommand(ficheMenu);
this.addCommandListener(this);
} // end of constructor
...
}
You see that I have considered the two cases if there is space or not below the ListBox in the pointerPressed method of the ListBox class.
When I don't write in the calling Form's code the addComponent for the containers cz1 through cz5 then the Dialog is shown very well below the ListBox component.
So why doesn't the Dialog show when there is no more space at the bottom ?
You invoke the dialog show method with sizes that don't leave any space for the dialog. You need to check that height - top - bottom > dialogPreferreHeight and the same should apply for width.
See the combo box popup code where we conditionally popup the dialog upwards if there is no room bellow.

Resources