user1460211
user1460211

Reputation: 39

Cannot remove a view from layout

I'm creating a small app in which you can add or delete a table row by button click. Whenever I click the "add line" button, the button adds a table row to the layout and does what it's supposed to do. However, the "delete line" doesn't remove the the newly added table row, but it does decrement (int count) like it's supposed to. I've worked and searched on it for about 4 to 5 hours now and I'm having no luck. Here's the code:

int count = 0;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);       
    setContentView(R.layout.activity_main);
    Button buttonAdd = (Button) findViewById(R.id.button1);
    Button buttonDel = (Button) findViewById(R.id.button2);
    buttonAdd.setOnClickListener(this);
    buttonDel.setOnClickListener(this);
}



public void onClick(View v) {
    TableLayout tableLayout1;
    EditText editText1;
    EditText editText2;
    TableRow tempRow;
    EditText tempText1;
    EditText tempText2;
    TableRow tableRow1;

    tableLayout1 = (TableLayout) findViewById(R.id.tableLayout1);
    editText1 = (EditText) findViewById(R.id.editText1);
    editText2 = (EditText) findViewById(R.id.editText2);
    tempRow = new TableRow(MainActivity.this);
    tempText1 = new EditText(MainActivity.this);
    tempText2 = new EditText(MainActivity.this);
    tempText1.setInputType(InputType.TYPE_CLASS_TEXT);
    tempText2.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
    tableRow1 = (TableRow) findViewById(R.id.tableRow1);

    tempRow.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
    tempText1.setLayoutParams(editText1.getLayoutParams());
    tempText2.setLayoutParams(editText2.getLayoutParams());
    switch(v.getId()){
    case R.id.button1:
        if(count != 9){
            count++;

            tempRow.addView(tempText1);
            tempRow.addView(tempText2);
            tableLayout1.addView(tempRow);
        } else {
            final AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create(); //Read Update
            alertDialog.setTitle("Error");
            alertDialog.setMessage("You can only have 10 rows!");

            alertDialog.setButton("Ok", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int which) {
                  alertDialog.dismiss();
               }
            });

            alertDialog.show();
        }
        break;
    case R.id.button2:
        if(count != 0){
            count--;
            tempRow.removeView(tempText1);
            tempRow.removeView(tempText2);
            tableLayout1.removeView(tempRow);
            //tableLayout1.invalidate();

        } else {
            final AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create(); //Read Update
            alertDialog.setTitle("Error");
            alertDialog.setMessage("You must have at least one row!");

            alertDialog.setButton("Ok", new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int which) {
                  alertDialog.dismiss();
               }
            });

            alertDialog.show();
        }
        break;
        default:
            //Do something;
    }

}    

.

10-30 21:22:23.379: E/AndroidRuntime(3970): FATAL EXCEPTION: main
10-30 21:22:23.379: E/AndroidRuntime(3970): java.lang.NullPointerException
10-30 21:22:23.379: E/AndroidRuntime(3970): at com.android.hopegpacalc.MainActivity.onClick(MainActivity.java:57)
10-30 21:22:23.379: E/AndroidRuntime(3970): at android.view.View.performClick(View.java:3511)
10-30 21:22:23.379: E/AndroidRuntime(3970): at android.view.View$PerformClick.run(View.java:14105)
10-30 21:22:23.379: E/AndroidRuntime(3970): at android.os.Handler.handleCallback(Handler.java:605)
10-30 21:22:23.379: E/AndroidRuntime(3970): at android.os.Handler.dispatchMessage(Handler.java:92)
10-30 21:22:23.379: E/AndroidRuntime(3970): at android.os.Looper.loop(Looper.java:137)
10-30 21:22:23.379: E/AndroidRuntime(3970): at android.app.ActivityThread.main(ActivityThread.java:4424)
10-30 21:22:23.379: E/AndroidRuntime(3970): at java.lang.reflect.Method.invokeNative(Native Method)
10-30 21:22:23.379: E/AndroidRuntime(3970): at java.lang.reflect.Method.invoke(Method.java:511)
10-30 21:22:23.379: E/AndroidRuntime(3970): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
10-30 21:22:23.379: E/AndroidRuntime(3970): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
10-30 21:22:23.379: E/AndroidRuntime(3970): at dalvik.system.NativeStart.main(Native Method)

Upvotes: 1

Views: 502

Answers (3)

Sam
Sam

Reputation: 86948

It is a matter of organization, try this:

public void onClick(View v) {
    // These should be class variables, like count, you don't need to re-find it on every click
    TableLayout tableLayout1 = (TableLayout) findViewById(R.id.tableLayout1);
    EditText editText1 = (EditText) findViewById(R.id.editText1);
    EditText editText2 = (EditText) findViewById(R.id.editText2);

    switch(v.getId()){
    case R.id.button1:
        if(count != 9){
            count++;

            // Create the row only when the add button is clicked
            TableRow tempRow = new TableRow(MainActivity.this);
            EditText tempText1 = new EditText(MainActivity.this);
            EditText tempText2 = new EditText(MainActivity.this);
            tempText1.setInputType(InputType.TYPE_CLASS_TEXT);
            tempText2.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);

            tempRow.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
            tempText1.setLayoutParams(editText1.getLayoutParams());
            tempText2.setLayoutParams(editText2.getLayoutParams());

            tempRow.addView(tempText1);
            tempRow.addView(tempText2);
            tableLayout1.addView(tempRow);
        } else {
            // Consider using Activity's showDialog() method, to reuse this "error" dialog rather than create a new one every time
            final AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create(); //Read Update
            alertDialog.setTitle("Error");
            alertDialog.setMessage("You can only have 10 rows!");

            alertDialog.setButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    alertDialog.dismiss();
                }
            });

            alertDialog.show();
        }
        break;
    case R.id.button2:
        if(count != 0){
            // Remove the last row at count or use "tableLayout1.getChildCount() - 1"
            tableLayout1.removeView(tableLayout1.getChildAt(count));
            count--;
        } else {
            // Consider reusing the other "error" Dialog and simply changing the message
            final AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create(); //Read Update
            alertDialog.setTitle("Error");
            alertDialog.setMessage("You must have at least one row!");

            alertDialog.setButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    alertDialog.dismiss();
                }
            });

            alertDialog.show();
        }
        break;
    default:
        //Do something;
    }
}

Upvotes: 2

GraphicsMuncher
GraphicsMuncher

Reputation: 4641

Your removal code is "removing" temporary views (eg tempText1) that aren't actually in the table - they were made on the fly inside the onClick method. Instead of instantiating all of those objects as soon as you get into onClick, do so in the body of each switch statement case. For the adding button, just copy and paste. For the removal one, set the objects equal to the row you want to remove.

It doesn't seem like you have a way of selecting which row to remove, but assuming you do this somewhere else you can use TableLayout.removeViewAt(int index) to select which one. There's also TableLayout.removeView(View view) if you have the view itself and not the index.

Upvotes: 0

Khantahr
Khantahr

Reputation: 8518

Your code makes a new TableRow every time onClick is executed. You should only do this when you want to add a row. When you want to delete one, you'll have to find the row to delete in the existing view by using findViewById( id ), then run removeView on that object.

case R.id.button2:
    if ( count != 0 ) {
        count--;
        tempRow = (TableRow)findViewById( idoftablerowtodelete );
        tableLayout1.removeView( tempRow );

This does mean that you'll have to set an id on each table row when you create it, using setId, and keep track of it.

Upvotes: 0

Related Questions