08/12/2010

Usando uma impressora matricial (Windows + RealBasic + LX-300)

Uma amiga olha para uma LX-300 em cima da minha mesa, franze o canto esquerdo do lábio superior e me pergunta: “-vem cá, essa coisa é velha ou é assim mesmo?”.
Para infelicidade de muitos nem tudo pode ser modernizado. Para que uma matricial possa ser substituída por outra tecnologia é necessário que o conceito de sua utilização também seja modificado.

As matriciais são mais comumente empregadas onde se deseja ter uma ou mais copias idênticas por meio de carbono, preenchimento de formulários e etc.

Enquanto os que fazem uso dessa necessária peça de museu não a substituírem por impressão laser, térmica ou algum tipo de documentação digital. Empresas como a Epson e suas clonoconcorrentes, bem como os programadores de aplicações dedicadas ainda precisam alimentar o mercado e dar o devido suporte.

Na hera Jurassic-DOS era sumariamente simples enviar caracteres de controle para a porta-paralela e baseado nos manuais do fabricante (que já não existem mais), era possível ir e vir em cima do papel de bordas perfuradas.
Mas hoje com o advento do “sistema protegido” e seu “Simulador DOS” até a porta paralela deixou de existir, hoje mesmo comprei uma Placa Mãe sem LPT, fato esse que não significa nada para quem usa MAC, lá ela nunca existiu.

Os problemas para usar estas impressoras estão se agravando por 3 motivos:
- Está caindo em desuso;
- A lei da procura e da oferta está elevando muito seu preço
- e por ultimo e não menos importante está faltando informações na internet.

Mas chega de filosofia e vamos ao que importa.
O maior problema na hora de se emitir um relatório em formulário continuo está em dizer para impressora que seu papel é exatamente deste tamanho e que ela não deve ejetar uma pagina A4 quando terminar de imprimir.

Eu descobrir da pior forma que não precisava de uma única linha de código alem das necessárias para imprimir. É só adicionar à coleção de paginas do servidor de impressão uma pagina no tamanho exato que você deseja e o spool se encarregará do resto.

Vá ao seu Painel de Controle e acesse Impressoras e Aparelhos de fax. No menu arquivo clique em Propriedades do Servidor

Adicione sua pagina no tamanho que quiser e assim todos os aplicativos irão ter acesso a este modelo. Lembre-se que a largura não poderá exceder a capacidade da impressora.

Estou preparando um tópico especifico para impressão já que eu acho que é mais fácil imprimir no Realbasic que roubar doce de criança dormindo.


\V/, vida longa e próspera.


28/10/2010

Usando Firebird no RealBasic

Dadas às necessidades de resolver alguns problemas, precisei ler bancos de dados no Firebird. Eu suspeitava que não fosse uma tarefa tão simples, e para completar, ainda esbarrei na vaga documentação on-line.


Em virtude do apelo de uma pessoa que prezo muito, não irei expressar meu desafeto pelo Firebird neste artigo, apesar de ter esta intenção.


Como não o estudei a fundo, e também não pretendo em função de algumas das características basicas que ele apresenta, tais como a dificuldade de conexão, banco de dados ser apenas um arquivo em disco entre outras. Tratarei apenas de demonstrar como se estabelece uma comunicação com este tipo de banco de dados usando o Realbasic e o plugin ODBC.




Requisitos:


Para começar, suponho que o Firebird já esteja instalado em uma maquina que você tenha acesso (pode ser seu próprio PC ou o servidor da sua empresa que, por algum motivo obscuro optou-se por ele). Eu não irei mencionar criação de banco de dados neste artigo, nem tão pouco as sintax SQL, tendo visto que já fiquei indignado com a falha na minha primeira tentativa (select now() não funciona)

Caso ainda não o tenha instalado, vá em www.firebirdsql.org, lá tem tudo que você precisa saber para instalá-lo.


Em segundo lugar, você precisa do drive ODBC especifico para ele. O qual pode ser encontrado em firebirdsql ODBC. Baixe e instale.


Em terceiro e tão importante quanto, seu RB deve possuir o plugin ODBC. O qual já deve existir na pasta ...\Extras\Database Plugins\ODBC aonde está instalado o RB. E se ainda não estiver na pasta ...\Plugins, é so copialo e reiniciar o rb. (Eu sei que você já sabe disso, mas tem gente q não sabia!)


Bom... Com esses detalhinhos resolvidos vamos nos conectar.


Temos 3 métodos simples para fazer isso.


- O primeiro e mais fácil é você ir ao Administrador de Fonte de Dados ODBC e criar um DSN.

  • Na guia Fonte de dados de usuários, clique em adicionar, na próxima tela (Criar nova fonte de dados) selecione o drive “Firebird/InterBase(r) driver”, clique em concluir. Na próxima tela (Firebird ODBC Setup), dê um nome ao seu DSN (ex: fb_test), depois, localize o banco de dados, que deve ser um fdb ou um gdb. Preencha o Database Accounte com seu login e depois Password (o padrão é SYSDBA e masterkey) (É um saco escrever manual!)


Vamos a diante. Agora no Realbasic:

Dim db As New ODBCDatabase //Instanciamos o objeto ODBC

Dim sDSN() as String //String para conter os parâmetros

//é assim q eu uso, pois Array são sempre mais rápidas q concatenação,

// mas você pode fazer diferente.


sDSN.Append "DSN= fb_test "

//Local do seu banco de dados

sDSN.Append "Dbname= C:\ Endereço_do_banco\banco_de_dados.GDB"


db.DataSource = Join(sDSN,";") //Preciso falar o que o join faz?


if db.connect Ten

MsgBox “Conexão bem sucedida!”

Else

MsgBox “Não foi desta vez!” + EndOfLine + db.ErrorMessage

End if


- A próxima conexão não fará uso de um DSN, o que pode facilitar a distribuição dos programas(e também não irá criar um DSN automaticamente para você)


Dim db As New ODBCDatabase //Instanciamos o objeto ODBC

Dim sDSN() as String //String para conter os parâmetros


//Local do seu banco de dados

sDSN.Append "Dbname= C:\Endereço_do_banco\banco_de_dados.GDB"

//O Nome do drive ODBC que você instalou

sDSN.Append "Driver=Firebird/InterBase(r) driver"

sDSN.Append "UID=SYSDBA" //Usuário

sDSN.Append "PWD=masterkey" //A senha(vc tb pode mandar em MD5 tambem)


db.DataSource = Join(sDSN,";")


if db.connect Ten

MsgBox “Conexão bem sucedida!”

Else

MsgBox “Não foi desta vez!” + EndOfLine + db.ErrorMessage

End if


- Por ultimo, vamos nus conectar remotamente ao banco de dados (é... isso é possível sim). Para isso na maquina cliente deverá ter o drive ODBC instalado. Mas, não podemos esquecer que sempre deixam algo de fora. Tem uma Dll de nome fbclient.dll que está na pasta system32 do servidor e deve ser copiada para o system32 do cliente (aproposito eu estou usando o windows)


Ficano do resultado assim:


Dim db As New ODBCDatabase //Instanciamos o objeto ODBC

Dim sDSN() as String //String para conter os parâmetros


sDSN.Append "Driver=Firebird/InterBase(r) driver"

sDSN.Append "Dbname=192.168.0.100:/Endereço_do_banco/banco_de_dados.GDB"

sDSN.Append "port=3050"

sDSN.Append "protocol=TCPIP"

sDSN.Append "CHARSET=NONE"

sDSN.Append "PWD=masterkey"

sDSN.Append "UID=SYSDBA"


db.DataSource = Join(sDSN,";")


if db.connect Ten

MsgBox “Conexão bem sucedida!”

Else

MsgBox “Não foi desta vez!” + EndOfLine + db.ErrorMessage

End if

Agora que você já se conectou ao Firebird, vamos abrir umas tabelas.


Dim rs As RecordSet


rs = db.SQLSelect("SELECT * FROM TB_VENDAS")

Só !

Eu adoro estas poucas linhas do RealBasic.


Mas já que são poucas. Veja também como listar todas as tabelas do banco de dados:


Dim a As String

r = db.TableSchema


Do until r.EOF


for n as integer = 1 to r.Fieldcount

a = a + r.IdxField( n ).Value + " >-> "

next

a = a + EndOfLine

r.MoveNext

loop


EditField1.Text = a

Por hoje é tudo pe pe ssoal!

29/07/2010

Expressões regulares no MySQL

A Expressão regular é uma poderosa ferramenta de busca de padrões.
Desenvolvida por nerdes que nunca tranzaram na vida, é terrivelmente confusa, e vai dar um no nos seus neurônios logo de cara!

Entretanto vale a pena o sacrifício, pois os resultados são incríveis!
Embora o RealBasic já trabalhe com as expressões regulares, é muito útil (e poupa muito codigo) deixar que o MySQL as execute. Verá que é possível fazer filtragens até absurdas.
Algo como isolar todos os e-mails de um único provedor e que comesse com "ana" ficaria mais ou menos assim:


>... WHERE Campo REGEXP "ana.+\@globo\.[a-z]{3}"

E a melhor parte:

- Se você usa o LIKE nas suas consultas, pode substitui-lo por RLIKE e abolir o por-cento (%), com a vantagem de poder usar as sintaxe regulares para ampliar suas filtragens de consultas.

Não irei mais a fundo por que outros já o fizeram por mim e merecem todo o credito. Entretanto se quiser ir e se aventurar, a Wikipedia é um bom começo para entender as expressões regulares ou, vá especificamente ao MySQL se preferir.

Temos também o Livro Expressões Regulares - Guia de Consulta Rápida disponível inteiramente grátis na nete. por Aurélio Marinho Jargas. (ou compre o livro se preferir)
Até a aproxima!

25/05/2010

Projeto de Interface com Usuário para Programadores

Navegando aleatoriamente pela internet me deparei com este excelente artigo sobre projeto de interface com usuário para programadores.

Por Joel Spolsky
Traduzido por Rosana de Oliveira

Vale a pena conferir.

Projeto de Interface com Usuário para Programadores



14/05/2010

Consulta MySQL

Aqui está uma coisa que me passou despercebido por um longo tempo.

Em uma consulta aonde eu preciso consultar 2 valores diferentes em uma mesma tabela, sempre recorria a uma sub consulta (SELECT dentro de SELECT). Até que, acidentalmente, descobri que era muito mais simples, e estava sempre ali na minha cara.

Para ilustrar a idéia vamos montar uma situação fictícia:

Em uma empresa altamente setorizada você tem um diretor e um vice diretor para cada setor, entre tanto, ambos são funcionários e estão cadastrados na mesma tabela Pessoas. E uma tabela de setores só contem o ID de cada um e é necessário exibir o nome dos 2 indivíduos em uma lista.

Ex. com sub consulta.



SELECT un.id,
f1.nome AS diretor,
(SELECT nome FROM pessoas WHERE id = un.pessoa) AS vice
FROM unidades AS un
LEFT JOIN pessoas AS f1 ON f1.id = un.pessoa

E a consulta como devia ser:

SELECT un.id,
f1.nome diretor,
f2.nome vice
FROM unidades AS un
LEFT JOIN pessoas f1 ON f1.id = un.pessoa
LEFT JOIN pessoas f2 ON f2.id = un.diretor

Não entrando em questão de performance (que deve levar alguns mili segundos de vantagem), a segunda é bem mais "limpa"

Simples! não é?



17/04/2010

CPF e CNPJ na mesma rotina

Não querendo ser repetitivo, mas já sendo. Vou apresentar uma rotina para calcular o CPF e CNPJ. Só que desta vez tudo em uma coisa só.

Eu não gosto de rotinas extensas muito menos redundantes. Mesmo já tendo ouvido falar que uma rotina mais extensa se torna mais fácil dar manutenção, ainda prefiro olhar varias vezes para um pouquinho de linhas e tentar achar onde está Wally do que ficar rolando a barra de scroll, ou ainda ficar quicando de uma sub-rotina a outra. Então procuro fazer uso dos recursos disponíveis e fazer o menor e mais eficiente código possível.

Nessa rotina de verificação eu organizei as seqüências de cálculos para serem executadas de uma só vez e de modo a calcular tanto o CPF quanto CNPJ.

A primeira atitude tomada por ela é extrair apenas os números do CNP, eliminando qualquer outro tipo de caractere. Em seguida verifica se todos os números são iguais, caso positivo já encerra ali mesmo.

Pela quantidade dos dígitos limpos saberemos se é um CPF ou um CNPJ, assim uma array é carregada com a sequência de valores de calculo para cada tipo, e logo em seguida executa-se o cálculo.

O retorno é verdadeiro ou falso.


Dim Nm(),Mt() As Integer 
Dim i,n As Integer 'Contadores
Dim Dv1, Dv2 As Integer 'Digitos de verificação
Dim chek As Boolean = True 'Controle
Dim vResto As Double 'Resultado
Dim s() As String

s = CNP.Split("") 'Separar todos os caracteres

For i = 0 to s.Ubound 'Deixar apenas numeros
if IsNumeric(s(i)) Then Nm.Append s(i).val
Next

For i = 0 To Nm.Ubound - 2 //numeros iguais: "222.222.222.22"
if Nm(i) = Nm(i + 1) Then n = n + 1
Next
if n = Nm.Ubound - 1 Then Return False 'Sair se todos os numeros forem iguais

Select case Nm.Ubound //Pelo tamanho, sabemos se é um cpf ou cnpj
Case 10 // CNPF "0 a 10 = 11"
Mt = Array(11, 10, 9, 8, 7, 6, 5, 4, 3, 2)
Case 13 // CNPJ "0 a 13 = 14"
Mt = Array(6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2)
Case Else
Return False 'NUMERO NAO É CALCULAVEL
end select

//Primeiro caltulo nos digitos
For i = 0 To Mt.Ubound -1
Dv1 = Dv1 + (Nm(i) * Mt(i + 1))
Dv2 = Dv2 + (Nm(i) * Mt(i))
Next

//Calcular dígito 1
vResto = Dv1 Mod 11
chek = vResto > 1
Dv1 = (11 - vResto) * Abs(Bin(chek).val)

//Calcular digito 2
vResto = (Dv2 + (Dv1 * 2)) Mod 11
chek = (vResto > 1)
Dv2 = (11 - vResto) * Abs(Bin(chek).val)

Return (Nm(Nm.Ubound-1) = Dv1) AND (Nm(Nm.Ubound) = Dv2)

10/04/2010

MySql e Ultimo ID

MySql e Ultimo ID = titulo de filme do velho oeste :)

Em outros tempos e em outras linguagens eu travava a tabelas, inseria e re-consultava.

Mas aqui e agora...

Quando você executar uma instrução INSERT e precisar do ID que esta instrução gerou para qualquer outra coisa é só perguntar para a conexão do MySql.

id = MyCnn.GetInsertID //MyCnn = conexão com banco de dados misql

Você também pode perguntar quantos registros foram afetados por uma instrução com GetAffectedRows (por ex: quantos registros eu deletei?)


29/03/2010

Tocar musica com RealBasic.

Esta quase nem tem graça. é muito fácil!

Dim s as Sound // instância do objeto

s = GetOpenFolderItem("").OpenAsSound //Abre o arquivo de som

if s = Nil Then Return //Encerra se não houver arquivo

s.Play // Toca a musica

Moleza não é ? Bom, mesmo assim vou falar algo a respeito.
A classe Sound apesar de reduzida tem algumas propriedades interessantes, como por exemplo o Pan, onde você pode regular o balanço do stério, o Volume que varia de 0 a 100, o PlayLooping que permite repetir continuamente um som, e sem esquecer do Stop que para o som imediatamente

Com o Stop, eu consegui fazer um telegrafo usando um único beep continuo, apenas variando o tempo de duração que eu queria para cada beep.

Com a propriedade IsPlaying, é possível saber se o som ainda esta tocando, assim um playlist ficará bem simples de ser feita (Quando terminar uma, coloque a próxima da lista).

E isso é tudo p p soal :)

14/03/2010

Componentes dinâmicos

Como adicionar dinamicamente componente em uma janela do RealBasic ?

É comum nos depararmos com a necessidade de adicionarmos campos de texto, botões ou outro componente de tela enquanto o programa está funcionando. Imagine fazer um calendário aonde cada um dos 31 dias seja um botão para selecionar o dia? É muito chato e demorado ter que colocar um por um e ainda levando em conta que eles mudam de lugar a cada mês.

É muito fácil se fazer isso no RealBasic. Só lembrando que o resultado é um Array de controles.

Insira o objeto desejado na tela, Nas propriedades, altere o Index para 0.

Declare uma Variável com o tipo do objeto em questão, em seguida atribua o valor a ela como sendo seu novo objeto.

Dim pb As PushButton
pb = New PushButton1

Em seguida é só alterar as propriedades que desejar e pronto, já temos dois botões na tela.

E para remover o objeto, basta acessar o método close:

PushButton1(n).Close

Para estender o uso sem muito trabalho podemos usar um conjunto de For ... next e criar quantos botões forem

necessário

Exemplo:

Seguindo os passos a cima, coloque um botão em uma janela e defina a sua altura e largura pra 22, e seu caption para 0. No evento Open da janela digite:

Dim x,y,n,c,l,t As integer 'Declarar das variaveis
Dim pb As PushButton 'Declarar objeto
l = PushButton1(0).Left 'Obter posição
t = PushButton1(0).Top
n = 1 'iniciar coluna em 1
for y = 0 to 5 'contar 6 linhas
for x = n to 4 'contar 5 colulas
pb = New PushButton1 'criar novo botão
pb.Left = x * 22 + l 'Posicionar botão
pb.Top = y * 22 + t
c=c+1 'Numero para exibir
pb.Caption = str(c) 'Exibir Numero
next
n=0 'zerar coluna
next
O resultado será similar a este:

23/02/2010

Calculo de idade

É comum nos depararmos com situações em que um programa precisa calcular a idade de alguém ou alguma coisa. Você sabe como isso pode ser feito? Se não sabe, agora vai saber.

A classe Date do RealBasic pode nus devolver o valor de sua data em segundos, o que facilita muito a encontrar uma idade precisa.

Veja esta tabela:

1 Minuto = 1m 60s
1 Hora = 1h 60m 3600s
1 Dia = 1d 24h 1440m 86400s
1 ano = 365.25d 8766h 525960m 31557600s

"Nos deparamos aqui com o POG original como é relatado na Deciclopedia :p"

Note que o ano tem 365.25 dias, em outra conotação, 365 dias e 6horas. Como 6h é um quarto de 24h (1 dia), então ¼ = 0.25. Isto resolve os problemas de cálculos com anos bissextos.

Inutilmente, a saber:
O segundo é a duração de 9.192.631.770 períodos da radiação correspondente à transição entre dois níveis hiperfinos do estado fundamental do átomo de césio 133.

Logo a diferença entre a data atual e a data anterior corresponde a idade em segundos. Que por sua vez dividida pelo Ano em segundos teremos a idade, que é normalmente seguida de um fracionário.

Se este fracionário for isolado e multiplicado por 12 teremos os meses após ultimo aniversário. E assim com os dias (por 24), com as horas (por 60) ..

Dim N As String
Dim Data As Date
Dim Hoje As Date
Dim idade As Double
Dim r as integer

N = "18/09/1975"

Hoje = new Date

//converte texto em data e encerra se o texto não for uma data
if Not ParseDate(n,Data) then Return

//pega a diferensa em segundos entre as duas datas
idade = Hoje.TotalSeconds - Data.TotalSeconds

idade = idade / 31557600 //Calcula a idade em anos
r = Floor(idade) //ignora valores apos o ponto decimal
N = r.Str + " anos "

idade = (idade - r) * 12 //Meses
r = Floor(idade)
N = N + r.Str + " meses "

idade = (idade-r) * 24 //Dias
r = Ceil(idade)
N = N + r.Str + " dias "

MsgBox n

Para os que só copião e colam e depois dizem “não funciona”, vale lembrar que a propriedade Str não é padrão na biblioteca do RB. E é exatamente igual a um CStr() mas como função estendida do tipo inteiro (só pode ser inserida dentro de um modulo global)

Function Str(Extends int As Integer) As String

Return CStr(int)

End Function

Ou substitua r.str por cstr( r )

Até a próxima.