Fórum Carregar menu Dinamico e jogar na tela conforme modelo #5755
18/05/2009
0
Sou iniciante em Delphi, porem tenho grande conhecimento em Firebird, ja com alguns anos de experiencia.
Eu assisti uma video aula no site da Devmedia, postada pelo Renato Matos, onde ele da um exemplo de carregar um Menu dinamico e tambêm estou seguindo uma video aula do mesmo autor com o assunto "Delphi OOP", dentro destes conceitos, eu gostatia de carregar um Menu de Forma dinamica (buscando de uma tabela no Firebird) baseado na empresa que o usuario irá logar.
Por exemplo:
Tenho 3 tipos de sistema, 1 basico, 1 intermediário e 1 completo, a diferença entre as 3 opções, é a quantida de menu disponivel no sistema.
Exemplificando:
Na opção 1 (Básico) o meu cliente terá apenas o Modúlo Contas a Receber que este contem o cadastro de Clientes, Lançamentos das parcelas e o Modulo Vendas que contem a Tela de Vendas e Cadastros de Produtos.
Na opção 2 (Intermediário) terá alem dos modulos contidos na opção 1, mais os modulos do Contas a Pagar com suas opções, o Modulo de Bancos, com suas opções e assim por diante na opção 3.
O tipo da opção do sistema contratado esta informado na tabela de Empresas no firebird.
Fiz um exemplo simbolico da Tela Inicial e abaixo a tela do Menu conforme eu gostaria de disponibilizar ao cliente.
No exemplo abaixo eu usei o ListView, não sei se é esta a melhor forma, mas pelo menos a disponização é importante para o produto que estou disponibilizando ao meu cliente.
Abaixo a tela do Menu:
Com esta configuração, ficará facil o acesso as opções, pois ele irá escolher o Modulo que se Encontra a Esquerda (Vendas, Caixa, etc) e do lado direito as opções do modulo (Cadastros, Relatórios, Movimentações, etc) que ele ira selecionar e escolher a opção que irá se abrir.
Sendo assim, ele irá escolher o modulo do lado esquerdo e do lado direito, ele irá mostrar a opção disponivel relacionada ao modulo.
Estes dados (Modulos e opções) eu gostaria de carregar conforme a opção informada no cadastro de empresa (tabela firebird), conforme o usuário logar e selecionar a empresa, ele irá trazer os modulos do menu e as opções do modulo.
Espero não ter abusado do meu primeiro chamado :D
Abraços,
Rogério.
Obs: Citei o listview, mas não precisa ser o mesmo, o importante para mim, é a flexibilidade do menu, ja que todas as opções estarão em apenas um banco de dados, disponibilizarei a opção conforme o cliente contratar (Basico, Intermediario e Completo) e a vizualização do mesmo para facilitar o manuseio do cliente, ja que eles reclamam muito dos MainMenus tradicionais.
Irei utilizar o Delphi 2009 e o Firebird 2.1.
Rogério Nascimento
Curtir tópico
+ 0Posts
19/05/2009
Rodrigo Mourão
Bem, não sei se você já assistiu alguma de minhas videos aulas. Eu sou bem prático, mas apesar disso não gosto de sair do padrão.
No seu caso temos duas opções: Ficar aqui durante dias desenvolvendo uma rotina que faça Exatamente o que você quer e com ListView. Digo dias pois a parte de montar os items do ListView e a parte mais simples, o mais complicado e linkar dinamicamente os eventos. O que também não é nada impossível de ser feito.
A segunda opção, e aí entra a praticidade, é criar manualmente todos os itens de menu conforme você quer na tela. E depois de criados apenas criamos uma rotina para exibir aqueles que o seu cliente tem acesso. Simples, prático, fácil e objetivo. O que acha ?
Isso irá lhe atender perfeitamente. Se estiver de acordo sinalize para que possamos dar início.
Abs!!!!!
P.S.: Gostei a ideia do ListView para trabalhar como menu. :-)
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
19/05/2009
Rogério Nascimento
Rapaz, estou acompanhando a sua video aula sobre Delphi 2007 e estou ansioso para ver o final. A sua proposta didatica e conceituosa sobre o assunto é muito boa.
Podemos fazer da forma que vc sugeriu, vindo de você a sugestão, ta feito.
Vamos lá, pode fazer da forma que você achou melhor.
Gostei + 0
19/05/2009
Rodrigo Mourão
Começo a trabalhar nisto hoje mesmo. Em breve posto a solução.
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
19/05/2009
Rodrigo Mourão
Vá no seu Form Principal e crie a seguinte procedure: procedure CarregaMenu(Nivel: Byte);
A implementação deste metodo fica assim:
procedure TFrmPrincipal.CarregaMenu(Nivel: Byte);
var
i: Integer;
J: Integer;
begin
for I := 0 to Pred(ComponentCount) do
if Components[I] is TListView then
begin
J := Pred(TListView(Components[I]).Items.Count);
while J >= 0 do
begin
if TListView(Components[I]).Items[J].StateIndex > Nivel then
begin
TListView(Components[I]).Items.Delete(J);
end;
Dec(J);
end;
end;
end;
O que faço ai na verdade é o seguinte. Eu varro o form e procuro por componentes TListView, pois pode haver mais de um. Quando localizo um TListView então percorro todos seus items e comparo a propriedade StateIndex com o Nivel passado, ou seja, cada item que você criar nos ListView você terá que alterar a propriedade StateIndex e colocar ali o nivel necessario para ele ser mostrado. Exemplo: 1, 2, 3, 4 Etc.
Assim quando você passar CarregaMenu(2) ele vai mostrar so os Items com StateIndex 1 e 2. No link abaixo te envio um exemplo feito em Delphi. Claro que o nivel voce traz do banco de dados.
http://video.devmedia.com.br/RodrigoCarreiro/Consultoria/MenuDinamico.zip
Abs.
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
20/05/2009
Rodrigo Mourão
Há mais alguma dúvida referente a este chamado?
Estamos aguardando para podermos encerrá-lo.
Abs.
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
20/05/2009
Rogério Nascimento
Vejamos pela imagem anexada, temos dois Listview, o da Esquerda é o Menu na qual eu irei carregar pela procedure, eu preciso que vc me ajude a chamar e passar o resultado da procedure para o listView da Esquerda.
Eu irei chamar a procedure que carrega os Menus e as Opçoes do Menu, apos o usuario logar no sistema e em seguida escolher a empresa que vai conectar, pois o mesmo pode ter mais de uma empresa no banco.
Abaixo da imagem, eu mandei 3 tabelas e 1 procedure exemplificando como seria.
Fiz um pequeno exemplo de como seria as tabelas:
CREATE TABLE EMPRESA (
CODIGO INTEGER NOT NULL,
RAZAOSOCIAL VARCHAR(60),
PACOTESISTEMA INTEGER DEFAULT 0
);
/* Fields descriptions */
COMMENT ON COLUMN EMPRESA.PACOTESISTEMA IS
'1 = versao basica
2 = versao intermediaria
3 = versao completa';
INSERT INTO EMPRESA (CODIGO, RAZAOSOCIAL, PACOTESISTEMA) VALUES (1, 'BRUNI QUIMICA LTDA', 1);
INSERT INTO EMPRESA (CODIGO, RAZAOSOCIAL, PACOTESISTEMA) VALUES (20, 'BRUNI QUIMICA LTDA MATRIZ', 2);
INSERT INTO EMPRESA (CODIGO, RAZAOSOCIAL, PACOTESISTEMA) VALUES (50, 'PEQUIMIK SOLVENTES', 3);
COMMIT WORK;
=====================================================================
CREATE TABLE MENU (
MENU_ID INTEGER NOT NULL,
MENUOPCAO VARCHAR(20) NOT NULL,
IMAGE INTEGER DEFAULT 0
);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (1, 'Contas a Receber', 0);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (2, 'Contas a Pagar', 1);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (3, 'Vendas', 2);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (4, 'PCP', 3);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (5, 'Compras', 4);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (6, 'Cheques', 5);
INSERT INTO MENU (MENU_ID, MENUOPCAO, IMAGE) VALUES (7, 'Faturamento', 6);
COMMIT WORK;
=====================================================================
CREATE TABLE MENU_ITENS (
MENU_ID INTEGER NOT NULL,
DESCRICAOITENSMENU VARCHAR(30) NOT NULL,
ABAOPCAO INTEGER NOT NULL,
IMAGEM INTEGER DEFAULT 0 ,
OPCAOCONTRATADA INTEGER DEFAULT 0
);
COMMENT ON COLUMN MENU_ITENS.ABAOPCAO IS
' SE PERTENCE A CADASTROS, RELATORIOS, MOVIMENTACOES, ETC
1 = CADASTROS
2 = MOVIMENTACOES
3 = RELATORIOS';
CREATE PROCEDURE SP_MENUS (
cod_empresa integer)
returns (
menu varchar(30),
menuindex integer,
item_menu varchar(30),
menu_imagem integer,
item_menu_imagem integer,
abacontrole integer)
as
begin
for select menu.menu_id, menu.menuopcao, menu.image,
menu_itens.abaopcao, menu_itens.descricaoitensmenu, menu_itens.imagem
from menu
left join menu_itens on menu.menu_id = menu_itens.menu_id
where menu_itens.opcaocontratada <= (select empresa.pacotesistema from Empresa Where Empresa.codigo = :cod_empresa)
into menuindex, menu, menu_imagem,
abacontrole, item_menu, item_menu_imagem do
suspend;
end
Gostei + 0
21/05/2009
Rodrigo Mourão
Mas onde está essa imagem?
- No imageList dentro do Delphi.
Então se você quiser alterar o nome de um menu altera no banco, mas trocar o ícone tem que abrir a aplicação e trocar a imagem no ImageList. Com isso você tem parte da rotina no banco e parte na aplicação. Isso é extremamente ruim.
Você chegou a rodar o código que lhe falei? Pois você pode ter 1,2,3 quantas listview quiser na aplicação com os itens que ele vai ocultar ou não.
Faça o seguinte em cada item que de cada ListView que você tem ai configura a propriedade StateIndex com 1, 2 ou 3 de acordo com o PACOTESISTEMA da empresa. Ex. menu Contas a Pagar coloca state Index 3 isso fara com que ele so aparceça na 3;
Agora como isso vai funcionar? Simples. Ao se logra você vai no banco e pega o PACOTESISTEMA da empresa e passar para a rotina CarregaMenu(Nivel: Byte); E mais.
Essa listView lateral tambem pode ter seus itens ocultados. Basta configurar a propriedade StateIndex dos itens também.
Rógerio esta é a melhor solução pois montar o menu e tranquilo mas se for feito dinamicamente como vai "injetar" o Onclick.
Por isso acho mais vantajoso deixar todos os itens criados em Design Time, com os onClick's ja programados e apenas ocultar os itens que a empresa não tenha acesso !!
Se quiser manda a sua aplicacao com o banco que implemento a rotina pra voce ver !!!
Abs !!!
Gostei + 0
21/05/2009
Rogério Nascimento
Gostei + 0
24/05/2009
Rodrigo Mourão
Por falta de retonro encerramos o seu chamado. Caso ainda possua alguma dúvida sobre esse assunto, por favor, post a mesma que o consultor voltará a lhe atender e o chamado será reaberto.
Abs !!
Gostei + 0
12/06/2009
Rogério Nascimento
Esbarrei com um problema não previsto na rotina implementada e preciso de sua ajuda.
Conforme a rotina que vc me passou, esta acontecendo o seguinte:
////////// Rotina implementada //////////////
procedure TfrmPrincipal.CarregaMenu(Nivel: Byte);
var
i: Integer;
J: Integer;
begin
// Filtra as opções do ListView conforme o Modulo Relacionado (Rodrigo Carreiro / DevMedia);
for I := 0 to Pred(ComponentCount) do
if Components[I] is TListView then
begin
J := Pred(TListView(Components[I]).Items.Count);
while J >= 0 do
begin
if TListView(Components[I]).Items[J].StateIndex > Nivel then
begin
TListView(Components[I]).Items.Delete(J);
end;
Dec(J);
end;
end;
end;
O Menu, tem vários modulos a esquerda e do lado direito tem o listview que aparece as opções do modulo selecionado, conforme vc tinha me orientado, adicionei todos os itens no listview e depois conforme clico no modulo, ele apaga os itens diferentes do modulo selecionado, porem acontece o seguinte:
Entrei no modulo Contas a Receber, beleza, os itens que estão no listview, são relacionados a ele, qdo vou para outro modulo, Vendas por exemplo, ja não aparece mais as opções no listview, ja que qdo eu entrei no Contas a Receber, ele apagou o que foi diferente dele, qdo entrei no vendas, ele tbm apagou o que foi diferente dele, porem não carregou as opções relacionadas a ele, assim o listview fica vazio.
Pensei na seguinte situação, como uso Tabsheet, adicionar uma Tab que não ficará visivel ao usuário e nesta adiciono um listView, com todas as opções do sistema ja inseridas nele e conforme eu clicar no menu na tela inicial, ele capta as opçoes relacionadas ao menu pelo State Index (conforme sugerido por você) e adiciona no listview principal. Se esta for a forma mais facil, gostaria que vc me ajudasse a implementar isto, ou, sugerir algo para isto.
Abaixo a tela principal de como esta.
Abraços,
Rogério Nascimento.
Gostei + 0
15/06/2009
Rodrigo Mourão
Bem vamos lá, eu acredito que a melhor maneira de resolver o problema seja restaurar a condição inicial ao mudar o módulo. Por exemplo, quando vc entra no Contas a Pagar vc oculta alguns itens. Quando vc trocar de modulo faça um loop e coloque todos os itens visíveis. Assim volta ao estado original e ai vc poderá chamar a rotina para outro modulo.
Assim é mais simples de implementar.
Abs!!
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
15/06/2009
Rogério Nascimento
Como eu faço para restaurar as opções que foram deletadas?
Gostei + 0
17/06/2009
Rodrigo Mourão
Não me atentei ao detalhe que estavamos deletando o item. Mas deixar eu ver aqui. Se não tiver a opção visible no Item (E acho que não tem) então vamos tentar reconstruir o controle. Aqui no momento estou sem Delphi mas assim que chegar no cliente eu vou fazer os teste e te enviar.
Abs!!
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
17/06/2009
Rogério Nascimento
Você tem alguma sugestão para substituir-mos o listview por outro componente que seja mais facil a manutenção, mas que de a mesma aparencia, pois o meu foco é dar facilidade ao acesso ao menu, ficando bem visivel todas opções ao entrar no modulo, evitando o incoveniente de ficar navegando pelo menu até achar a outra opção.
Gostei + 0
17/06/2009
Rodrigo Mourão
Este disposição e esta ideia do ListView foi uma grande sacada você está de parabéns.
Eu fiquei enrolado durante o dia mas ja estou fazendo o teste com o repaint e o CreateWND acho que vai nos ajudar.
Peço que aguardo mais um pouco !!
Abs!!
Atenciosamente,
Rodrigo Carreiro Mourão
Borland Instructor Certified
Coordenador da Consultoria em Delphi
Gostei + 0
Clique aqui para fazer login e interagir na Comunidade :)