VIII. Desenvolvimento de um Programa com Telas e Arquivos
Olá
Se você vem acompanhando esta série de tutoriais, já deve ter aprendido muita coisa sobre programação. Para consolidar esse aprendizado, decidi dedicar este oitavo tutorial a apresentar um projeto concluído de um programa com vários dos conceitos que aprendemos nos últimos tutoriais. O objetivo desta etapa é entender como aplicamos os conceitos aprendidos até aqui de forma a construir um programa que servirá para um propósito comum em nosso dia a dia.
Você alguma vez já se viu com um monte de tarefas diferentes para fazer e percebeu que era difícil distribuir o seu tempo de forma organizada entre elas? É comum estarmos bem atarefados no nosso dia-a-dia profissional ou estudantil e quando as datas de entrega dos trabalhos ou das provas vão se aproximando, nós sempre ficamos com aquela sensação de que perdemos muito do nosso tempo ou que temos sempre muita coisa para entregar de uma só vez em alguma semana específica.
A razão desta sensação normalmente não é o número de tarefas, mas a forma empírica como nós controlamos as tarefas fazendo uso somente da nossa mente. Demonstrar isso é fácil: basta perceber que na semana anterior tinhamos praticamente o mesmo número de tarefas, mas não tínhamos a mesma sensação de urgência e sobrepeso desta semana!
Portanto, se quisermos melhorar nossa vida e distribuir melhor a nossa carga de compromissos ao longo do nosso tempo, precisamos fazer uso de ferramentas informativas que melhorem o nosso controle sobre as nossas tarefas pendentes.
Desta forma, este tutorial se dedica a demonstrar e explicar o desenvolvimento e o código de um programa gestor de tarefas.
Vamos lá?
1. Desenvolvendo os aspectos conceituais
Conforme vimos nos tutoriais I e III, todo projeto nasce de uma ideia, e esta surge normalmente a partir da constatação de um problema e de nosso conhecimento prévio sobre o que podemos usar para melhor resolver este problema. Dessa forma, podemos definir o nosso para este tutorial como sendo
como controlar melhor as nossas tarefas e gerir o nosso tempo gasto com elas.
Assim, nos vem a mente, graças ao nosso conhecimento prévio sobre as possibilidades da programação, a ideia de criar um programa que nos permita gerenciar essas tarefas.
O próximo passo é então planejar este programa, transformando-o em um projeto. Isso significa que devemos nos esforçar para criar um esboço, onde fique mais fácil elencar que informações vamos precisar controlar e que telas, tabelas, e outros controles vão ajudar nosso usuário a realizar este controle de forma fácil e efetiva.
Pensando um pouco sobre como se executa a maioria das tarefas, vejo que elas tem alguns
momentos distintos que podem ser relativamente bem definidos. O primeiro é o
momento inicial, aquele no qual descobrimos que teremos que cumprir a tarefa. Esse momento pode ser o momento em que o professor ou chefe nos passa a tarefa, ou o momento em que decidimos que vamos implementar essa tarefa. Quando este primeiro momento chega a tarefa ganha forma e passamos a conhecer alguns aspectos importantes dela. O primeiro é a
descrição da tarefa, ou seja, o trabalho que precisa ser feito. Além disso, temos a
data e/ou hora inicial, aquela na qual tomamos conhecimento da necessidade de executar a tarefa. Também podemos descobrir naquele momento
o responsável pela tarefa, que pode ser a pessoa principal caso a tarefa seja delegada a um time. Outro ponto importante da tarefa é a
data máxima para a sua conclusão, ou seja, até quando podemos entregar a tarefa, que vai nos dizer ainda
o prazo que temos para concluir a tarefa. Além disso, como esta tarefa provavelmente não será a única que teremos para entregar em um mesmo momento, podemos ainda indicar para a mesma uma
prioridade em relação às outras tarefas que temos para entrega. Mas aqui cabe uma ressalva: muita gente define a prioridade com base na data de entrega. Isso não é necessariamente verdade: a prioridade serve para sabermos em qual tarefa devemos trabalhar primeiro caso já tenhamos, ou caso apareça depois, uma outra tarefa para concluir,
mas não significa que podemos deixar as tarefas para depois. Lembre-se: deixar tarefas para depois é o que nos faz sentir sobrecarregados próximo às datas de entrega!
Basicamente são estes os principais pontos que as tarefas têm em comum e que podem ser conhecidos assim que recebemos a tarefa.
Isso signfica que estas são as informações que precisamos controlar no nosso programa e que serão inseridas no momento do cadastro da tarefa. Mas um ponto importante precisa ser destacado também: muitas tarefas têm outros pontos específicos que podem ser muito importantes de se controlar. Para estes casos especiais, precisamos ter em nosso programa um ou mais campos genéricos, que permitam ao usuário uma certa flexibilidade no controle das informações importantes das tarefas. Por este motivo, é importante em quase qualquer programa pelo menos um
campo de observações.
Após o momento inicial, temos também
momentos secundários da conclusão da tarefa. Estes momentos são os andamentos que damos à tarefa ao longo do tempo de execução. Tirando algumas tarefas menores, as tarefas normalmente envolvem um tempo de execução longo, onde precisamos avançar passo-a-passo antes de concluir a tarefa. Por exemplo, para construir uma casa, é preciso primeiro esquadrejar as medidas e cavar a vala da fundação. Depois, precisamos construir a fundação, e daí poderemos levantar os pilaretes e construir as paredes, que precisarão mais à frente serem rebocadas, emassadas e pintadas. Também temos a construção do telhado e do forro. Todas essas tarefas menores são andamentos da tarefa maior (que é a construção da casa). Assim, vemos que
uma tarefa longa pode ser dividida em andamentos menores, e controlar esses andamentos é uma forma mais adequada de controlar a tarefa maior. Se hoje nós terminamos de cavar a vala, é importante poder colocar isso no nosso programa, de modo que fique claro que concluímos um passo importante para a construção da casa!
Resumindo, o programa deve:
- 1. Permitir a inclusão de tarefas e controle de seus principais aspectos conhecidos no início.
- 2. Permitir a inclusão de cada andamentos em cada tarefa, de modo que fique claro o passo-a-passo para a solução da tarefa.
- 3. Permitir a indicação da conclusão da tarefa (para que saibamos o que está pendente e o que já foi feito). Isso pode vir através do status de conclusão e do status de finalização da tarefa.
2. Desenvolvendo as telas
Para desenvolver as telas do nosso programa, precisamos pensar em como utilizaremos os controles disponíveis (botões, campos, tabelas, etc) para controlar adequadamente o que elencamos no final do item anterior.
Pensando um pouco, vejo que seria interessante um formulário de inclusão de tarefas, e também uma tabela mostrando cada tarefa pendente. Além disso, como as tarefas têm andamentos que devem ser controláveis, precisamos de um formulário de inclusão de andamentos e de uma tabela que mostra os andamentos de cada tarefa. Precisamos colocar tudo isso em um (ou mais) espaços de tela, vejo que seria interessante que
os andamentos fossem dispostos em uma tabela à parte, e que essa tabela mostrasse os andamentos da tarefa selecionada na tabela de tarefas.
- ESBOCO FORMULARIO INCLUIR TAREFA.jpg (45.78 KiB) Viewed 74398 times
- ESBOCO DO GESTOR DE TAREFAS.jpg (109.1 KiB) Viewed 74398 times
- ESBOCO INCLUIR ANDAMENTO.jpg (39.26 KiB) Viewed 74398 times
Está quase bom. Mas ainda faltam algumas coisas. Primeiro, precisamos de uma forma de separar as tarefas finalizadas. Para isso, podemos usar simplesmente outra tela com uma tabela própria para as tarefas finalizadas. Isso significa também colocar um botão para o usuário indicar a finalização da tarefa. Além disso, precisamos pensar onde vai ficar o formulário de inclusão de andamentos. Acredito que o melhor lugar é a própria tela de tarefas em aberto (colocaremos na parte de baixo dela).
Com isso, já temos uma boa ideia sobre como vai funcionar o programa!
3. Desenvolvendo os arquivos
Conforme vimos no tutorial VII, se quisermos controlar informações que não podem ser perdidas caso o programa seja fechado ou o computador seja desligado, precisamos salvar estas informações em arquivos no disco rígido do computador. Para isso precisamos projetar nossos arquivos.
A melhor maneira de fazer isso é pensar em que tipo de informações estaremos salvando nesse arquivo. Todas as informações que vamos trabalhar são de certa forma descrições textuais das tarefas e andamentos, inseridas pelo usuário. Assim, podemos perceber que trabalharemos com uma espécie de arquivo de texto.
Mas há um porém:
algumas informações que precisamos salvar não são exatamente texto. Imagine que precisamos que o programa saiba que porção do texto que o usuário inseriu se refere à observação de determinado andamento de determinada tarefa. Temos que salvar isso também!
Estes dados sobre dados são, conforme vimos no tutorial VII, chamados de
metadados. Eles são importantes para que o programa saiba tratar corretamente a informação recebida. No nosso caso, isso significa que o programa precisa ter uma forma de saber o que é uma observação, o que é uma data, e assim sucessivamente.
Podemos fazer isso de várias formas. Uma delas é desenvolver um novo tipo de arquivo, que permita indicar as posições no texto que se referem a cada campo. Mas como vimos no tutorial VII, isso vai demandar muito tempo e trabalho. Talvez seja melhor procurar outro tipo de arquivo já existente que permita fazer isso de forma mais fácil.
Consultando o arquivo de ajuda do AutoHotkey, vemos que ele possui suporte para um tipo de arquivo de texto chamado
.ini. Os arquivos desse tipo são normalmente arquivos de parâmetros de configuração, e se organizam através de chaves descritivas de cada informação.
Parece bastante com o que queremos!
Portanto, vamos investigar se o arquivo
.ini nos permitiria grava tudo o que precisamos sobre os andamentos e tarefas.
Um arquivo
.ini se organiza da seguinte forma:
Code: Select all
[seção1]
chave1=valor
chave2=valor
chave3=valor
...
[seção2]
chave1=valor
chave2=valor
...
Assim posso imaginar que a informação que preciso pode ser escrita mais ou menos assim:
Code: Select all
[1]
descricao=CONSTR. CASA
data_inic=22/05/2018
resp=CICRANO
status=40
prior=media
[1.1]
data=23/05/2018
hora=08:00
descricao=VALA DA FUNDACAO CAVADA
novo_status=10
observ=PEDREIRO BELTRANO
[1.2]
data=25/05/2018
hora=10:30
descricao=CONSTRUCAO DO BALDRAME
novo_status=20
observ=PEDREIRO CICRANO
A ideia é simples. O nome de cada seção diz se é uma tarefa ou um andamento, e no caso do andamentos, diz ainda a qual tarefa se refere. Isso será feito através dos códigos numéricos. Assim, a seção 8 por exemplo, que não tem decimais, será uma seção de tarefa, e a seção 8.1, que tem um decimal, será o primeiro andamento da tarefa da seção 8.
Além disso, as chaves de uma seção sem decimais, como a 5, se referem as informações de uma tarefa, e as chaves de seção com decimais, tipo 5.3, se referem as informações de um andamento.
Agora, podemos fazer uso dos comandos do AutoHotkey que tratam de arquivos do tipo
.ini para botar esta ideia em prática!
Um detalhe: Os comandos de arquivos do tipo
.ini não necessitam que o arquivo seja normeado com a extensão
.ini. Podemos usar isso como um nível de segurança, fazendo com que o usuário não consiga abrir o arquivo automaticamente em um editor de texto, como faria se ele estivesse nomeado corretamente com a extensão
.ini (embora caiba destacar que esse nível de segurança extremamente básico, afinal, o arquivo ainda pode ser abertos em um editor de texto se o usuário souber que isso é possível!).
Se quiséssemos, poderíamos aumentar ainda mais o nível de segurança das informações de várias formas. Uma delas é encriptar as informações no arquivo
.ini. Para este tutorial, isso não será feito, pois este programa é somente para estudo. Mas é importante dizer que cabe ao programador definir o nível de segurança das informações do seu programa, lembrando que maior segurança pode requerer maior trabalho.
4. Escrevendo o código
Agora que já temos um projeto adequado, está na hora de executá-lo. Isso significa basicamente escrever o código e tornar real o nosso programa. Podemos iniciar escrevendo os códigos das telas, e você pode consultar o tutorial VI para ver como isso é feito.
Em resumo: mostramos uma tela com o comando show, e seguimos duas máximas: os preparativos da tela (colocar botões, campos, etc) são escritos ANTES DO SHOW e as ações dos personagens (ou seja, o que vai acontecer quando o usuário ativar os controles) serão escritos APÓS O SHOW.
Assim, as ações dos controles são o que ativa as labels de escrita dos arquivos. Essa labels contém os comandos de tratamento do arquivo
.ini que renomeamos com
.bdgt para que somente nós saibamos a princípio que se trata de um arquivo de texto.
Lembre-se também de uma coisa muito importante:
como vamos escrever um código longo, é extremamente importante comentar bastante o código e também dividí-lo em labels e funções com nomes bem indicativos do que os códigos fazem. Isso signifca que apesar de nosso código ter mais de 350 linhas, será relativamente fácil analisá-lo e ainda entender onde teremos que mexer se quisermos alterar alguma coisa. ASSIM, PARA LER O CÓDIGO ABAIXO, PENSE NOS NOMES DAS LABELS E FUNCOES E COMO ISSO INDICA O QUE A PORÇÃO DE CÓDIGO FAZ. LEIA TAMBÉM OS COMENTÁRIOS (QUE FICAM NAS PRÓPRIAS LINHAS APÓS O SÍMBOLO
;).
Assim, o código final do programa Gestor de Tarefas pode ser conferido abaixo.
Execute o código e cadastre algumas tarefas. Depois, cadastre andamentos para algumas das tarefas. Veja como o programa se comporta e como ele exibe as informações de forma organizada.
Veja também que o programa cria um arquivo chamado BD.dbgt na pasta em que se encontra quando você o executa. Este arquivo é o arquivo
.INI (embora com uma extensão diferente). Depois de incluir algumas tarefas e andamentos, você pode abrir este arquivo em um editor de texto para ver como o programa o usou para salvar as informações!
A SENHA É
ABACAXI.
Code: Select all
; GESTOR DE TAREFAS.AHK
; AUTOR: GIO
; LINK DO POST: https://autohotkey.com/boards/viewtopic.php?p=213650#p213650
; DATA DE ESCRITA: 21/05/2018
; DESCRIÇÃO DO PROGRAMA: GERENCIADOR DE TAREFAS COM ROTINAS DE INCLUSAO E VISUALIZAÇÃO DE TAREFAS E DE SEUS ANDAMENTOS EM TABELAS
; O PROGRAMA INICIA AQUI
; ESTA PORÇÃO INICIAL ABRE A PRIMEIRA TELA, ONDE O USUÁRIO DEVE COLOCAR A SENHA ABACAXI.
Gui, Font, s16 w700
Gui, Add, Text, x20 y20 w560 Center, Bem-Vindo!
Gui, Font
Gui, Font, s12 w700
Gui, Add, Text, x20 y280 w560 Center, Insira a senha abaixo para continuar
Gui, Add, Text,
Gui, add, Edit, Password x200 y310 w200 Limit12 vSENHA_INSERIDA
Gui, add, Button, x250 y350 w100 gAbrir_Agenda, Entrar ; AQUI TEM UMA G-LABEL! ISSO SIGNIFICA QUE QUANDO ESSE BOTAO DA PRIMEIRA TELA É PRESSIONADO, A LABEL ABRIR_AGENDA É EXECUTADA!
Gui, show, w600 h400, SisOrg v0.1
Return
Abrir_Agenda:
Gui, Submit, nohide
If !(SENHA_INSERIDA = "ABACAXI") ; ESTA CONDICIONAL CHECA SE O USUÁRIO NÃO ESCREVEU ABACAXI NO CAMPO DE SENHA DA PRIMEIRA TELA. SE ELE NÃO ESCREVEU, EXIBE UM ERRO E RETORNA A EXECUÇÃO SEM PROSSEGUIR.
{
msgbox, 0x10, Erro, A senha digitada está incorreta! Tente novamente ou procure o suporte! `n`n`n(OBS: A SENHA ESTÁ NO POST, ACIMA DO CÓDIGO! OU VEJA ELA NO CÓDIGO DO SCRIPT!)
Return
}
; SE A EXECUÇÃO CHEGAR AQUI, ISSO SIGNFICA QUE O USUÁRIO ESCREVEU A SENHA ABACAXI (POIS SE NÃO TIVESSE ESCRITO, A LINHA DE RETORNO TERIA SIDO EXECUTADA).
; ENTENDEMOS PORTANTO QUE O USUÁRIO ESCREVEU A SENHA CERTA E ASSIM CONTINUAMOS OS COMANDOS PARA ABRIR A AGENDA.
IniRead, MAXIMA_ENTRADA, %A_SCriptDir%/BD.bdgt, MAXIMA_ENTRADA, CODIGO
If (MAXIMA_ENTRADA = "ERROR") ; ESTA CONDICIONAL CHECA SE O ARQUIVO INI NÃO POSSUI UMA SEÇÃO COM A MÁXIMA ENTRADA. USAMOS ESSA INFORMAÇÃO PARA CONTROLE DOS CODIGOS DAS TAREFAS.
{
; SE A EXECUÇÃO ENTRAR AQUI, O ARQUIVO INI NÃO POSSUI UMA SEÇÃO COM A MÁXIMA ENTRADA (MÁXIMO CÓDIGO DE TAREFA). ENTENDEMOS QUE SE ISSO ACONTECEU, ESTA PODE SER A PRIMEIRA VEZ QUE
; O PROGRAMA É EXECUTADO OU ENTÃO O ARQUIVO INI FOI CORROMPIDO.
CAMINHO_DO_ARQUIVO_DB := A_SCriptDir . "/BD.bdgt"
If !(FileExist(CAMINHO_DO_ARQUIVO_DB)) ; AQUI VERIFICAMOS SE EXISTE UM ARQUIVO INI NO CAMINHO QUE DEVERIA ESTAR (NA PASTA DO PROGRAMA).
{
Msgbox, 0x14, Erro, O sistema não detectou a presença de um arquivo de banco de dados na pasta principal. Deseja criar um novo arquivo de banco de dados em branco?
IfMsgBox, no ; ESTA CONDICIONAL VERIFICA SE O USUARIO ESCOLHEU "NÃO" NA CAIXA DE TEXTO. SE ESCOLHEU, TERMINAMOS A EXECUÇÃO DO PROGRAMA, POIS ESTE NÃO PODE TRABALHAR SEM O ARQUIVO INI.
{
msgbox, 0x10, Erro, O sistema não pôde se comunicar com o banco de dados. Reinicie ou contacte o suporte.
ExitApp
}
; SE A EXECUÇÃO CHEGAR AQUI, O USUÁRIO ESCOLHEU "SIM" NA CAIXA DE TEXTO (SABEMOS DISSO POR ELIMINAÇÃO, VEZ QUE O CÓDIGO DO "NÃO" NÃO FOI EXECUTADO).
IniWrite, 0, %A_SCriptDir%/BD.bdgt, MAXIMA_ENTRADA, CODIGO ; ESCREVEMOS UM NOVO ARQUIVO INI COM A MAXIMA ENTRADA 0 (ZERO) PARA INICIO DE CONTROLE DE CODIGOS DE TAREFAS.
Goto, Abrir_Agenda
Return
}
}
CriarGui2() ; NESTA LINHA CHAMAMOS A FUNÇÃO CRIARGUI2(). ASSIM, A EXECUÇÃO PULARÁ ATÉ O CÓDIGO DELA (PROCURE POR ELE ABAIXO). A FUNÇÃO NOS PERMITE SEPARAR E ORGANIZAR O CÓDIGO LONGO, VEZ QUE AQUI IRIAM MUITAS LINHAS RELACIONADAS SOMENTE A CRIAR A JANELA, POR ISSO, SEPARAMOS ELAS EM UMA FUNÇÃO PRÓPRIA. ASSIM, SE QUISER VER AS LINHAS QUE LIDAM COM A CRIAÇÃO DA TELA 2, BASTA IR NO CORPO DA FUNÇÃO CRIARGUI2(), QUE É AGORA UM PASSO SEPARADO DA ROTINA ABRIR_AGENDA.
Loop % MAXIMA_ENTRADA ; NESTA LINHA INICIAMOS UM LOOP, QUE É UMA REPETIÇÃO DE UM BLOCO DE COMANDOS. NO CASO DESTE LOOP, ELE VAI REPETINDO O CÓDIGO ABAIXO PARA LER CADA LINHA DO ARQUIVO INI E ADICONAR AS INFORMAÇÕES DA TAREFA NA TABELA DE TAREFAS DA TELA 2. VEJA COMO USAMOS A VARIAVEL EMBUTIDA A_INDEX PARA MUDAR A LEITURA EM CADA REPETIÇÃO DO LOOP (ITERAÇÃO). NA PRIMEIRA EXECUÇÃO, A_INDEX CONTÉM O NÚMERO 1, NA SEGUNDA CONTÉM O NÚMERO 2, E ASSIM SUCESSIVAMENTE ATÉ A ÚLTIMA REPETIÇÃO, QUE NADA MAIS É DO QUE O NÚMERO CONTIDO NA SEÇÃO MAXIMA_ENTRADA, QUE INDICA O NÚMERO DE TAREFAS ESCRITO NO ARQUIVO INI. É IMPORTANTE ENTENDER ESTE PONTO, POIS TODO O PROGRAMA TRABALHA CORRIGINDO ESSA INFORMAÇÃO: POR EXEMPLO, QUANDO ADICIONAMOS UMA NOVA TAREFA, O PROGRAMA VAI NO ARQUIVO INI E ADICIONA 1 AO NÚMERO QUE ESTÁ NA SEÇÃO MÁXIMA ENTRADA E SALVA O ARQUIVO. ASSIM, NA PRÓXIMA EXECUÇÃO, O PROGRAMA VAI SABER QUANTAS TAREFAS TEM (UMA A MAIS)..
{
IniRead, CODIGO, %A_SCriptDir%/BD.bdgt, %A_Index%, CODIGO
IniRead, DATA_INICIAL, %A_SCriptDir%/BD.bdgt, %A_Index%, DATA_INICIAL
IniRead, HORA_INICIAL, %A_SCriptDir%/BD.bdgt, %A_Index%, HORA_INICIAL
IniRead, DESCRICAO, %A_SCriptDir%/BD.bdgt, %A_Index%, DESCRICAO
IniRead, RESPONSAVEL, %A_SCriptDir%/BD.bdgt, %A_Index%, RESPONSAVEL
IniRead, STATUS, %A_SCriptDir%/BD.bdgt, %A_Index%, STATUS
IniRead, FINALIZADA, %A_SCriptDir%/BD.bdgt, %A_Index%, FINALIZADA
IniRead, OBSERVACAO, %A_SCriptDir%/BD.bdgt, %A_Index%, OBSERVACAO
If (FINALIZADA = "NAO") ; SE A TAREFA QUE ESTÁ SENDO LIDA TEM A INFORMAÇÃO "NAO" NA CHAVE FINALIZADA, ELA VAI PARA A TABELA DE TAREFAS EM ABERTO.
{
Gui, 2: Default
Gui, 2: ListView, VIEW_TAREFAS
Lv_Add("", CODIGO, DATA_INICIAL, HORA_INICIAL, DESCRICAO, RESPONSAVEL, STATUS, OBSERVACAO)
}
If (FINALIZADA = "SIM") ; MAS SE TIVER A INFORMAÇÃO "SIM" NA CHAVE FINALIZADA, ELA VAI PARA A TABELA DE TAREFAS FINALIZADAS. QUANDO FINALIZAMOS A TAREFA, O SISTEMA MUDA A INFORMAÇÃO DESTA CHAVE NESTA TAREFA, É ASSIM QUE CONTROLAMOS QUAIS TAREFAS ESTAO FINALIZADAS.
{
Gui, 2: Default
Gui, 2: ListView, VIEW_TAREFAS_FIN
Lv_Add("", CODIGO, DATA_INICIAL, HORA_INICIAL, DESCRICAO, RESPONSAVEL, STATUS, OBSERVACAO)
}
}
GoSub, GuiClose
Return
; A FUNÇÃO ABAIXO CRIA A TELA 2. VEJA QUE TODOS OS COMANDOS VEM ANTES DO COMANDO SHOW (QUE É O ÚLTIMO).
CriarGui2()
{
global
Gui, 2: Font, s12 w700
Gui, 2: Add, Tab2, x20 y20 w760 h560, Nova Tarefa|Tarefas Em Aberto|Tarefas Finalizadas
Gui, 2: Add, GroupBox, x40 y60 w720 h400, NOVA TAREFA
Gui, 2: Add, Text, x60 y90, Descrição
Gui, 2: Add, Edit, x60 y110 h100 w600 UPPERCASE vDESCRICAO_NOVA_TAREFA
Gui, 2: Add, Text, x60 y220, Responsável
Gui, 2: Add, Edit, x60 y240 w600 UPPERCASE -MULTI vRESPONSAVEL_NOVA_TAREFA
Gui, 2: Add, Text, x60 y280, Observação
Gui, 2: Add, Edit, x60 y300 h100 w600 UPPERCASE vOBSERVACAO_NOVA_TAREFA
Gui, 2: Add, Button, x60 y420 gSALVAR_TAREFA, SALVAR NOVA TAREFA
Gui, 2: Tab, 2
Gui, 2: Add, Text, x40 y60 w660 Center, TAREFAS
Gui, 2: Add, ListView, x40 y80 w720 r6 Grid vVIEW_TAREFAS gSELECIONAR_TAREFA AltSubmit, Cód|Data Inicial|Hora Inicial|Descrição|Responsável|Status|Observação ; MUITO IMPORTANTE!! VEJA A G-LABEL AQUI INIDICADA. QUANDO CLICAMOS NESSA TABELA, ELA EXECUTA: É ASSIM QUE ATUALIZAREMOS A TABELA DE ANDAMENTOS CADA VEZ QUE O USUÁRIO CLICAR EM UMA TAREFA DIFERENTE!
Gui, 2: Default
Gui, 2: ListView, VIEW_TAREFAS
LV_ModifyCol(1, 50), LV_ModifyCol(2, 120), LV_ModifyCol(3, 110), LV_ModifyCol(4, 220), LV_ModifyCol(5, 140), LV_ModifyCol(6, 80), LV_ModifyCol(7, 500)
Gui, 2: Add, Text, x40 y280 w660 Center, ANDAMENTOS
Gui, 2: Add, ListView, x40 y300 w720 r5 Grid vVIEW_ANDAMENTOS, Cód|Data|Hora|Descrição|Novo Status|Observação
Gui, 2: Default
Gui, 2: ListView, VIEW_ANDAMENTOS
LV_ModifyCol(1, 50), LV_ModifyCol(2, 120), LV_ModifyCol(3, 110), LV_ModifyCol(4, 280), LV_ModifyCol(5, 120), LV_ModifyCol(6, 500)
Gui, 2: Add, GroupBox, x40 y460 w720 h100, NOVO ANDAMENTO
Gui, 2: Font, s10 w700
Gui, 2: Add, Text, x60 y480, Descrição
Gui, 2: Add, Edit, x60 y500 w280 UPPERCASE vDESCRICAO_ANDAMENTO
Gui, 2: Add, Text, x360 y480, Novo Status
Gui, 2: Add, Edit, x360 y500 w80 Number Limit3 vSTATUS_ANDAMENTO
Gui, 2: Add, Text, x460 y480, Observações
Gui, 2: Add, Edit, x460 y500 w280 UPPERCASE vOBSERVACOES_ANDAMENTO
Gui, 2: Add, Button, x60 y530 gINCLUIR_ANDAMENTO, INCLUIR ANDAMENTO
Gui, 2: Add, Button, x580 y530 w160 gFINALIZAR_TAREFA, FINALIZAR TAREFA
Gui, 2: Tab, 3
Gui, 2: Add, Text, x40 y60 w660 Center, TAREFAS FINALIZADAS
Gui, 2: Add, ListView, x40 y80 w720 r8 Grid vVIEW_TAREFAS_FIN gSELECIONAR_TAREFA_FINALIZADA AltSubmit, Cód|Data Inicial|Hora Inicial|Descrição|Responsável|Status|Observação
Gui, 2: Default
Gui, 2: ListView, VIEW_TAREFAS_FIN
LV_ModifyCol(1, 50), LV_ModifyCol(2, 120), LV_ModifyCol(3, 110), LV_ModifyCol(4, 220), LV_ModifyCol(5, 140), LV_ModifyCol(6, 80), LV_ModifyCol(7, 500)
Gui, 2: Add, Text, x40 y280 w660 Center, ANDAMENTOS TOTAIS
Gui, 2: Add, ListView, x40 y300 w720 r10 Grid vVIEW_ANDAMENTOS_FIN, Cód|Data|Hora|Descrição|Novo Status|Observação
Gui, 2: Default
Gui, 2: ListView, VIEW_ANDAMENTOS_FIN
LV_ModifyCol(1, 50), LV_ModifyCol(2, 120), LV_ModifyCol(3, 110), LV_ModifyCol(4, 280), LV_ModifyCol(5, 120), LV_ModifyCol(6, 500)
Gui, 2: Show, w800 h600, Tarefas Atuais
}
Return
; A LABEL ABAIXO É CHAMADA QUANDO O USUARIO CLICA EM UMA ENTRADA NA TABELA DE TAREFAS (POIS FOI COLOCADA COMO G-LABEL DAQUELA TABELA). ELA ATUALIZA A TABELA DE ANDAMENTOS COM AS ENTRADAS CORRESPONDENTE AOS ANDAMENTOS DA TAREFA QUE FOI SELECIONADA QUANDO O USUARIO CLICOU.
SELECIONAR_TAREFA:
If (CHAMAR_EVENTO = "") ; Devido à opção Alt_Submit, necessária para que a g-label seja chamada ao clique no controle, a g-label é chamada duas vezes. Abaixo, a primeira chamada é descartada.
{
CHAMAR_EVENTO := 1
Return
}
If (CHAMAR_EVENTO = 1)
{
CHAMAR_EVENTO := ""
}
Gui, 2: Default
Gui, 2: Submit, nohide
Gui, 2: ListView, VIEW_TAREFAS
Count := ""
Count := Lv_GetCount("Selected")
If (Count < 1)
{
Return
}
ControlGet, TAREFA_SELECIONADA, List, Selected, SysListView321, A
StringSplit, TAREFA_SELECIONADA_, TAREFA_SELECIONADA, `t`n
IniRead, ANDAMENTOS, %A_SCriptDir%/BD.bdgt, %TAREFA_SELECIONADA_1%, ANDAMENTOS
Gui, 2: Default
Gui, 2: ListView, VIEW_ANDAMENTOS
Lv_Delete()
Loop % ANDAMENTOS ; NESTE LOOP ENTRAMOS NOS REGISTROS DO ARQUIVO INI. VEJA QUE O LOOP CORRE POR QUANTOS ANDAMENTOS TEM AQUELA TAREFA (CHAVE ANDAMENTOS DA SEÇÃO DA TAREFA SELECIONADA). CADA ANDAMENTO DEVE TER UMA SEÇÃO PRÓPRIA CUJO NÚMERO É O MESMO NUMERO DA TAREFA E O DECIMAL É O NÚMERO DO ANDAMENTO. ASSIM, SEÇÃO 4.7 É O SÉTIMO ANDAMENTO DA TAREFA 4.
{
SECAO_PARA_USO := TAREFA_SELECIONADA_1 . "." . A_Index
IniRead, CODIGO, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, CODIGO
IniRead, DATA, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, DATA
IniRead, HORA, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, HORA
IniRead, DESCRICAO, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, DESCRICAO
IniRead, NOVO_STATUS, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, NOVO_STATUS
IniRead, OBSERVACAO, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, OBSERVACAO
Gui, 2: Default
Gui, 2: ListView, VIEW_ANDAMENTOS
Lv_Add("", CODIGO, DATA, HORA, DESCRICAO, NOVO_STATUS, OBSERVACAO)
}
Return
; ESTA LABEL É SEMELHANTE À LABEL ACIMA, MAS PARA TAREFAS FINALIZADAS.
SELECIONAR_TAREFA_FINALIZADA:
If (CHAMAR_EVENTO = "") ; Devido à opção Alt_Submit, necessária para que a g-label seja chamada ao clique no controle, a g-label é chamada duas vezes. Abaixo, a primeira chamada é descartada.
{
CHAMAR_EVENTO := 1
Return
}
If (CHAMAR_EVENTO = 1)
{
CHAMAR_EVENTO := ""
}
Gui, 2: Default
Gui, 2: Submit, nohide
Gui, 2: ListView, VIEW_TAREFAS_FIN
Count := ""
Count := Lv_GetCount("Selected")
If (Count < 1)
{
Return
}
ControlGet, TAREFA_SELECIONADA, List, Selected, SysListView323, A
StringSplit, TAREFA_SELECIONADA_, TAREFA_SELECIONADA, `t`n
IniRead, ANDAMENTOS, %A_SCriptDir%/BD.bdgt, %TAREFA_SELECIONADA_1%, ANDAMENTOS
Gui, 2: Default
Gui, 2: ListView, VIEW_ANDAMENTOS_FIN
Lv_Delete()
Loop % ANDAMENTOS
{
SECAO_PARA_USO := TAREFA_SELECIONADA_1 . "." . A_Index
IniRead, CODIGO, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, CODIGO
IniRead, DATA, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, DATA
IniRead, HORA, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, HORA
IniRead, DESCRICAO, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, DESCRICAO
IniRead, NOVO_STATUS, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, NOVO_STATUS
IniRead, OBSERVACAO, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, OBSERVACAO
Gui, 2: Default
Gui, 2: ListView, VIEW_ANDAMENTOS_FIN
Lv_Add("", CODIGO, DATA, HORA, DESCRICAO, NOVO_STATUS, OBSERVACAO)
}
Return
; ESTA LABEL É CHAMADA QUANDO O USUÁRIO CLICA NO BOTÃO "SALVAR NOVA TAREFA"
; ELA BASICAMENTE ESCREVE UMA NOVA SEÇÃO NO ARQUIVO INI, CUJO NÚMERO É O NÚMERO MÁXIMO ANTERIOR ADICIONADO DE 1 E AS INFORMAÇÕES SÃO AS QUE O USUÁRIO ESCREVEU NO FORMULÁRIO E AS QUE SÃO
; COLETADAS AUTOMATICAMENTE (DATA DE INCLUSAO, POR EXEMPLO).
SALVAR_TAREFA:
Msgbox, 0x04, Aviso, Confirma a inclusão da tarefa?
IfMsgbox, No
{
Msgbox, 0x10, Aviso, Inclusão da tarefa cancelada pelo usuário.
Return
}
Gui, 2: Submit, Nohide
Gui, 2: Default
Gui, 2: ListView, VIEW_TAREFAS
DATA_INICIAL := A_DD . "/" . A_MM . "/" . A_YYYY
HORA_INICIAL := A_HOUR . ":" . A_MIN
StringReplace, DESCRICAO_NOVA_TAREFA, DESCRICAO_NOVA_TAREFA, `n, %A_Space%, All
StringReplace, OBSERVACAO_NOVA_TAREFA, OBSERVACAO_NOVA_TAREFA, `n, %A_Space%, All
MAXIMA_ENTRADA += 1
IniWrite, %MAXIMA_ENTRADA%, %A_SCriptDir%/BD.bdgt, MAXIMA_ENTRADA, CODIGO
IniWrite, %MAXIMA_ENTRADA%, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, CODIGO
IniWrite, %DATA_INICIAL%, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, DATA_INICIAL
IniWrite, %HORA_INICIAL%, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, HORA_INICIAL
IniWrite, %DESCRICAO_NOVA_TAREFA%, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, DESCRICAO
IniWrite, %RESPONSAVEL_NOVA_TAREFA%, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, RESPONSAVEL
IniWrite, 0, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, STATUS
IniWrite, NAO, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, FINALIZADA
IniWrite, %OBSERVACAO_NOVA_TAREFA%, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, OBSERVACAO
IniWrite, 0, %A_SCriptDir%/BD.bdgt, %MAXIMA_ENTRADA%, ANDAMENTOS
;MAXIMA_ENTRADA += 1
Lv_Add("", MAXIMA_ENTRADA, DATA_INICIAL, HORA_INICIAL, DESCRICAO_NOVA_TAREFA, RESPONSAVEL_NOVA_TAREFA, 0, OBSERVACAO_NOVA_TAREFA)
ControlSetText, Edit1,
ControlSetText, Edit2,
ControlSetText, Edit3,
Msgbox,, Aviso, Tarefa incluída com sucesso!
Return
; ESTA LABEL TROCA O VALOR DA CHAVE "FINALIZADA" DA SEÇÃO DO ARQUIVO INI CORRESPONDENTE À TAREFA SELECIONADA. DE "NAO" PARA "SIM".
FINALIZAR_TAREFA:
Gui, 2: Default
Gui, 2: Submit, nohide
Gui, 2: ListView, VIEW_TAREFAS
Count := ""
Count := Lv_GetCount("Selected")
If (Count < 1)
{
msgbox, 0x10, Erro, Selecione uma tarefa na lista de cima para indicar a finalização.
return
}
ControlGet, TAREFA_SELECIONADA, List, Selected, SysListView321, A
StringSplit, TAREFA_SELECIONADA_, TAREFA_SELECIONADA, `t`n
msgbox, 0x4, Aviso, Confirma a finalização da tarefa %TAREFA_SELECIONADA_1%?
IfMsgbox, No
{
Msgbox, 0x1, Aviso, Finalização cancelada pelo usuário.
Return
}
IniWrite, SIM, %A_SCriptDir%/BD.bdgt, %TAREFA_SELECIONADA_1%, FINALIZADA
LINHA_A_EXCLUIR := Lv_GetNext(0)
Lv_Delete(LINHA_A_EXCLUIR)
Gui, 2: ListView, VIEW_TAREFAS_FIN
Lv_Add("", TAREFA_SELECIONADA_1, TAREFA_SELECIONADA_2, TAREFA_SELECIONADA_3, TAREFA_SELECIONADA_4, TAREFA_SELECIONADA_5, TAREFA_SELECIONADA_6, TAREFA_SELECIONADA_7)
Gui, 2: ListView, VIEW_ANDAMENTOS
Lv_Delete()
Msgbox, 0x1, Aviso, Tarefa finalizada com sucesso!
Return
; ESTA LABEL CRIA UMA NOVA SEÇÃO NO ARQUIVO INI CUJO NUMERO É IGUAL AO DA TAREFA SELECIONADA E CUJO DECIMAL É 1 MAIOR QUE O NÚMERO DE ANDAMENTOS ANTERIOR DAQUELA TAREFA. ELA TAMBÉM ATUALIZA O NUMERO DE ANDAMENTOS INDICADO NA SECAO DA TAREFA, ADICIONANDO 1 A ELE.
INCLUIR_ANDAMENTO:
Gui, 2: Default
Gui, 2: Submit, nohide
If (DESCRICAO_ANDAMENTO = "")
{
Msgbox, 0x10, Erro, Informe uma descrição para este andamento.
Return
}
If (STATUS_ANDAMENTO > 100)
{
Msgbox, 0x10, Erro, O novo status informado deve ser um número entre 0 e 100.
Return
}
If (STATUS_ANDAMENTO = "")
{
Msgbox, 0x10, Erro, Informe o novo status da tarefa mediante este andamento!
Return
}
Gui, 2: ListView, VIEW_TAREFAS
Count := ""
Count := Lv_GetCount("Selected")
If (Count < 1)
{
msgbox, 0x10, Erro, Selecione uma tarefa na lista de cima na qual queira incluir o andamento.
return
}
ControlGet, TAREFA_SELECIONADA, List, Selected, SysListView321, A
StringSplit, TAREFA_SELECIONADA_, TAREFA_SELECIONADA, `t`n
IniRead, ANDAMENTOS_ATUAIS, %A_SCriptDir%/BD.bdgt, %TAREFA_SELECIONADA_1%, ANDAMENTOS
PROXIMO_ANDAMENTO := ANDAMENTOS_ATUAIS + 1
SECAO_PARA_USO := TAREFA_SELECIONADA_1 . "." . PROXIMO_ANDAMENTO
IniWrite, %PROXIMO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, CODIGO
DATA_DO_ANDAMENTO := A_DD . "/" . A_MM . "/" . A_YYYY
IniWrite, %DATA_DO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, DATA
HORA_DO_ANDAMENTO := A_Hour . ":" . A_Min
IniWrite, %HORA_DO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, HORA
IniWrite, %HORA_DO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, HORA
IniWrite, %HORA_DO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, HORA
IniWrite, %DESCRICAO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, DESCRICAO
IniWrite, %STATUS_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, NOVO_STATUS
IniWrite, %OBSERVACAO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %SECAO_PARA_USO%, OBSERVACAO
; TAMBEM ATUALIZAMOS DUAS CHAVES DA SECAO DA TAREFA
IniWrite, %PROXIMO_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %TAREFA_SELECIONADA_1%, ANDAMENTOS
IniWrite, %STATUS_ANDAMENTO%, %A_SCriptDir%/BD.bdgt, %TAREFA_SELECIONADA_1%, STATUS
Gui, 2: ListView, VIEW_ANDAMENTOS
Lv_Add("", PROXIMO_ANDAMENTO, DATA_DO_ANDAMENTO, HORA_DO_ANDAMENTO, DESCRICAO_ANDAMENTO, STATUS_ANDAMENTO, OBSERVACAO_ANDAMENTO)
Gui, 2: ListView, VIEW_TAREFAS
Lv_Modify(Lv_GetNext(0), "Col6", STATUS_ANDAMENTO)
Msgbox, 0x1, Aviso, Andamento incluído com sucesso.
Return
; ESTA LABEL EXECUTA QUANDO O USUÁRIO OU O PROGRAMA FECHA A TELA 1. ELA APENAS TERMINA O PROGRAMA (SE O USUARIO FECHOU) OU DESTROI A TELA 1 (SE O PROGRAMA FECHOU PARA ABRIR A TELA 2).
GuiClose:
IfWinNotExist, Tarefas Atuais
{
ExitApp
}
Gui, 1: Destroy
Return
; ESTA LABEL EXECUTA QUANDO O USUARIO FECHA A TELA 2. ELA APENAS DESTROI A TELA 2 E DEPOIS REINICIA O PROGRAMA. PARA FECHAR O PROGRAMA, O USUARIO DEVE FECHAR A TELA 1 CLICANDO NO X.
2GuiClose:
Gui, 2: Destroy
Reload
Return
5. Considerações Finais
Se você dedicou um pouco de ler o código do programa acima e a testar o programa, deve ter aprendido um monte de coisas! Aposto que muita coisa que coloquei nesse código você não sabia ainda (por exemplo, como fazer para atualizar uma tabela com base no clique em outra tabela). Talvez essa questão da quantidade de informações novas para fazer esse programa tenha lhe assustado um pouco, mas não se preocupe: todos os comandos escritos podem ser buscados no arquivo de ajuda e aprendidos! Em programação nós nunca saberemos fazer absolutamente tudo, e ter contato com códigos novos é importante para aumentar nossa bagagem de conhecimento. Se você estudar o código acima, poderá ver e aprender muita coisa, e quando estiver projetando outro programa, poderá usar o que aprendeu para melhorar o seu programa!
Este código tem o objetivo de consolidar as informações do últimos tutoriais. Acredito que com ele estamos muito perto de concluir esta série de tutoriais básicos de programação em AutoHotkey. Dos principais conceitos da linguagem, a maioria já foi explicada. O que achou de nossa jornada até aqui? Vale a pena dedicar um tempo diário a aprender coisas novas não é?
Ah, um detalhe! algumas das ideias que escrevemos no tutorial não foram implementadas ainda no código. Esse será o seu dever de casa: para consolidar seu conhecimento adicione ao programa o código de controle das datas finais das entregas das tarefas, a contagem de prazos restante, e o campo para indicação da prioridade da tarefa.
Dica: Você deve lembrar que tem de alterar o código de criação da tabela, o código de busca dos dados no arquivo, o código de inserção dos dados na tabela e também os códigos que inserem os dados no arquivo quando do cadastro da nova tarefa. Mas como o código está organizado, você poderá encontrar facilmente as linhas correspondentes a cada caso se olhar os nomes da labels e funções!
Parabéns pela dedicação e vamos em frente