Delphi - Número de submenus

 
Vista:

Número de submenus

Publicado por Mariposa Mental (8 intervenciones) el 26/09/2007 16:36:06
Hola a todos,
estoy intentando recorrerme todos los items de un mainmenu, incluidos los submenús de segundo, tercer... nivel.

Para el primer nivel no tengo ningún problema, se pueden recorrer con MainMenu1.Items.Count

Pero para el segundo nivel, aunque si que me sale como tal la propiedad al compilar me da error, intento acceder con MainMenu1.Items[i].Items.Count

El error que me da es que espera un '[' como para que ponga el índice.
Si no sé cuantos submenús tiene no puedo recorrerlo correctamente ya que no sé cuando me puede dar error de 'List Index out of bounds"

Si alguien me pudiera dar la forma de recorrérmelo me solucionaría muchos problemas

Muchas gracias!
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 65
Oro
Ha mantenido su posición en Delphi (en relación al último mes)
Gráfica de Delphi

RE:Número de submenus

Publicado por E.T. (1244 intervenciones) el 26/09/2007 18:26:04
He logrado recorrer todos los items de un menú de la siguiente forma, muy poco ortodoxa pero funciona

declaramos el siguiente procedimiento dentro de la unidad

procedure TForm1.recorrer(V_Menu: TMenuItem);
var i:integer;
begin
ShowMessage(V_Menu.Name+' '+V_Menu.Caption);
try
if V_Menu.Items[0]<>nil then
for i:=0 to High(V_Menu.items[0].Count) do begin
recorrer(V_Menu.Items[i]);
end;
Except

end;
end;

Luego la llamamos desde un botón

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
for i:=0 to MainMenu1.Items.Count-1 do
recorrer(MainMenu1.Items[i]);
end;

funciona de la siguiente manera, recorre uno a uno los items, si un item tiene una rama entra en ella, al terminarla regresa donde se desprendio la rama para continuar (si es uqe hay mas items), no respeta niveles, si hay una rama va a entrar antes de continuar con los demas items.

Hay que correr el programa fuera de delphi para evitar las Excepciones, que van a ocurrir siempre (estando dentro de delphi)
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Número de submenus

Publicado por Mariposa Mental (8 intervenciones) el 27/09/2007 08:14:14
Hola,
primero muchas gracias por contestar.
Yo también lo había hecho con un procedimiento recursivo para ver si así cogía el count, pero no hay manera, no entiendo como no está implementado. :S

No lo expliqué en el primer mensaje, cada una de las opciones de menú está asociada a una acción que se hace visible o invisible según los permisos que tenga el usuario que entra al programa.
Al hacerlo así es posible que se me queden submenús vacíos si no se tiene permiso para ninguna de las opciones de dentro, por eso tengo que recorrerme el menú para quitar los submenús vacíos.

Necesitaría encontrar una forma en la que no diera error porque tengo que ir devolviendo los visibles de cada una de las acciones (los recojo con or's) y hacer una serie de comprobaciones.

No conocía el uso de la función High, aunque en este caso, a mí me sale un número muy alto, no entiendo muy bien como para el bucle.

Muchas gracias, saludos
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Número de submenus

Publicado por Mariposa Mental (8 intervenciones) el 27/09/2007 08:25:49
El bucle para al dar error, está claro es que es demasiado temprano para pensar. :D

Gracias.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 65
Oro
Ha mantenido su posición en Delphi (en relación al último mes)
Gráfica de Delphi

RE:Número de submenus

Publicado por E.T. (1244 intervenciones) el 27/09/2007 20:23:58
Hola, le hice unas modificaciones espero te sirva:

procedure TForm1.recorrer(V_Menu: TMenuItem);
var i:integer;
flag:boolean;
begin
ShowMessage(V_Menu.Name+' '+V_Menu.Caption);
try
if V_Menu.Items[0]<>nil then begin
flag:=false;
for i:=0 to 100{High(V_Menu.items[0].count)} do begin
if V_Menu.Items[i].Visible then begin
recorrer(V_Menu.Items[i]);
flag:=true;
end;
end;
end;
Except
if flag then
ShowMessage('Fin de la rama')
else begin
ShowMessage('no hay submenú');
{si es un menú padre, es decir si tiene o puede tener hijos, hacer algo}
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
begin
for i:=0 to MainMenu1.Items.Count-1 do
recorrer(MainMenu1.Items[i]);
end;

Bien, dentro de la función, ahora hay una variable llamada flag, si dicha variable es true quiere decir que ya terminó la rama que se desprende del menú principal o de un submenú, si no es true, quiere decir que entró a un submenú y que este mismo submenú no tiene hijos, aqui es donde tienes que quitarlo en caso de que sea un submenú padre puesto que no tiene hijos si no es un padre simplemente te pasas de largo.

Si hay un submenú que sea padre y todos sus hijos quedan invisibles, te marcará que no tiene submenús, por lo tanto tienes que poner un "case" o un "if" donde si es padre lo quitas de ahi.

La función High, te devuelve el valor mas alto de un tipo de variable (yo lo usé mal aqui por que te devuelve el high de un entero que es el count, que es tipo integer) puedes poner un valor cualquiera que se mayor al número de submenús de una rama, si tienes una rama que tenga por decir 20 hijos (y es la que mas hijos tiene) en el for basta con poner 20, o el numero mas grande de hijos que tengas

Espero me haya hecho entender, si no escribe de nuevo
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Número de submenus

Publicado por Mariposa Mental (8 intervenciones) el 28/09/2007 10:40:36
Hola,
al final ya conseguí hacerlo con lo que me dijiste del high, de todas formas como da error en el primer índice que se pasa, va al except y continúa con la siguiente rama. Pero sí que es verdad que se puede poner un número fijo y será mejor.

Te pongo el código por si te interesa, la he hecho recursiva pero voy sumando los visibles de cada rama con 'or's' con lo que con que haya una opción visible, la rama ya es visible. Comienza siendo invisible.

function TFMain.QuitarSubmenu(OpcionMenu:TMenuItem):Boolean;
var
i : integer;
EsVisible : Boolean;
begin
EsVisible := False;

try
if OpcionMenu.Items[0]<>nil then
for i:=0 to High(OpcionMenu.Items[0].Count) do
begin
if (OpcionMenu.Items[i].Tag = 1) then
begin
(OpcionMenu.Items[i].Action as TAction).Visible := QuitarSubmenu(OpcionMenu.Items[i]);
EsVisible := EsVisible or (OpcionMenu.Items[i].Action as TAction).Visible;
end
else EsVisible := EsVisible or (OpcionMenu.Items[i].Action as TAction).Visible;
end;
except
end;
end;

Los submenús los tengo marcados con tag = 1. El código lo he modificado un poco aquí por no poner peculiaridades de mi programa que no importan nada en lo que estamos viendo de recorrerlo, creo que lo he dejado correcto.

Para cada submenú llamo recursivamente a la función, que me devuelve si es visible o no y además lo acumulo para el de nivel superior.
Y sino simplemente acumula el visible.

Espero haberme explicado bien. Gracias por tu ayuda.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar