Foros del Web » Programando para Internet » Android »

Cómo habilitar-deshabilitar un MenuItem desde el onCLick de un botón

Estas en el tema de Cómo habilitar-deshabilitar un MenuItem desde el onCLick de un botón en el foro de Android en Foros del Web. 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 ...
  #1 (permalink)  
Antiguo 08/12/2011, 17:47
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años, 7 meses
Puntos: 3
Cómo habilitar-deshabilitar un MenuItem desde el onCLick de un botón

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.
__________________
Saludos,

zacktagnan.
=================================================
  #2 (permalink)  
Antiguo 17/12/2011, 17:59
Avatar de zacktagnan  
Fecha de Ingreso: abril-2005
Mensajes: 501
Antigüedad: 19 años, 7 meses
Puntos: 3
Respuesta: Cómo habilitar-deshabilitar un MenuItem desde el onCLick de un botón

Resuelto usando el método onPrepareOptionsMenu(Menu menu)

Dentro de este método, cuando se cumpla una condición, se reconstruirá el menú de una manera o de otra, habilando o deshabilitando uno u otro item del menú (o si se quisiera, cambiar también su texto o su icono o lo que sea)

Código:
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
    	menu.clear();

	if(!elBtnComenzar.isEnabled()) {
		menu.add(0, elMnuComenzarItem, 0, R.string.str_mnuComenzar).setIcon(R.drawable.ic_menu_inicio).setEnabled(false);
		menu.add(0, elMnuFinalizarItem, 0, R.string.str_mnuFinalizar).setIcon(R.drawable.ic_menu_fin).setEnabled(true);

    	} else {
		menu.add(0, elMnuComenzarItem, 0, R.string.str_mnuComenzar).setIcon(R.drawable.ic_menu_inicio).setEnabled(true);
		menu.add(0, elMnuFinalizarItem, 0, R.string.str_mnuFinalizar).setIcon(R.drawable.ic_menu_fin).setEnabled(false);

    	}
	menu.add(0, elMnuSalirItem, 0, R.string.str_mnuSalir).setIcon(R.drawable.ic_menu_fin);

    	return super.onPrepareOptionsMenu(menu);
    }
__________________
Saludos,

zacktagnan.
=================================================

Etiquetas: emulador, onclick, proyecto, todo, apps
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 04:07.