none
Parar um loop pressionando uma tecla RRS feed

  • Pergunta

  • Gostaria de saber se uma forma de ler o estado da tecla no loop, para saber se ela é pressionada.

    Estou desenvolvendo uma aplicação que gera uma lista em excel, estou utilizando um loop para gerar cada linha do arquivo, mas quero que a operação seja abortada caso a tecla Escape seja pressionada.

    terça-feira, 16 de abril de 2013 16:42

Respostas

  • Olá,

    A solução não funcionará, pois, conforme você mencionou o Form está bloqueado.

    Ele está bloqueado porque o seu método está sendo executado na Thread Principal que é a mesma do formulário, portanto, enquanto seu método estiver sendo executado, a Thread Principal estará totalmente ocupada com ele, não conseguindo atualizar o form e tratar outros eventos.

    No seu caso, acredito que somente chamando seu método com Thread, seguindo os passos:

    - Criar um método com o código do looping;

    - Tratar neste método o catch e finally para que não estore erro e para que os recursos alocados pelo excel sejam liberados quando a Thread for abortada;

    - Declarar uma Thread em escopo global, exemplo:

    private Thread thread = null;

    - No click do botão que dispara o loop, instanciar a Thread passando seu método como referência e iniciar ela, exemplo:

    thread = new Thread(new ThreadStart(MetodoLoop));
    thread.Start();

    - Verificar no seu Form o evento que captura o pressionamento da tecla e nele chamar o cancelamento da Thread (validar se a Thread está instanciada), exemplo:

    thread.Abort();

    Observação: com este tratamento, seu formulário ficará disponível, portanto, deve-se tratar o bloqueio do botão após disparo da Thread, desbloqueando ele somente após a execução desta ou do cancelamento pela tecla, para que não seja possível disparar várias Thread em paralelo.

    Abraços


    terça-feira, 16 de abril de 2013 19:57

Todas as Respostas

  • Olá,

    Para vc verificar se a tecla "Esc" foi pressionada, no evento "PreviewKeyDown" vc colocaria assim:

    if (e.Key == Keys.Escape)
    {
       //... seu código
    }

    Agora a questão é, onde está esse loop? Como vc está verificando se é para cancelar ou não?

    O que lhe aconcelho é:

    Criar uma variável:

    //Variável global
    bool termina = false;

    E no seu loop (usei Do While para exemplificar, mas é igual para qualquer ciclo:

    Do
    {
        if(termina == true)
        {
            return;
        }
        //Resto do código
    }While(...)

    E no PreviewKeyDown do seu formulário, vc faria:

    if (e.Key == Keys.Escape)
    {
        termina = true;
    }

    Desta forma assim que vc pressionar ele vai mudar o estado do "termina", e de seguida o loop pára pois vai verificar que o "termina" ficou como verdadeiro

    Cumpz, ADAE.

    • Sugerido como Resposta Vitor Mendes terça-feira, 16 de abril de 2013 16:55
    • Marcado como Resposta ericquaresma terça-feira, 16 de abril de 2013 18:41
    • Não Marcado como Resposta ericquaresma terça-feira, 16 de abril de 2013 18:41
    terça-feira, 16 de abril de 2013 16:49
  • Eu cheguei a tentar algo parecido, mas estava utilizando no evento "KeyDown", tbm cheguei a encontra algo sobre o "PreviewKeyDown", mas é como se o Form ficasse bloqueado.

    Eu clico em um botão para gerar a planilha e durante o processo não é possível fazer nada com o Form, os botões ficam bloqueados, não consigo fechá-lo e ao pressionar qq tecla, não acontece nada, o "KeyPreview" está como true e caso não esteja gerando a planilha os eventos "KeyDown" e "PreviewKeyDown" funcionam corretamente, até tentei utilizar o "PreviewKeyDown" com o botão Gerar em foco, mas ainda assim não reconhece.

    terça-feira, 16 de abril de 2013 18:39
  • Olá,

    Pode postar o código do seu loop para podermos ajudar?

    Cumpz, ADAE.

    terça-feira, 16 de abril de 2013 18:48
  • Claro q sim, aqui já está com o código q vc me indicou, eu tbm fiz um teste simples com o q me passou e ocorre o mesmo, fiz somente um Form com um loop e é como se ele ficasse bloqueado.

    if (vop_Lista.Items.Count > 0)
    {
     for (int vil_CountL = 0; vil_CountL < vop_Lista.Items.Count; vil_CountL++)
     {
      lblRegistro.Text = "Processando registro: " + Convert.ToString(vil_CountL + 1) + " de " + Convert.ToString(vop_Lista.Items.Count);
      lblRegistro.Refresh();
      vil_Count = 0;

      if (termina == true)
      {
       return;
      }

      for (int vil_CountCLista = 0; vil_CountCLista < vop_Lista.Columns.Count; vil_CountCLista++)
      {
       vil_CountCampo = 0;
       for (int vil_CountC = 0; vil_CountC < lvwColunas.Items.Count; vil_CountC++)
       {
        if (lvwColunas.Items[vil_CountC].Checked == true)
        {
         if (ail_indice[vil_CountC] == "s")
         {
          vol_Range = (Excel.Range)vol_Sheet.Cells[vil_CountL + 2, vil_CountCampo + 1];
          vol_Range.Value2 = vop_Lista.Items[vil_CountL].SubItems[vil_CountC].Text.ToString();
          vol_Range.Select();
          vol_Range.Font.Name = "Verdana";
          vol_Range.Font.Size = 8;
          vol_Range.HorizontalAlignment = Excel.Constants.xlCenter;
          vol_Range.Interior.ColorIndex = 2;
          vol_Range.Borders.Weight = 3;
          vol_Range.Borders.LineStyle = Excel.Constants.xlSolid;
          vol_Range.EntireColumn.AutoFit();
          vil_CountCampo++;
         }
        }
       }
      }
     }
    }

    terça-feira, 16 de abril de 2013 18:58
  • Oq eu fiz o teste ficou da seguinte maneira.

    namespace WindowsFormsApplication2
    {
        public partial class Form1 : Form
        {
            bool termina = false;
            int i = 0;

            public Form1()
            {
                InitializeComponent();
            }

            private void Form1_Load(object sender, EventArgs e)
            {

            }

            private void button1_Click(object sender, EventArgs e)
            {
                i = 0;
                //for (i = 0; i < 1000000; i++)
                //{
                //    label1.Text = i.ToString();

                //    if (termina == true)
                //    {
                //        return;
                //    }
                //}

                do
                {
                    i++;
                    label1.Text = i.ToString();

                    if (termina == true)
                    {
                        label1.Text = "PAROU";
                        return;
                    }
                }
                while (i < 100000);
            }

            private void Form1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
            {
                if (e.KeyCode == Keys.Escape)
                {
                    termina = true;
                }
            }

            private void Form1_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Escape)
                {
                    termina = true;
                }
            }
        }
    }

    terça-feira, 16 de abril de 2013 19:00
  • Olá,

    A solução não funcionará, pois, conforme você mencionou o Form está bloqueado.

    Ele está bloqueado porque o seu método está sendo executado na Thread Principal que é a mesma do formulário, portanto, enquanto seu método estiver sendo executado, a Thread Principal estará totalmente ocupada com ele, não conseguindo atualizar o form e tratar outros eventos.

    No seu caso, acredito que somente chamando seu método com Thread, seguindo os passos:

    - Criar um método com o código do looping;

    - Tratar neste método o catch e finally para que não estore erro e para que os recursos alocados pelo excel sejam liberados quando a Thread for abortada;

    - Declarar uma Thread em escopo global, exemplo:

    private Thread thread = null;

    - No click do botão que dispara o loop, instanciar a Thread passando seu método como referência e iniciar ela, exemplo:

    thread = new Thread(new ThreadStart(MetodoLoop));
    thread.Start();

    - Verificar no seu Form o evento que captura o pressionamento da tecla e nele chamar o cancelamento da Thread (validar se a Thread está instanciada), exemplo:

    thread.Abort();

    Observação: com este tratamento, seu formulário ficará disponível, portanto, deve-se tratar o bloqueio do botão após disparo da Thread, desbloqueando ele somente após a execução desta ou do cancelamento pela tecla, para que não seja possível disparar várias Thread em paralelo.

    Abraços


    terça-feira, 16 de abril de 2013 19:57
  • Obrigado Diego, dessa forma realmente funcionou, só precisei declarar um delegate para tratar os controles da primeira thread, outra forma q encontrei e tbm funcionou foi utilizar declarar o Application.DoEvents() dentro do loop, junto com a solução do ADAE, tbm vi q essa forma não é recomendada, mas para a aplicação q estou utilizando aparentemente não haverá problemas.
     
    Obrigado aos dois.
    quarta-feira, 17 de abril de 2013 14:54