kelsch.cristiano Posted May 16, 2010 at 08:48 PM Report #327480 Posted May 16, 2010 at 08:48 PM Boa noite estou com um problema que pode ser simples para quem já esteja com um conhecimento mais em C# a dúvuda é: Fiz uma tela em C# que tem dois botões Star e Stop, quando eu clico em Start ele executa esse código abaixo private void b_Play_Click(object sender, EventArgs e) { FicarEmLoop = true; //Seta o Loop no programa lbl_Executando.Visible = true; lbl_Parado.Visible = false; b_Play.Enabled = false; b_Stop.Enabled = true; while (FicarEmLoop) { //EXECUTA MEUS COMANDOS... } } Só que assim, a qualquer momento eu quero clicar e atualizar a variavel FicarEmLoop com false quando clicar em Stop, só que o programa não deixa pois está no meio do loop ainda, existe solução para isso?, esse é meu bloco do botão Stop. private void b_Stop_Click(object sender, EventArgs e) { FicarEmLoop = false; // Para o loop no programa } Preciso poder clicar no botão, o que posso fazer? Abraço a todos
DVD Posted May 16, 2010 at 10:09 PM Report #327490 Posted May 16, 2010 at 10:09 PM O problema é simples, o windows forms controlo de aspecto gráfico da plataforma .NET tal como o Swing do java apenas usa uma thread para actualizar o estado da componente gráfica de uma aplicação, ou seja, todos os eventos gerados por acções da parte gráfica são corridos numa só thread, logo se bloqueias essa thread a tua parte gráfica deixa de funcionar. Sugiro-te o uso da class BackgroundWorker para pores esse teu loop a correr numa outra thread. Cump<
FreiNando Posted May 16, 2010 at 10:33 PM Report #327492 Posted May 16, 2010 at 10:33 PM Algures dentro do teu LOOP usa o comando DoEvents, em seguida a verificação do valor de FicarEmLoop, para poderes sair. Mais informação em:http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents.aspx O caminho mais curto para conseguir fazer muitas coisas é fazer uma de cada vez. Samuel Smiles
RA Posted May 16, 2010 at 10:48 PM Report #327496 Posted May 16, 2010 at 10:48 PM Boas... Já agora, aproveito também para tirar umas dúvidas e conhecer as vossas opiniões! :-) A utilização do Application.DoEvents() parece-me ser bastante simples, o que é bom. No entanto, o loop continua a ser executado na thread do GUI o que pode levar a que o form fique "congelado" e o botão Stop inacessível. Eu faria algo como o DVD sugeriu, mas usaria a TheadPool, por achar mais simples. Algo assim: using System; using System.Windows.Forms; using System.Threading; namespace Tests { public partial class Form1 : Form { private object lockObject = new object(); private bool isInLoop = true; private bool IsInLoop { get { lock (lockObject) { return isInLoop; } } set { lock (lockObject) { isInLoop = value; } } } public Form1() { InitializeComponent(); btnStop.Enabled = false; } private void btnStop_Click(object sender, EventArgs e) { btnStop.Enabled = false; btnPlay.Enabled = true; IsInLoop = false; } private void btnPlay_Click(object sender, EventArgs e) { btnPlay.Enabled = false; btnStop.Enabled = true; IsInLoop = true; ThreadPool.QueueUserWorkItem(ExecuteMyAppLogic); } private void ExecuteMyAppLogic(object state) { while (IsInLoop) { // Executar a lógica da aplicação } } } } Cmpts
kelsch.cristiano Posted May 17, 2010 at 05:05 PM Author Report #327655 Posted May 17, 2010 at 05:05 PM Teria como me dar uma exemplo utilizando minhas variaveis do meu projeto? se puder colocar no código o que cada linha faz agradeço obrigado.
kelsch.cristiano Posted May 17, 2010 at 05:46 PM Author Report #327663 Posted May 17, 2010 at 05:46 PM Quando eu minimizar minha tela queria que meu programa ficasse no lado do relógio igual a muitos programas e não minimizado na minha barra, tem como? Vlw.
RA Posted May 17, 2010 at 07:26 PM Report #327692 Posted May 17, 2010 at 07:26 PM Boas... Quanto ao exemplo com o nome das tuas variáveis... Essa é muito simples! 😁 Acho que consegues lá chegar sozinho! 🙂 De qualquer maneira, neste exemplo, usei nomes como os teus. O exemplo que aqui coloco também faz aquela coisinha de "ficar ao lado do relógio". Não sei se era bem isto que querias, mas com um bocado de pesquisa acho que consegues fazer o que queres. Para que este exemplo funcione tens que fazer o seguinte: [*]Arrasta um componente "NotifyIcon" (Na Toolbox, em Common Controls) para o teu Form. [*]Tens que associar um ícone ao teu "NotifyIcon". Para isso tens que preencher a propriedade Icon do teu NotifyIcon com um ficheiro .ico válido (no meu teste usei este). [*]Tens que criar um "handler" para evento Click do "NotifyIcon". O meu é representado pelo método notifyIcon1_Click. [*]Tens que criar um "handler" para o evento Resize do teu formulário. O meu é representado pelo método Form1_Resize. Tem atenção aos comentários do código e vai ficando atento ao fórum para o caso de alguém notar uma falha, ou sugerir uma implementação melhor! 🙂 using System; using System.Windows.Forms; using System.Threading; namespace Tests { public partial class Form1 : Form { private object lockObject = new object(); private bool ficarEmLoop = true; private bool FicarEmLoop { get { lock (lockObject) { return ficarEmLoop; } } set { lock (lockObject) { ficarEmLoop = value; } } } /// <summary> /// Inicializa tudo. /// </summary> public Form1() { InitializeComponent(); b_Stop.Enabled = false; lbl_Executando.Visible = false; lbl_Parado.Visible = true; } /// <summary> /// Handler do evento Click do Botão Stop (b_Stop) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void b_Stop_Click(object sender, EventArgs e) { FicarEmLoop = false; lbl_Executando.Visible = false; lbl_Parado.Visible = true; b_Stop.Enabled = false; b_Play.Enabled = true; } /// <summary> /// Handler do evento Click do Botão Play (b_Play) /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void b_Play_Click(object sender, EventArgs e) { FicarEmLoop = true; //Seta o Loop no programa lbl_Executando.Visible = true; lbl_Parado.Visible = false; b_Play.Enabled = false; b_Stop.Enabled = true; // Dar ordem à ThreadPool para adicionar o método // ExecutaMeusComandos à sua "lista de execuções" // (que ocorrerão numa outra thread). ThreadPool.QueueUserWorkItem(ExecutaMeusComandos); } /// <summary> /// Irá executar os comandos do Loop. /// </summary> /// <param name="state"></param> private void ExecutaMeusComandos(object state) { while (FicarEmLoop) { //EXECUTA MEUS COMANDOS... } } /// <summary> /// Handler do evento Resise do teu Form. /// Este evento é que fará com que o form "fique ao lado do relógio". /// Encontrei isto no Google com a seguinte pesquisa: c# minimize to tray /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Resize(object sender, EventArgs e) { if (this.WindowState == FormWindowState.Minimized) { // Quero que o meu icone "que fica no lado do relógio" fique visivel notifyIcon1.Visible = true; // Texto e título para colocar no "balão" que aparece quando minimizamos para o tray notifyIcon1.BalloonTipText = "Para voltar a ver o formulário clique neste ícone."; notifyIcon1.BalloonTipTitle = "O meu programa"; // Este balão fica visivel durante 1 segundo notifyIcon1.ShowBalloonTip(1000); // Quando minimizo não quero que o formulário apareça na minha barra de tarefas. // Apenas o quero "ao lado do relógio" this.ShowInTaskbar = false; this.Hide(); } } /// <summary> /// Handler do evento Click do ícone do tray (o ícone "que fica no lado do relógio"). /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void notifyIcon1_Click(object sender, EventArgs e) { // Quero que o meu formulário fique visivel. this.Show(); // Quero que a minha janela volte ao estado "normal" -- pois ela tinha sido minimizada this.WindowState = FormWindowState.Normal; // Quero que o meu icone "que fica no lado do relógio" fique escondido this.notifyIcon1.Visible = false; } } } Qq dúvida sobre interpretação do que eu disse, ou escrevi, não hesites. Cmpts.
kelsch.cristiano Posted May 17, 2010 at 10:17 PM Author Report #327763 Posted May 17, 2010 at 10:17 PM Vlw, a única coisa que não entendi foi esse bloco abaixo. private bool FicarEmLoop { get { lock (lockObject) { return ficarEmLoop; } } set { lock (lockObject) { ficarEmLoop = value; } } } Obrigado.
RA Posted May 17, 2010 at 10:43 PM Report #327772 Posted May 17, 2010 at 10:43 PM Boas... É assim, nesta implementação simples, honestamente, isso é mais um preciosismo do que outra coisa. Isso tem a ver com conceitos programação concorrente e multi-thread. Esse lock garante-te acesso exclusivo à variável "ficarEmLoop": ou estás a ler, ou a escrever. Nunca acontecerá leitura e escrita ao mesmo tempo. Para leres mais sobre o assunto dá aqui um salto: http://www.inteligenciadigital.org/usando-lock-csharp-thread-dotnet/. Honestamente, se isso te provoca confusão, podes retirar os locks, ou apagar mesmo a propriedade "FicarEmLoop" e usar apenas a "ficarEmLoop". Não estou a ver nenhuma forma deste código poder dar grandes problemas. Eu coloquei esses locks mais por ser uma boa prática proteger dados que são lidos ou escritos em duas Threads diferentes, ou seja, estou a proteger uma "secção crítica". Cmpts.
DVD Posted May 18, 2010 at 02:16 PM Report #327881 Posted May 18, 2010 at 02:16 PM não precisas de lock nenhum esse problema de publicação resolve-se colocando a variavel como volatile. 🙂
kelsch.cristiano Posted May 18, 2010 at 04:30 PM Author Report #327919 Posted May 18, 2010 at 04:30 PM Boa tarde pessoal, Tem como fazer uma interrupção no programa de 0,1 Segundo quando uma variavel X for igual a verdadeiro? não queria utilizar o Thread.Sleep(10); Obrigado.
DVD Posted May 19, 2010 at 03:10 PM Report #328107 Posted May 19, 2010 at 03:10 PM Porque não usas um auto reset event para resolver isso?
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now