Hola:
Pongamos que estoy programando un juego para Android.
En la interfaz gráfica, hay disponibles dos botones para [Comenzar] y [Finalizar] la partida (con los id btnComenzar y btnFinalizar, respectivamente)
También, hay un menú con las mismas funciones, es decir, un MenuItem para [Comenzar] y otro para [Finalizar] (). El menú está construido dentro de un menu.xml de la carpeta [menu] dentro de la carpeta [res] del árbol del proyecto.
Un archivo menu.xml como el que sigue:
Código:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/mnuComenzar"
android:title="Comenzar"
android:icon="@drawable/ic_menu_inicio">
</item>
<item android:id="@+id/mnuFinalizar"
android:title="Finalizar"
android:icon="@drawable/ic_menu_fin"
android:enabled="false">
</item>
</menu>
Lo que tengo configurado por la parte de código del archivo de la actividad del proyecto y funcionando correctamente es que cuando se pulsa el botón de Comenzar, entre las acciones del onClick, aparte de iniciar el juego, está la de poner .setEnabled(false) el botón pulsado y el otro a .setEnabled(true).
Es decir, si pulso el de Comenzar, se deshabilita éste y se habilita el de Finalizar, y si después pulso el de Finalizar se deshabilitaría éste y se habilitaría el de Comenzar.
Bueno, pues lo que quiero es llegar a aplicar lo mismo y al mismo tiempo para los MenuItems antes mencionados.
Es decir, si pulso en el botón de Comenzar que se deshabilite dicho botón y se deshabilite también el MenuItem de Comenzar, y se habilite el botón de Finalizar y el MenuItem de Finalizar. Y viceversa.
Bien, según como tengo montado la clase Actividad tiene este código como partes importantes:
Código:
import android.app.Activity;
//...
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
//...
import android.widget.Toast;
public class AndroidJuegoActivity extends Activity implements OnClickListener {
private Button elBtnComenzar, elBtnFinalizar;
private MenuItem elMnuComenzar, elMnuFinalizar;
// ... y demás variables que ahora no vienen al caso
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
asignacionControles();
}
private void asignacionControles() {
// Asignando Atributos a su correspondiente Control del Interfaz
elBtnComenzar = (Button)findViewById(R.id.btnComenzar);
elBtnFinalizar = (Button)findViewById(R.id.btnFinalizar);
// ...
// Referentes al menú
elMnuComenzar = (MenuItem)findViewById(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)findViewById(R.id.mnuFinalizar);
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater elInflater = getMenuInflater();
elInflater.inflate(R.menu.menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem itemElegido) {
boolean resultado = true;
switch (itemElegido.getItemId()) {
case R.id.mnuComenzar:
Toast.makeText(this, "Nueva partida iniciada", Toast.LENGTH_SHORT).show();
// llamada al método de ComenzarJuego();
break;
case R.id.mnuFinalizar:
Toast.makeText(this, "La partida se ha cancelado", Toast.LENGTH_SHORT).show();
// llamada al método de Finalizar();
break;
default:
break;
}
return resultado;
} // onOptionsItemSelected
public void onClick(View elControl) {
boolean acertado = false;
switch (elControl.getId()) {
case R.id.btnComenzar:
// ... diversas acciones
m_puntos.setText(String.valueOf(juego.Ruleta()));
// Habilitando-Deshabilitando BOTONES
elBtnComenzar.setEnabled(false);
elBtnFinalizar.setEnabled(true);
// Habilitando-Deshabilitando partes del MENÚ
elMnuComenzar.setEnabled(false);
elMnuFinalizar.setEnabled(true);
break;
case R.id.btnFinalizar:
// ... diversas acciones
m_puntos.setText(String.valueOf(juego.Ruleta()));
// Habilitando-Deshabilitando BOTONES
elBtnComenzar.setEnabled(true);
elBtnFinalizar.setEnabled(false);
// Habilitando-Deshabilitando partes del MENÚ
elMnuComenzar.setEnabled(true);
elMnuFinalizar.setEnabled(false);
break;
}
} // onClick
}
El código del main.xml es:
Código:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/sty_Layout" >
<Button
android:id="@+id/btnComenzar"
style="@style/sty_btnComenzar"
android:text="@string/str_btnComenzar" />
<Button
android:id="@+id/btnFinalizar"
style="@style/sty_btnFinalizar"
android:text="@string/str_btnFinalizar" />
<!-- y otros elementos que ahora no vienen al caso -->
</LinearLayout>
Si lo dejo así, al ejecutarlo por el emulador y al pulsar en el botón de Comenzar me sale la ventana de advertencia de que se ha producido un error de ejecución y me fuerza a cerrar el programa.
Haciendo un DEBUG, la ejecución se queda parada en la línea con se deberían asignar los controles de MenuItem, no llegando a asignarlos y quedando por tanto los correspondientes atributos a null.
Esto es exactamente en las siguientes líneas situadas dentro de asignacionControles() :
Código:
elMnuComenzar = (MenuItem)findViewById(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)findViewById(R.id.mnuFinalizar);
Ya al llegar a la primera elMnuComenzar no llega a capturar el control al que se debe referir y se queda a null.
Lo que produce que cuando se quiere habilitar o deshabilitar el elemento del menú adecuado a través de
Código:
elMnuComenzar.setEnabled(false);
// o
elMnuComenzar.setEnabled(true);
se produzca el error de ejecución pues el elMnuComenzar no llega a ser asignado al control que le corresponde sino que se queda a null.
¿Cómo debería entonces hacer las cosas? ¿Se puede asignar de otra manera los elementos del menú?
¿O hay que plantearlo todo de otra manera?
Encontré otra forma de asignar los elementos del menú a los respectivos atributos
Código:
// en vez de así
elMnuComenzar = (MenuItem)findViewById(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)findViewById(R.id.mnuFinalizar);
// de esta otra forma
elMnuComenzar = (MenuItem)menu.findItem(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)menu.findItem(R.id.mnuFinalizar);
Lo que pasa es que con esta forma, el programa no sabe que es la referencia menu marcada en negrita en las líneas anteriores. Entonces, tendría que crear otro atributo private al inicio de la clase tal que
private Menu miMnu;
Y luego añadir otra línea en el bloque se asignaciones para que fuera asignado el menu.xml al atributo miMnu. Y entonces terminaría siendo
Código:
elMnuComenzar = (MenuItem)miMnu.findItem(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)miMnu.findItem(R.id.mnuFinalizar);
Lo que no sé es como sería esa última asignación entre miMnu y el menu.xml
Comentar que si meto las líneas de
elMnuComenzar = (MenuItem)
menu.findItem(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)
menu.findItem(R.id.mnuFinalizar);
dentro del onCreateOptionsMenu todo funciona bien siempre y cuando, antes de pulsar el botón haya abierto antes el menú, si no dará error.
Por tanto, no llega a ser del todo efectiva esta opción
En el onCreateOptionsMenu, quedaría así:
Código:
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater elInflater = getMenuInflater();
elInflater.inflate(R.menu.menu, menu);
// Aquí funciona, pero dará error si no
// se abre el menú antes de pulsar el botón
elMnuComenzar = (MenuItem)menu.findItem(R.id.mnuComenzar);
elMnuFinalizar = (MenuItem)menu.findItem(R.id.mnuFinalizar);
return true;
}
Al ponerlo aquí, el elemento
menu se refiere al que llega como atributo del onCreateOptionsMenu.
Pues nada, espero se haya entendido la consulta. Espero gustoso vuestras respuestas. Gracias.