 |
ActiveDelphi .: O site do programador Delphi! :.
|
| Exibir mensagem anterior :: Exibir próxima mensagem |
| Autor |
Mensagem |
valdiralbertod@gmail.com Novato

Registrado: Sábado, 14 de Julho de 2018 Mensagens: 6
|
Enviada: Sáb Jul 14, 2018 6:48 pm Assunto: Problemas com Application.ProcessMessasges no Tokyo |
|
|
Boa noite,
Até o Delphi Berlin, para apresentar uma mensagem ao usuário e aguardar a resposta dele para depois executar a rotina X ou a rotina Y, eu utilizava a função abaixo e funcionava legal.
class function TFuncoes.MsgConfirmacao(VMsg : String) : boolean;
Var
VModalResult : TModalResult;
begin
MessageDlg(VMsg, System.UITypes.TMsgDlgType.mtConfirmation,
[System.UITypes.TMsgDlgBtn.mbYes, System.UITypes.TMsgDlgBtn.mbNo], 0,
procedure(const AResult: TModalResult)
begin
VModalResult := AResult;
end);
While VModalResult = mrNone do application.ProcessMessages;
Result := VModalResult = mrYes;
end;
Porém, no Delphi Tokyo, o sistema congela ao executar essa função. Nas pesquisa que fiz, parece que o problema está no application.ProcessMessages que agora (com o Tokyo) gera um resultado diferente no processamento quando SO Android.
A minha dúvida é: alguém tem alguma rotina, sugestão ou qualquer dica que possa me passar em relação a essa questão?
O que preciso é apresentar uma pergunta ao usuário e somente depois da resposta executar determinada rotina.
Encontrei inúmeros artigos e até com e exemplos sobre isso, mas nada funciona. Parece que no Android não funciona nada sincrono. Tem que ser tudo assíncrono.
Agradeço qualquer ajuda.
Obrigado. |
|
| Voltar ao Topo |
|
 |
strak2012 Colaborador


Registrado: Segunda-Feira, 13 de Janeiro de 2014 Mensagens: 1518 Localização: Maceió - AL
|
Enviada: Sáb Jul 14, 2018 9:21 pm Assunto: |
|
|
Com o uso de thread tem a questão resolvida. _________________ Tudo podemos quando tudo sabemos! |
|
| Voltar ao Topo |
|
 |
valdiralbertod@gmail.com Novato

Registrado: Sábado, 14 de Julho de 2018 Mensagens: 6
|
Enviada: Dom Jul 15, 2018 9:06 am Assunto: |
|
|
| strak2012 escreveu: | | Com o uso de thread tem a questão resolvida. |
Bom dia,
Obrigado pela resposta.
Eu fiz uma thread colocando toda a minha class function TFuncoes.MsgConfirmacao(VMsg : String) : boolean dentro da thread. No Windows funciona beleza, mas no Android ele congela (trava) do mesmo jeito que s executada fora da thread.
Na verdade eu não tenho muito conhecimento com threads...você poderia me ajudar com algumas dicas de como iniciar? Talvez um pequeno exemplo?
Obrigado.[/b] |
|
| Voltar ao Topo |
|
 |
igormoita Profissional


Registrado: Quinta-Feira, 14 de Janeiro de 2010 Mensagens: 601
|
Enviada: Seg Jul 16, 2018 9:41 am Assunto: |
|
|
Thread é um assunto complexo, visto que ela deve rodar fora da Aplicação em um novo processo no CPU. Acontece que com o FMX alguns detalhes na sua utilização mudaram, segue código para utilização de AnonymousThread para o FMX (testado no Windows e Android):
https://textuploader.com/dzzmv
Acontece que ao utilizarmos Thread o sistema executa um processo fora do Aplication para realização da seu código, isso quer dizer que seu código fora da Thread vai rodar normalmente msm se a Thread não terminar, aqui temos dois detalhes:
1º: Se vc precisa de qualquer informação de retorno da Thread, vai ter que bolar um jeito de 'aguardar' a finalização;
2º: Qualquer interação da Thread para com qualquer objeto criado em Application deve ser executado dentro de um TThread.Synchronize (segue no código). Esse comando obriga a Thread a sincronizar com o objeto da aplicação (esse objeto pode ser uma variável, componente, class, etc);
Para o 1º caso existem vários contextos, um dos que eu utilizo é na hora de realizar o Login: aciono a Thread para fazer o Login, inicio no Application um Timer que irá esperar o fim da Thread, após o fim da Thread (try finally end) eu preencho uma variável para informar ao Timer que o Login finalizou, daí pego os retornos e valido. Existem várias outras formas de se 'esperar', esse é um exemplo;
Uma observação no 2º caso, passamos meses tentando solucionar um problema com a Thread, onde se perdia os resultados que precisávamos, apenas às vezes dava o erro, na maioria o sistema funcionava perfeitamente, apenas com o Synchronize passou a dar 100% certo. Não posso te dizer exatamente como utilizar, pois Thread é um assunto muito delicado, espero que estas dicas facilitem teu aprendizado nessa área. _________________ SEMPRE COLOQUE [RESOLVIDO] NO SEU POST |
|
| Voltar ao Topo |
|
 |
valdiralbertod@gmail.com Novato

Registrado: Sábado, 14 de Julho de 2018 Mensagens: 6
|
Enviada: Seg Jul 16, 2018 10:30 am Assunto: |
|
|
| igormoita escreveu: | Thread é um assunto complexo, visto que ela deve rodar fora da Aplicação em um novo processo no CPU. Acontece que com o FMX alguns detalhes na sua utilização mudaram, segue código para utilização de AnonymousThread para o FMX (testado no Windows e Android):
https://textuploader.com/dzzmv
Acontece que ao utilizarmos Thread o sistema executa um processo fora do Aplication para realização da seu código, isso quer dizer que seu código fora da Thread vai rodar normalmente msm se a Thread não terminar, aqui temos dois detalhes:
1º: Se vc precisa de qualquer informação de retorno da Thread, vai ter que bolar um jeito de 'aguardar' a finalização;
2º: Qualquer interação da Thread para com qualquer objeto criado em Application deve ser executado dentro de um TThread.Synchronize (segue no código). Esse comando obriga a Thread a sincronizar com o objeto da aplicação (esse objeto pode ser uma variável, componente, class, etc);
Para o 1º caso existem vários contextos, um dos que eu utilizo é na hora de realizar o Login: aciono a Thread para fazer o Login, inicio no Application um Timer que irá esperar o fim da Thread, após o fim da Thread (try finally end) eu preencho uma variável para informar ao Timer que o Login finalizou, daí pego os retornos e valido. Existem várias outras formas de se 'esperar', esse é um exemplo;
Uma observação no 2º caso, passamos meses tentando solucionar um problema com a Thread, onde se perdia os resultados que precisávamos, apenas às vezes dava o erro, na maioria o sistema funcionava perfeitamente, apenas com o Synchronize passou a dar 100% certo. Não posso te dizer exatamente como utilizar, pois Thread é um assunto muito delicado, espero que estas dicas facilitem teu aprendizado nessa área. |
Bom dia,
Beleza Igor. Vou me aprofundar na questão. Suas dicas foram de grande ajuda.
Obrigado. |
|
| Voltar ao Topo |
|
 |
valdiralbertod@gmail.com Novato

Registrado: Sábado, 14 de Julho de 2018 Mensagens: 6
|
Enviada: Qua Jul 18, 2018 10:27 am Assunto: |
|
|
| igormoita escreveu: | Thread é um assunto complexo, visto que ela deve rodar fora da Aplicação em um novo processo no CPU. Acontece que com o FMX alguns detalhes na sua utilização mudaram, segue código para utilização de AnonymousThread para o FMX (testado no Windows e Android):
https://textuploader.com/dzzmv
Acontece que ao utilizarmos Thread o sistema executa um processo fora do Aplication para realização da seu código, isso quer dizer que seu código fora da Thread vai rodar normalmente msm se a Thread não terminar, aqui temos dois detalhes:
1º: Se vc precisa de qualquer informação de retorno da Thread, vai ter que bolar um jeito de 'aguardar' a finalização;
2º: Qualquer interação da Thread para com qualquer objeto criado em Application deve ser executado dentro de um TThread.Synchronize (segue no código). Esse comando obriga a Thread a sincronizar com o objeto da aplicação (esse objeto pode ser uma variável, componente, class, etc);
Para o 1º caso existem vários contextos, um dos que eu utilizo é na hora de realizar o Login: aciono a Thread para fazer o Login, inicio no Application um Timer que irá esperar o fim da Thread, após o fim da Thread (try finally end) eu preencho uma variável para informar ao Timer que o Login finalizou, daí pego os retornos e valido. Existem várias outras formas de se 'esperar', esse é um exemplo;
Uma observação no 2º caso, passamos meses tentando solucionar um problema com a Thread, onde se perdia os resultados que precisávamos, apenas às vezes dava o erro, na maioria o sistema funcionava perfeitamente, apenas com o Synchronize passou a dar 100% certo. Não posso te dizer exatamente como utilizar, pois Thread é um assunto muito delicado, espero que estas dicas facilitem teu aprendizado nessa área. |
Bom dia Igor,
Desculpe a insistência Igor, mas não estou conseguindo e não há quase nenhum material na net sobre o assunto. Estou há 60 dias nessa peleja, rs...sem progresso, hehe!
Se puder me ajudar fazendo um exemplo funcional. Gostaria inclusive de lhe pagar por isso. Se for o caso me manda uma msg em pv (ou WhatsApp 41-99709-5622) para combinarmos.
Vou relatar como tentei fazer, mas sem sucesso.
Var
VThread: TThread;
VFModal : TFModalResult;
begin
VControle := 0; //é uma variável global.
VThread := TThread.CreateAnonymousThread(procedure ()
begin
TThread.Synchronize(TThread.CurrentThread,
procedure ()
begin
//FModalResult é um form que tem 3 botões. Quando clica no primeiro botão, VControle := 1.
if VFModal = nil then VFModal := TFModalResult.Create(nil);
VFModal.ShowModal(procedure(ModalResult: TModalResult)
begin
While VControle = 0 do Application.ProcessMessages; //isto deveria parar a aplicação com o VFModal na tela até que o usuário clique no botão lá no VFModal, mas não pára.
end);
end);
end);
VThread.FreeOnTerminate := True;
VThread.Start();
//isto acontece mesmo sem o usuário ter clicado lá no FModal
ShowMessage('Daqui em diante só deve processar após thread, ou seja, após o usuário ter clicado no botão fo VModal');
end;
Obrigado. |
|
| Voltar ao Topo |
|
 |
igormoita Profissional


Registrado: Quinta-Feira, 14 de Janeiro de 2010 Mensagens: 601
|
Enviada: Qua Jul 18, 2018 11:16 am Assunto: |
|
|
Desculpe, mas acabei de passando uma dica errada. Esqueça a utilização de Thread neste caso, não irá facilitar a solução, deixe o código como estava sem a Thread, vamos fazer de uma outra forma.
(mas sugiro que aprenda a utilizar Thread para outros casos, ajuda muito para deixar o App fluido)
Vamos para minha solução para seu problema (Apresentar um MessageDiolog e "esperar" resposta):
Links ao final.
No Fontes1 é um código que eu utilizo em um Biblioteca.pas, basicamente é uma unit compartilhada com vários outros projetos, tentei deixar o mais padrão possível para ser utilizada em Units ou Units de Forms (não sei quais alterações seriam necessárias para uma UnitForm);
No Fontes2 é um exemplo de chamada para o código do Fontes1.
Basicamente estou utilizado o MessageDialog do FMX, mas executo um procedimento no caso se a resposta for mrYes (Sim). Neste caso específico eu vou executar um procedimento que obrigatoriamente recebe um parâmetro do tipo TObject, fiz o exemplo assim pois apanhei horrores para migrar da execução Sem parâmetro para o Com Parâmetro. Deixei no Fontes1 detalhes para que vc consiga fazer a execução sem parâmetros, até sugiro que vc altere e teste sem, pois é mais fácil de entender, mas já mandei com parâmetro para diminuir o tempo de aprendizagem.
Pelo que me lembre este código funciona igualmente para Desktop (Windows) e Mobile (Android), não testei em outras plataformas.
Fontes1: https://textuploader.com/dz708
Fontes2: https://textuploader.com/dz7kd
(Dica: sempre faça testes em projetos novos, pois é mais fácil vc controlar seus erros. Se vc for testar em seu projeto completo pode ser que um erro externo cause falhas e vc terá dificuldade para saber se foi no seu código novo ou não) _________________ SEMPRE COLOQUE [RESOLVIDO] NO SEU POST |
|
| Voltar ao Topo |
|
 |
valdiralbertod@gmail.com Novato

Registrado: Sábado, 14 de Julho de 2018 Mensagens: 6
|
Enviada: Qua Jul 18, 2018 2:29 pm Assunto: |
|
|
| igormoita escreveu: | Desculpe, mas acabei de passando uma dica errada. Esqueça a utilização de Thread neste caso, não irá facilitar a solução, deixe o código como estava sem a Thread, vamos fazer de uma outra forma.
(mas sugiro que aprenda a utilizar Thread para outros casos, ajuda muito para deixar o App fluido)
Vamos para minha solução para seu problema (Apresentar um MessageDiolog e "esperar" resposta):
Links ao final.
No Fontes1 é um código que eu utilizo em um Biblioteca.pas, basicamente é uma unit compartilhada com vários outros projetos, tentei deixar o mais padrão possível para ser utilizada em Units ou Units de Forms (não sei quais alterações seriam necessárias para uma UnitForm);
No Fontes2 é um exemplo de chamada para o código do Fontes1.
Basicamente estou utilizado o MessageDialog do FMX, mas executo um procedimento no caso se a resposta for mrYes (Sim). Neste caso específico eu vou executar um procedimento que obrigatoriamente recebe um parâmetro do tipo TObject, fiz o exemplo assim pois apanhei horrores para migrar da execução Sem parâmetro para o Com Parâmetro. Deixei no Fontes1 detalhes para que vc consiga fazer a execução sem parâmetros, até sugiro que vc altere e teste sem, pois é mais fácil de entender, mas já mandei com parâmetro para diminuir o tempo de aprendizagem.
Pelo que me lembre este código funciona igualmente para Desktop (Windows) e Mobile (Android), não testei em outras plataformas.
Fontes1: https://textuploader.com/dz708
Fontes2: https://textuploader.com/dz7kd
(Dica: sempre faça testes em projetos novos, pois é mais fácil vc controlar seus erros. Se vc for testar em seu projeto completo pode ser que um erro externo cause falhas e vc terá dificuldade para saber se foi no seu código novo ou não) |
Muitíssimo obrigado Igor.
Consegui fazer funcionar, mas ocorre um probleminha. Não sei se fiz algo errado ou que foi...
Chamando a função (button 1) conforme abaixo, tudo certo
procedure TFPrincipal.Button1Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz uma pergunta?', Sender, ExecutarSeForSim);
end;
Mas, se chamar a função mais de uma vez a função (button 2) conforme abaixo, aí ele inverte a ordem quando em Android (no Windows blz), ou seja, executa a terceira chamada, depois a segunda e depois a primeira.
procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1); //no Android isto é executado por terceiro
ShowMessageYesNo('Faz a segunda pergunta?', Sender, ExecutarSeForSim2); //no Android isto é executado por segundo
ShowMessageYesNo('Faz a segunda pergunta?', Sender, ExecutarSeForSim3); //no Android isto é executado por primeiro
end;
|
|
| Voltar ao Topo |
|
 |
igormoita Profissional


Registrado: Quinta-Feira, 14 de Janeiro de 2010 Mensagens: 601
|
Enviada: Qua Jul 18, 2018 3:50 pm Assunto: |
|
|
Na realidade a ordem de execução está correta, mas provavelmente a lógica de execução não.
No Android (não sei no iOS) realmente as coisas são assíncronas, ou seja, vai executar o primeiro ShowMessage, depois o segundo e depois o terceiro, como está escrito no seu código, sendo assim é certo apresentar de 'trás para frente', visto que a msg 3 sobrepõe a 2 e a 1, consequentemente.
O correto nessa estratégia seria vc colocar os ShowMessage dentro dos procedures, por exemplo:
ExecutarSeForSim1 executa o ShowMessage2;
ExecutarSeForSim2 executa o ShowMessage3;
Etc...
Daí vc faz só a primeira chamada
procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
end;
Tecnicamente dizendo o Android vai executar tudo depois do ShowMessage, mas só vai executar a Procedure se a pessoa clicar em Sim.
procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
StrToIn('1'); // Sera executado mesmo sem escolher Sim ou Nao
//Mas a procedure ExecutarSeForSim1 so sera executada se clicar em Sim, msm se o sistema excutou estas linhas apos o ShowMessage
end;
Sabendo disso, tudo que vc quer que seja executado em caso de SIM deve ser codificado dentro da procedure ExecutarSeForSim1 (que foi enviada no ShowMessage) _________________ SEMPRE COLOQUE [RESOLVIDO] NO SEU POST |
|
| Voltar ao Topo |
|
 |
valdiralbertod@gmail.com Novato

Registrado: Sábado, 14 de Julho de 2018 Mensagens: 6
|
Enviada: Qui Jul 19, 2018 7:30 am Assunto: |
|
|
| igormoita escreveu: | Na realidade a ordem de execução está correta, mas provavelmente a lógica de execução não.
No Android (não sei no iOS) realmente as coisas são assíncronas, ou seja, vai executar o primeiro ShowMessage, depois o segundo e depois o terceiro, como está escrito no seu código, sendo assim é certo apresentar de 'trás para frente', visto que a msg 3 sobrepõe a 2 e a 1, consequentemente.
O correto nessa estratégia seria vc colocar os ShowMessage dentro dos procedures, por exemplo:
ExecutarSeForSim1 executa o ShowMessage2;
ExecutarSeForSim2 executa o ShowMessage3;
Etc...
Daí vc faz só a primeira chamada
procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
end;
Tecnicamente dizendo o Android vai executar tudo depois do ShowMessage, mas só vai executar a Procedure se a pessoa clicar em Sim.
procedure TFPrincipal.Button2Click(Sender: TObject);
begin
inherited;
ShowMessageYesNo('Faz a primeira pergunta?', Sender, ExecutarSeForSim1);
StrToIn('1'); // Sera executado mesmo sem escolher Sim ou Nao
//Mas a procedure ExecutarSeForSim1 so sera executada se clicar em Sim, msm se o sistema excutou estas linhas apos o ShowMessage
end;
Sabendo disso, tudo que vc quer que seja executado em caso de SIM deve ser codificado dentro da procedure ExecutarSeForSim1 (que foi enviada no ShowMessage) |
Beleza, vou tentar implementar.
Muito obrigado. Foi de grande ajuda.
Abraços. |
|
| Voltar ao Topo |
|
 |
|
|
Enviar Mensagens Novas: Proibido. Responder Tópicos Proibido Editar Mensagens: Proibido. Excluir Mensagens: Proibido. Votar em Enquetes: Proibido.
|
|