View Full Version : Aplicação em C# com event handling
candycane 18-05-2008, 21:45 Boa noite comunidade! :)
Preciso desenvolver uma aplicação em que crie x números de botões consoantes o numero de registo que tenha na base de dados. Ate aqui tudo bem, mas a minha duvida é:
como eu faço para que ao clicar no botão x vá ter as propriedades desse registo em questão? :(
A aplicação é para um café, em que pretendo ter um botão para cada mesa da sala, e ao clicar no botão da mesa x me diga os pedidos que fizeram dessa mesa.
Acho que será necessário event handling, não?
Qualquer ajuda é muito bem vinda :)
Ш¡zard·σf·Шαr 19-05-2008, 00:05 Para adicionar um event handler para cada botão, basta fazer isto:
botao[x].Click += new System.EventHandler(this.CliqueDeBotao);Isto faz com que a subrotina CliqueDeBotao seja o event handler do evento Click do botão botao[x]. Claro que a sub tem que ter a mesma assinatura (mesmos parâmetros) que o delegate do evento correspondente.
andrepadez 19-05-2008, 10:04 Boas. Eu deparei-me com esse problema há uns dias, e consegui resolvê-lo com algum esforço.
1º - tens de decidir o que te dá mais jeito - ter um eventhandler para cada botão, o que pode tornar o código demasiado extenso e redundante ou ter um eventhandler que dependendo do botão clickado, receba esses parâmetros e chame os métodos correspondentes.
Se a tua opção for a 1ª, podes fazer exactamente como o Wizzard-of-War disse e não terás problemas.
Se escolheres a segunda, também não tem muito que saber, embora tenhas de abandonar um pouco a ajuda do "Visual". O que eu fiz foi criar um array de botões, cada um com uma propriedade que o torna único (no meu caso um simples X,Y), e no eventhandler, como recebes como argumento o próprio objecto que o chamou, extrais essas propriedades únicas e chamas os métodos em função do botão que o chamou.
Se decidires usar esta segunda opção, diz qq coisa, que eu passo-te o código do que fiz.
candycane 19-05-2008, 11:56 Obrigada pelas ajudas :)
andrepadez prefiro o 2º metodo, era algo assim que tinha em mente. Só que nunca usei event handling :(
andrepadez 19-05-2008, 14:30 Este problema então vai um pouco além do EventHandler. Provalvelmente alguem mais entendido em programação vai dizer que há forma melhor de fazer isto. Eu agradeço, mas esta foi a forma como consegui resolver o que precisava.
Comecemos pelo início:
1º - Convem perceberes que código o Visual C# gera ao colocar um botão (ou o objecto da Toolbox que quiseres usar, vamos supor que é um botão)
a) Coloca um botão na tua form de forma normal e faz duplo click nele para o programa criar o EventHandler tb,
b) Vais ver o código do formdesigner que foi gerado pelo botão. Gera logo uma série de linhas para declarar o botão, declarar o nome, definir o tamanho, a posição, etc.
podes até copiar este código para um ficheiro de texto, para depois ir buscá-lo mais facilmente. Podes apagar o botão que criaste.
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(12, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
2º - Pô-los no form
a)no form principal, declaras um array (ou matriz) de botões (como global)
Button[] botoes = new button[nºde botões]
no método Form_Load(), constróis o array no ecrã com um for (recorrendo ao código que guardaste, só tens de alterar umas ceninhas, como retirar o this):
for (i = 0; i < nºbotões; i++)
{
botoes[i] = new Button();
botoes[i].Name = "botao" + i;
botoes[i].Size = new System.Drawing.Size(75,23);
....
botoes[i].Click += new System.EventHandler(Botoes_Click);
}
Notas: quanto ao nome, o iterador i é uma maneira de dares uma propriedade única ao botão, de forma a poderes distinguí-lo dos outros quando for clickado; a localização de cada um, pode ser definido dentro do for se a distância entre eles for sempre regular, senão defines uma a uma com botoes[0].Location = new System.Drawing.Point(12,12); botoes[1].Location = ...; Desta maneira, com o EventHandler a ser sempre o mesmo, ele vai receber como argumento o botão que foi clickado.
No código do form, vais então criar o método Eventhandler com o nome que puseste entre-parenteses, e da seguinte forma:
private Void Botoes_Click (object sender, EventArgs e)
Lá dentro vais ter de declarar uma variável que receba as propriedades do botão que invocou a função:
Button variavel = (Button) sender;
a partir daqui podes fazer o que quiseres como:
if variavel.Name = "botao0"
método0();
else if variavel.Name = "botao1"
método1();
assim, quando o user clicka num, botão sabes que está a chamar o método correspondente.
Espero que te tenha clarificado, foi um pouco difícil de transcrever isto para o que querias que as minhas necessidades eram um pouco diferentes ( um tabuleiro de xadrez com uma classe que herda de PictureBoxes), mas a filosofia é a mesma. Qualquer coisa apita, se quiseres tb te mando o código do que fiz, para veres melhor como posicionei as cenas no ecrã, etc.
Não te esqueças que tb podes criar uma classe que herde de Button e acrescentes as propriedades e os métodos que quiseres.
Fica bem
Ш¡zard·σf·Шαr 19-05-2008, 17:34 Na verdade, não é necessário complicar muito. Para obter o índice do botão clicado no array de botões, dentro da subrotina que faz handling do evento, pode-se fazer assim:
Button botaoClicado = (Button)sender;
int indiceDoBotao = Array.IndexOf(Botao, botaoClicado, 0);
andrepadez 19-05-2008, 17:49 Tens razão, não tinha pensado nisso; como tinha propriedades x,y usei-as e aqui foi a maneira que me lembrei. Thx wizzard
candycane 20-05-2008, 09:09 Muito obrigada a todos! :)
Acho que já vou conseguir resolver o problema :D
candycane 20-05-2008, 09:48 Há alguma maneira de eu guardar numa variável dentro do meu EventHandler o texto que dei ao botão?
O nome que dei aos botões foi o nome das mesas que estao na base de dados.
Se conseguisse ter apenas o nome já conseguia fazer um query em que o meu where seria o nome da mesa do botao clicado.
O que me aparece é: System.Windows.Forms.Button, Text: mesa: M01
O que queria é apenas o M01, tentei com substring mas sem sucesso :(
a parte do botao esta assim:
for (int i = 0; i < (count / 3); i++)
{
for (int j = 0; j < (count / 7); j++)
{
sr.Read();
btn_mesa[i, j] = new Button();
btn_mesa[i, j].Name = "botao" + i;
btn_mesa[i, j].Location = new Point(120 * i, 100 * j);
btn_mesa[i, j].Size = new Size(100, 80);
btn_mesa[i, j].Text = "Mesa: \n " + sr["id_mesa"].ToString();
pnl_inicio.Controls.Add(btn_mesa[i, j]);
btn_mesa[i, j].Click += new System.EventHandler(this.btn_click);
}
}
o meu sr é o meu SqlDataReader.
Ш¡zard·σf·Шαr 20-05-2008, 09:55 Para obter todas as propriedades do botão no event handler:
Button botaoClicado = (Button)sender;
//botaoClicado.Text - devolve o texto do botão
//botaoClicado.Name - devolve o nome do botão
//...
candycane 20-05-2008, 10:14 Muito obrigada!!!
Ja vou poder avançar e muito na aplicação :)
candycane 20-05-2008, 16:39 Acho que vou precisar que vocês me deem uma luz novamente. :\
eu fiz a aplicação com panels, e coloquei um botao para voltar a tras(para a ver todas a mesas)
so que n me limpa os dados do botão anterior. Então pnsei que tinha que fazer o metodo ao contrario, remover os Controls.
Fiz da seguinte maneira, mas não me esta a limpar as labels :(
public void remover_control()
{
List<Control> controlsRemover = new List<Control> ();
foreach (Control c in this.Controls)
{
if (c is Label)
{
controlsRemover.Add(c);
}
}
foreach (Control remove in controlsRemover)
{
this.Controls.Remove(remove);
remove.Dispose();
}
dentro do meu botao voltar a tras chamo essa funçao, mas não me entra no if (c is Label)
Acho que estao a complicar, n sei que eventos keres....
mas no msm sitio das properties tens la a lista com os eventos para esse control, dps double click e ele cria logo...
Repito, n sei se keres fazer algo muito especifico...mas os basicos tao la...tipo mouse over, etc
Ш¡zard·σf·Шαr 20-05-2008, 21:09 Não percebi porque é que decidiste remover os controls, mas para remover todos os controls faz-se assim:
private List<Control> obterControls(Control parent)
{
List<Control> l = new List<Control>();
foreach (Control c in parent.Controls)
{
l.Add(c);
l.AddRange(obterControls(c));
}
return l;
}
public void remover_controls(Control parent)
{
foreach (Control c in obterControls(parent))
c.Parent.Controls.Remove(c);
}Se quiseres apenas remover alguns controls (por exemplo, todas as labels), basta pôr uma condição antes da linha l.Add(c):
if (c is Label)
l.Add(c);Acho que estao a complicar, n sei que eventos keres....
mas no msm sitio das properties tens la a lista com os eventos para esse control, dps double click e ele cria logo...
Repito, n sei se keres fazer algo muito especifico...mas os basicos tao la...tipo mouse over, etc
Estamos a falar de event handling para controls criados durante a execução do programa, não durante o design. ;)
candycane 21-05-2008, 09:16 decidi remover pk quando volto a tras, a lista das mesas, ao clicar noutro botao de outra mesa, os dados da mesa anterior n apagam :(
Ficam uns em cima dos outros :\
Tou a buscar os dados a partir da BD.
Por ex, clico na mesa M01 e vejo os pedidos dessa mesa, quanco clico em voltra atras, vou ter novamente os botoes de todas a mesas. Clico no botao da mesa M02 e os pedidos da mesa M01 continuam lá, e os da M02 ficam por cima :(
Tou a fazer com panels, um panel pros botoes das mesas todas, e outro panel com os detalhes de cada mesa. Será por isso?
Ш¡zard·σf·Шαr 21-05-2008, 09:43 Mas, ao clicares numa mesa, os dados dos controls que mostram os detalhes não vão ser todos substituídos pelos detalhes da nova mesa (obtidos da BD)? Era suposto funcionar assim. Não há necessidade de remover todos os controls, basta alterar o conteúdo de cada um. E utilizas os mesmos controls para os detalhes de qualquer mesa.
candycane 21-05-2008, 09:49 Também pensava k substituia... mas estao a ficar um em cima dos outros :(
o que tenho no btn_atras é isto:
private void btn_atras_Click(object sender, EventArgs e)
{
pnl_inicio.Visible = true;
pnl_detalhes.Visible = false;
}
:(
Ш¡zard·σf·Шαr 21-05-2008, 09:57 E na parte de preencher os detalhes para uma mesa, não estás a criar novos controls? Acho que esta é a única razão para aparecerem uns controls em cima dos outros...
candycane 21-05-2008, 10:10 Tou sim, crio labels com os pedidos e botoes para mais detalhes. Fiz debug e os dados variam conforme a mesa que clico. Mas ficam em cima uns dos outros :(
if(conta == 0)
{
lbl_SemPedido.Visible = true;
lbl_SemPedido.Text = "Não há pedidos para esta mesa.";
}
else
{
for (int i = 0; i < conta; i++)
{
sr.Read();
lbl_Pedidos[i] = newLabel();
btn_detalhes[i] = newButton();
lbl_Pedidos[i].Location = newPoint(105, 120 + (i * 25));
lbl_Pedidos[i].Text = sr["P_Mesa"].ToString();
btn_detalhes[i].Location = newPoint(16, 118 + (i * 25));
btn_detalhes[i].Text = "+ info";
btn_detalhes[i].Size = newSize(48, 23);
btn_detalhes[i].ForeColor = SystemColors.HotTrack;
btn_detalhes[i].Font = newFont("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
pnl_detalhes.Controls.Add(lbl_Pedidos[i]);
pnl_detalhes.Controls.Add(btn_detalhes[i]);
}
}
Ш¡zard·σf·Шαr 21-05-2008, 10:19 Então é esse o problema. Se não houver nenhum inconveniente, devias usar sempre o mesmo conjunto de labels e botões para a apresentação dos detalhes. E esses labels/botões podem ser colocados durante o design.
Se quiseres mesmo criar novos controls, também não há problema, podes sempre usar a subrotina que mostrei no post #14. Basta passá-la o pnl_detalhes como argumento, e todos os controls dentro do pnl_detalhes serão eliminados.
remover_controls(pnl_detalhes);
candycane 21-05-2008, 10:26 Então é esse o problema. Se não houver nenhum inconveniente, devias usar sempre o mesmo conjunto de labels e botões para a apresentação dos detalhes. E esses labels/botões podem ser colocados durante o design.
Não entendi a parte do desing...
Crio uma label no desing e depois de criar o array de labels digo que lbl_design.Text = lbl_array[i].ToString();
Ups...
Coloquei como argumento no remover_controls o panel mas apagaou-me tudo LOLOLOL
Não tou a conseguir é que ele veja se é apenas Labels...
publicvoid remover_control(Panelpanel)
{
foreach (Control c in obterControls(panel))
c.Parent.Controls.Remove(c);
}
No obterControls n mexi em nada:
privateList<Control> obterControlos(Controlparent)
{
List<Control> l = newList<Control>();
foreach (Control c in parent.Controls)
{
if (c isLabel)
{
l.Add(c);
l.AddRange(obterControlos(c));
}
}
return l;
}
Acho que o melhor a fazer é criar tudo dinamicamente dentro do pnl_detalhes.. Assim ele apaga e depois cria tudo outra vez... Tinha criado em desgn uns botoes e labels mas assim apaga tudo. Vou fazer agora tudo dinamicamente, espero que dê certo :)
Ш¡zard·σf·Шαr 21-05-2008, 10:45 Não entendi a parte do desing...
Crio uma label no desing e depois de criar o array de labels digo que lbl_design.Text = lbl_array[i].ToString();
Não, a ideia era criar apenas 1 label e 1 botão (ou mais, se for necessário), e usar sempre o mesmo label e o mesmo botão para todas as mesas. Assim não precisas de estar a criar e inserir um novo label e um novo botão por cada vez que apresentas os detalhes de uma mesa, basta alterar o conteúdo da label e do botão que foram criados durante o design.
Ups...
Coloquei como argumento no remover_controls o panel mas apagaou-me tudo LOLOLOL
Estranho, testei aqui e funciona bem... Isto é, apaga todos os controls que estão dentro do control que é passado por argumento à rotina remover_control. Nesse caso, apagaria todos os controls que estão dentro do pnl_detalhes.
Não tou a conseguir é que ele veja se é apenas Labels...É só alterar esta parte:
if (c is Label)
l.Add(c);
l.AddRange(obterControlos(c));Também testei.
candycane 21-05-2008, 11:13 Obrigada :)
declarei uma labels publicas para os titulos,
fiz tudo dinamicamente e qgora ja esta tudo ok... ufa :)
Tava a apagar tudo e depois cria-se tudo novamente... so espero que n se torne pesado, pk depois terei k fazer um grafico com as mesas que mais lucro deram LOLOL
Mãezinha...
Muito obrigada pela ajuda! não ia conseguir fazer sem voces :)
|
|