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:
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).<?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>
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:
Ya al llegar a la primera elMnuComenzar no llega a capturar el control al que se debe referir y se queda a null.elMnuComenzar = (MenuItem)findViewById(R.id.mnuComenzar); elMnuFinalizar = (MenuItem)findViewById(R.id.mnuFinalizar);
Lo que produce que cuando se quiere habilitar o deshabilitar el elemento del menú adecuado a través de
Código:
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.elMnuComenzar.setEnabled(false); // o elMnuComenzar.setEnabled(true);
¿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:
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// 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);
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:
Lo que no sé es como sería esa última asignación entre miMnu y el menu.xmlelMnuComenzar = (MenuItem)miMnu.findItem(R.id.mnuComenzar); elMnuFinalizar = (MenuItem)miMnu.findItem(R.id.mnuFinalizar);
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:
Al ponerlo aquí, el elemento menu se refiere al que llega como atributo del onCreateOptionsMenu.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; }
Pues nada, espero se haya entendido la consulta. Espero gustoso vuestras respuestas. Gracias.