Arquivo da categoria: Programação

Dicas de programação, desenvolvimento de software, linguagens de programação

ADO – Localizando Informações

Quando falamos a nível de dados (campos e registros), estamos tratando com o objeto Recordset. Vamos ver como encontrar dados específicos em um Recordset ADO. Lembrando que um objeto Recordset possui muitas funções úteis, dentre elas, as mais usadas são bookmark, Find, Seek e Filter.

Usando Bookmarks (marcadores)

Um bookmark de um recordset é como um cursor que aponta para um registro específico dentro do Recordset, identificando-o de forma única. Fazendo uma analogia: ao ler um livro, você não costuma usar um marcador para indicar em qual página parou? O bookmark funciona da mesma forma. Para usá-lo em um objeto Recordset, as etapas são as seguintes:

  • Defina uma variável para ser usada como marcador:
    Dim marcador as variant
  • Quando desejar marcar uma posição em um recordset no registro atual usando a variável definida acima, faça:
    marcador = rs.bookmark
  • Para retornar à posição marcada, faça:
    rs.bookmark = marcador

Mas, atenção! Nem todos os registros suportam bookmarks. Para verificar se um recordset suporta bookmarks, use a instrução:

blnmarcador = rs.Supports(adBookmarks)

O método Supports, usando o argumento adBookmark retorna True se o recordset suporta bookmarks e FALSE caso contrário.

Localizando dados com ADO

Basicamente, temos dois métodos para localizar dados em um recordset usando ADO: Find e Seek.

Usando o método Find

O método Find é usado para encontrar um registro que contém um determinado valor em um determinado campo do registro. Você define um critério de busca e se o critério for satisfeito, o ponteiro do registro se posiciona no registro que atendeu o critério, se não, o ponteiro se posiciona no fim do recordset. A sintaxe é:

Find (criterio, SkipRows, searchDirection, star)

onde:

criterio – é uma string contendo o nome da coluna, o operador de comparação e o valor que desejamos localizar. Exemplos:

"FornecedorID >= 7"
"DataPedido = #07/08/2014#"
"Codigo > 7"
"Nome = '" & variavel & "'"

Lembrando que os valores strings devem vir entre aspas simples (‘teste’) e as datas devem ser iniciadas e terminadas com o símbolo (#).

SkipRows – define o deslocamento da linha atual ou o bookmark padrão para iniciar a busca. O padrão é começar na linha atual e terminar na última linha.

searchDirection – indica a direção em que o recordset é percorrido. Os valores podem ser:

adSearchForward ou adSearchBackward – a busca irá parar no início ou no fim do recordset dependendo destes valores. Se a busca é iniciada para frente e nada for encontrado, o cursor do recordset é definido para além do último registro e a propriedade EOF (En Of File) retorna TRUE. Se a busca é feita para trás e nada for achado, o cursor é definido para além do início do arquivo e a propriedade BOF (Beginning Of File) retorna TRUE.

start – define um bookmark de início para a busca.

OBS.: Se você não definir a posição do cursor na linha atual quando for iniciar a busca, irá ocorrer um erro. Por isso, antes de usar o método Find, você pode mover o cursor para o início do arquivo usando o método MoveFirst.

Na prática

  • Inicie um novo projeto no VB e faça referência a biblioteca ADO na opção do menu Project -> References.
  • Insira o codigo abaixo no projeto:
'Define as variáveis objetos que serão usadas para a conexão e para o recordset
Dim cnn As New ADODB.connection
Dim rst As New ADODB.connection

Private Sub Form_Load()

Dim criterio As String

'Abre uma conexão
cnn.Open "Provider=Microsoft.Jet.OLEDB.3.51;Data Source=C:\Northwind.mdb;"

'Abre o recordset
'Definimos o tipo de cursor usado, no caso usamos o cursor do lado do cliente (adUseClient) e abrimos um recordset com os parâmetros adOpenKeyset (permite alteração) e adLockOptimistic (usa bloqueio pessimista, ou seja, mantém o bloqueio até usar o método para atualizar)
rst.CursorLocation = adUseClient
rst.Open "Select * From Suppliers", cnn, adOpenKeyset, adLockOptimistic, adCmdText

'Move para o primeiro registro
rst.MoveFirst

'Define o critério para busca e a inicia com o método Find usando o parâmetro adSearchForward, que busca do início para o fim
criterio = "Country Like 'A%'"

'Inicia busca no recordset
rst.Find criterio, 0, adSearchForward

'Percorre o recordset até o final, imprimindo o campo CompanyName e posicionando a partir do bookmark anterior, com avanço de um registro para frente a partir do bookmark marcador. Note que usamos o bookmark para armazenar a posição atual do registro e usamos esta posição inicial para a próxima busca
While Not rst.EOF
   Debug.Print rs("CompanyName")
   marcador = rst.Bookmark
   rs.Find criterio, 1, adSearchForward, marcador
Wend
End Sub

Usando o método Seek

O método Seek permite procurar em uma coluna. Ele só encontra valores iguais ao valor da procura e precisa de um provedor de dados que permita a utilização da propriedade Index. Além disso, o método Seek requer um cursor do lado do servidor.

Atualmente, somente alguns provedores permitem usar a propriedade Index e o método Seek do objeto Recordset para procurar por valores em um índice de uma tabela. O provedor OLE DB – Provider for Microsoft Jet 4.0 (utilizado para conectar a um banco de dados Access) permite a utilização do método Seek.

Para verificar se o provedor suporta a propriedade Index e o método Seek, utilize o método Supports com os parâmetros adIndex e adSeek.

If rs.Supports(adIndex) then
   msgbox "Este Provedor suporta a propriedade Index"
End If

If rs.Supports(adSeek) then
   msgbox "Este Provedor suporta a propriedade Seek"
End If

É necessário definir a propriedade Index assim que o recordset for aberto para depois usar o método Seek. A propriedade Index indica o nome do índice que estará ativo. Assim, supondo que você possua uma tabela chamada Clientes e queira fazer uma busca pela coluna Nome da tabela, vai precisar definir um índice para esta coluna na tabela dando um nome a ele. O nome do índice pode ser o mesmo do nome da coluna. Para o caso em questão, poderíamos ter criado um índice chamado Nome. Teríamos então:

rs.index = "nome"

Em muitos casos, quando você usa um campo autonumérico no Access e define este campo como uma chave primária, o índice PrimaryKey será criado para esta coluna da tabela. Então, se for usar esta coluna para fazer uma busca usando o Seek, deverá usar a sintaxe:

rs.index = "PrimaryKey"

Depois que a propriedade Index foi definida para o nome do índice existente na tabela, podemos usar o método Seek para procurar na coluna desejada. Quando o método Seek encontrar o registro desejado, o ponteiro irá se posicionar neste registro. Se nada for encontrado, o ponteiro é definido para EOF. A sintaxe é:

rs.Seek Array(ValordaColuna)

Aqui você deve tomar cuidado. Como um índice pode ser constituído de uma ou mais colunas, o termo ValordaColuna indica os valores da coluna. Vamos supor que você tenha uma tabela de Cliente com um campo CodigoID definido como chave primária e queira procurar pelo cliente de código 120. Você deverá procurar pelo valor 120 na coluna CodigoID e deverá fazer:

rs.index = "PrimaryKey"
rs.Seek Array(120)

Se o índice possuir mais de uma coluna, você deverá informar no vetor (array) os valores de todas as colunas contidas no índice. Por exemplo, se uma tabela Pedidos possuir um índice chamado PrimaryKey e for constituído pelos campos CodigoPedido e CodigoProduto, ao usar o método Seek para procurar pelo pedido 23 e código de produto igual a 50, você deverá fazer:

rs.index = "PrimaryKey"
rs.Seek Array(23, 50)

Vejamos agora um exemplo completo usando a propriedade Index e o método Seek. Neste exemplo usaremos o banco de dados Northwind.mdb e a tabela Funcionários. A estrutura e os índices criados são dados abaixo.

Iremos usar o índice chave primária CodigoDoFuncionario para localizar o funcionário e exibir o seu nome.

O projeto usará um formulário, uma caixa de texto e um botão de comando.

Defina as variáveis objeto na seção General Declarations.

Dim cnn As New ADODB.connection
Dim rst As New ADODB.Recordset

O código do botão de comando é:

Private Sub Command1_Click()
If Text1.Text = "" Then
   MsgBox "Informe um valor para a busca"
   Exit Sub
End If

'Abre a conexão
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Northwind.mdb;"

'Abre o recordset
rst.CursorLocation = adUseServer
rst.Open "Funcionarios", cnn, adOpenKeyset, adLockReadOnly, adCmdTableDirect

If rst.Supports(adIndex) And rst.Supports(adSeek) then
   rst.index = "CodigoDoFuncionario"
   rst.MoveFirst
   rst.Seek Array(CLng(Text1.Text))

   If rst.EOF Then
      MsgBox "Funcionário não localizado"
   Else
      MsgBox rst("CodigoDoFuncionario") & " - " & rst("nome") & vbCrLf
   End If
Else
   MsgBox "O Provedor utilizado não suporta Index e Seek"
End If

rst.Close
cnn.Close

Set rs = Nothing
Set cnn = Nothing

End Sub

Observe que antes de iniciar a busca, verificamos se o provedor suporta a utilização de Index e Seek. Se o método Supports é novo para você, ele pode ser usado com as seguintes constantes:

  • adAddNew – verifica se novos registros podem ser adicionados
  • adApproxPosition – verifica se as propriedades AbsolutePage e AbsolutePosition estão disponíveis
  • adBookMark – verifica se podemos usar um marcador no recordset
  • adDelete – verifica se os registros poderão ser excluídos
  • adHoldRecords – verifica se podemos recuperar os registros sem submeter as alterações
  • adResync – verifica se o método Resynd está disponível
  • adUpdate – verifica se o conjunto de registros permite a atualização
  • adUpdateBatch – verifica se o recordset permite a atualização em lote (via UpdateBatch)

Bug ao Compactar e Reparar

Há bastante tempo, uma falha grave no utilitário Compactar e Repara Banco de Dados no Access 2007 vem pegando de surpresa muitos programadores. O que acontece é que, no meio do processo, o Access para e apresenta a mensagem:

O Microsoft Office Access não pode excluir C:\SuaPasta\SeuBD.accdb após compactá-lo. O banco de dados compactado foi nomeado como C:\SuaPasta\BancodeDados.mdb

O Access, no seu processo normal de compactação e reparação, cria um novo arquivo com todos os objetos, deleta o arquivo original e renomeia a cópia, que passa a ser o seu novo arquivo.

Quando a falha do Access acontece e gera a mensagem de erro acima, o que se percebe é que ele deletou o arquivo original mas não conseguiu renomear o arquivo copiado, que está íntegro. Se você tiver a infelicidade de clicar no botão OK da mensagem, ele também irá deletar esta cópia e você perderá o seu banco de dados definitivamente. E se você não tiver uma cópia de backup…..

Então, como proceder caso aconteça esta falha?

NÃO CLIQUE NO OK EM HIPÓTESE ALGUMA.

Vá na pasta de origem do aplicativo e salve o arquivo que o Access nomeou como BancodeDados.mdb.

Com a cópia realizada, você poderá clicar no OK da mensagem. Renomeie esta cópia salva para o nome original do banco de dados do seu aplicativo, incluindo a alteração da extensão para accdb, se for o caso, e pronto.

Existe correção para este bug?

A Microsoft lançou uma correção (hotfix 950812) em abril de 2008, mas não está disponível para download diretamente. Ao acessar a opção de solicitação de download, aparece a tela abaixo:

Observe que o quadro informa que esta correção estaria sendo lançada no SP2.

De fato, a incidência desse problema diminui consideravelmente após a atualização do SP2, mas não o resolve definitivamente.

Tem alguma forma de se evitar esse problema?

Parece que o principal problema está relacionado com erros não verificados no código VBA.

Siga os seguintes procedimentos:

  • Realize uma cópia de segurança sempre que fizer alterações no seu banco de dados;
  • Após realizar alterações no seu código, use imediatamente o compilar do VBA para sanar quaisquer erros de sintaxe e/ou comandos cometidos;
  • Com o código devidamente compilado, você poderá usar o compactar e reparar.
  • Após ter compilado e compactado, você pode ativar o compactar e reparar ao sair, se o desejar.

Comandos chgrp e chown

A segurança em sistemas Linux (e Unix em geral) é constituída a partir dos conceitos de propriedade dos arquivos e de permissões de arquivos. Neste artigo estudaremos a posse dos arquivos, falando sobre Proprietário e Grupo de um arquivo.

Cada arquivo (e diretório) tem um proprietário individual, geralmente o usuário que o criou, e um grupo com o qual é associado – o “grupo do arquivo”.

Cada grupo pode ter diversos usuários como membros, o que combinado com o conceito de proprietário dos arquivos nos permite fornecer três camadas para controle de acesso aos arquivos e diretórios: usuário proprietário do arquivo, grupo do arquivo, e todos os demais usuários – os “outros”.

Podemos verificar quem é o proprietário de um arquivo ou diretório e seu grupo padrão usando o comando ls com a opção de listagem longa (-l):

ls -l

comando-ls-linux

Observe que no exemplo, todas as pastas e o arquivo curriculum são de propriedade do usuário fabio e estão associados ao grupo fabio. A primeira coluna da esquerda para a direita, logo após a string de permissões (caracteres r, w, x e -) mostra o usuário proprietário e a coluna seguinte, ao lado do tamanho dos arquivos, é o grupo.

Podemos perceber também que ambos são iguais – o nome do proprietário e o grupo – pois este é um comportamento padrão do sistema: quando um usuário cria um arquivo, automaticamente o arquivo é associado ao grupo padrão do usuário.

Vejamos agora como alterar o proprietário de um arquivo e seu grupo associado.

Alterando o proprietário de um arquivo – Comando chown

Podemos alterar o proprietário de um arquivo usando o comando chown (“change owner”). Somente o usuário root pode efetuar essa alteração.

Sintaxe:

chown [opções][novo_proprietátio][:novo_grupo] nomes_arquivos

Veja que o comando chown também permite alterar o grupo associado dos arquivos indicados.

Por exemplo, vamos alterar o proprietário do arquivo curriculum para um usuário chamado renata (já existente no sistema):

sudo chown renata curriculum

comando-chown-linux

Podemos também alterar o grupo do arquivo juntamente com o usuário. Por exemplo, vamos alterar o usuário do arquivo curriculum para ana e seu grupo para marketing ao mesmo tempo:

sudo chown ana:marketing curriculum

comando-chown-linux-ubuntu

Há poucas opções disponíveis para o comando chown, mas uma das mais úteis é a opção -R ou –recursive, que permite alterar a propriedade do arquivo em uma árvore de diretórios inteira.

Tomemos como exemplo o diretório planilhas que contém 5 arquivos de planilhas, todas pertencentes ao usuário fabio:

comando-ls-linux-ubuntu

Queremos alterar o proprietário do diretório e  todos esses arquivos para a usuária renata, de uma vez. Usaremos então a opção –recursive (ou -R) para isso:

sudo chown -recursive renata ./planilhas

comando-chown-linux-debian

Veja que todas as planilhas passaram a ser propriedade da usuária renata.

Se um usuário for removido, os arquivos dos quais esse usuário era proprietário se mantém no sistema, e no lugar do nome do proprietário aparecerá o UID que o usuário possuía. Por exemplo, vamos excluir a usuária renata e depois verificar como ficou a posse de seus arquivos:

comando-ls-linux-debian

Agora, o usuário proprietário dos arquivos mostra apenas o número 1001, que era o UID do usuário renata.

Alterando o grupo de um arquivo – Comando chgrp

Para alterar apenas o grupo de um arquivo usaremos o comando chgrp, que pode ser executado pelo root (sempre) ou por um usuário comum (desde que o grupo seja alterado para um grupo ao qual o usuário pertença).

Sintaxe:

chgrp [opções] novo_grupo arquivos

As opções do comando chgrp são similares às do comando chown, como por exemplo a opção -R (–recursive).

Exemplos:

Vamos alterar o grupo do arquivo planilha-01 para o grupo marketing com o comando chgrp:

sudo chgrp marketing planilha-01

comando-chgrp-linux-ubuntu

Num próximo artigo veremos como controlar o acesso a arquivos alterando suas permissões de acesso.

Escrevendo com PHP

Este post é bem básico, pois é destinado a quem está começando com PHP.

O primeiro passo para começar a programar com PHP é inicializar o servidor, como vimos em post anterior.

Após inicializar o servidor temos que abrir um editor para escrever nosso código. Vamos usar um bem simples, o Bloco de Notas.

Todo código PHP deve obrigatoriamente estar entre as tags <?php ?>.

Escrevendo o primeiro código

Dentro do Bloco de Notas digite o seguinte comando:

<?php
  echo 'Escrevendo meu primeiro comando';
?>

Após escrever o primeiro comando, salve o arquivo dentro da pasta do servidor para que seja possível visualizar o resultado no navegador.

Clique em Arquivo > Salvar.

Na opção Tipo, altere para Todos os arquivos (*.*), como mostra na imagem abaixo.

php-comandos-echo

 

 

 

 

 

 

 

 

Selecione o local onde este arquivo deve ser salvo. O Xampp tem uma pasta especifica chamada htdocs, que é onde ficam os projetos/arquivos salvos para visualização no navegador.

Selecione o diretório C:/xampp/htdocs

Observação: Se você instalou o servidor em outro diretório, seu caminho pode ser diferente.

Digite o seguinte nome comandoecho.php, não esquecendo de digitar o ‘.php’.

Sua tela deve estar assim:

php-comandos-echo-salvando

Clique em Salvar.

Para visualizar o resultado do código, abra o navegador.

Digite o seguinte endereço: http://localhost/comandoecho.php

php-comandos-echo-navegador

 

Instalando Servidor Xampp para Trabalhar com PHP

Neste post vou mostrar como preparar o seu computador para testar os projetos desenvolvidos em PHP. Existem vários programas que simulam um servidor de hospedagem dentro do próprio computador, não sendo necessária a contratação de um servidor de hospedagem durante o desenvolvimento dos projetos.

Vamos aprender a instalar o Xampp, um ótimo servidor local que nos auxilia no momento de testar os projetos.

Instalando servidor PHP – Xampp

Para baixar o Xampp para Windows clique aqui. Você também pode acessar o site oficial do Xampp para buscar versões mais novas ou para outros sistemas operacionais.

Após baixar o instalador do Xampp, execute o arquivo dando dois cliques no mesmo no local onde ele foi salvo. Irá surgir a seguinte tela:

php-servidor-xamp-loading

Aguarde o carregamento. Em seguida irá surgir a tela para selecionar o idioma:

php-servidor-xamp-idioma

Selecione o idioma que melhor ser adapte ao seu conhecimento e clique em OK.

Na tela seguinte, o instalador dá boas vindas:

php-servidor-xamp-welcome

Basta clicar em Next.

Na tela Choose Components, deixe todos os recursos selecionados e clique em Next.

php-servidor-xamp-components

Por padrão, o Xampp instala todos os seus arquivos dentro de uma pasta com seu nome no “C:” do computador. Se preferir, podemos alterar este caminho.

php-servidor-xamp-location

Depois clique em Install e aguarde até o final da instalação. Em seguida, clique em Finish.

Irá aparecer uma janela como a seguinte:

php-servidor-xamp-inicializar

Clique em Sim para iniciar o Painel de Controle do Xampp.

Iniciando o servidor local

Toda vez que formos trabalhar com um projeto PHP, temos que iniciar os serviços do servidor local. Vejamos.

Após a instalação, foi criado um ícone na área de trabalho do computador como a imagem abaixo:

php-servidor-xamp-icone

Clique duas vezes e abrirá a seguinte tela:

php-servidor-xamp-control

Nesta tela, clique em Start para Apache e para MySQL. Sua tela deverá ficar assim:

php-servidor-xamp-control2

Obs.: Se for a primeira vez que estiver fazendo esta ação, o Windows irá pedir permissão para o usuário. Irá aparecer as seguintes telas:

php-servidor-xamp-permissao1

php-servidor-xamp-permissao2

Basta clicar em Permitir Acesso.

Pronto! Servidor inicializado e pronto para testar seus projetos em PHP.

Animation: bounce

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Label;
import java.awt.Panel;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.text.NumberFormat;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Bouncer extends JPanel implements Runnable {
private boolean trucking = true;

private long[] previousTimes; // milliseconds

private int previousIndex;

private boolean previousFilled;

private double frameRate; // frames per second

private Image image;

public static void main(String[] args) {
final Bouncer bouncer = new Bouncer();
Frame f = new AnimationFrame(bouncer);
f.setFont(new Font("Serif", Font.PLAIN, 12));
f.setSize(200, 200);
Panel controls = new Panel();
controls.add(bouncer.createCheckbox("Anti.", Bouncer.ANTIALIASING));
controls.add(bouncer.createCheckbox("Trans.", Bouncer.TRANSFORM));
controls.add(bouncer.createCheckbox("Gradient", Bouncer.GRADIENT));
controls.add(bouncer.createCheckbox("Outline", Bouncer.OUTLINE));
controls.add(bouncer.createCheckbox("Dotted", Bouncer.DOTTED));
controls.add(bouncer.createCheckbox("Axes", Bouncer.AXES));
controls.add(bouncer.createCheckbox("Clip", Bouncer.CLIP));
f.add(controls, BorderLayout.NORTH);

f.setVisible(true);
}

// Tweakable variables
private boolean mAntialiasing, mGradient, mOutline;

private boolean mTransform, mDotted, mAxes, mClip;

// ...and the constants that represent them. See setSwitch().
public static final int ANTIALIASING = 0;

public static final int GRADIENT = 1;

public static final int OUTLINE = 2;

public static final int TRANSFORM = 3;

public static final int DOTTED = 4;

public static final int AXES = 5;

public static final int CLIP = 6;

private float[] mPoints;

private float[] mDeltas;

private float mTheta;

private int mN;

private Shape mClipShape;

public Bouncer() {
previousTimes = new long[128];
previousTimes[0] = System.currentTimeMillis();
previousIndex = 1;
previousFilled = false;

mN = 38;
mPoints = new float[mN];
mDeltas = new float[mN];
Random random = new Random();
for (int i = 0; i < mN; i++) {
mPoints[i] = random.nextFloat() * 500;
mDeltas[i] = random.nextFloat() * 3;
}

addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce) {
Dimension d = getSize();
for (int i = 0; i < mN; i++) {
int limit = ((i % 2) == 0) ? d.width : d.height;
if (mPoints[i] < 0)
mPoints[i] = 0;
else if (mPoints[i] >= limit)
mPoints[i] = limit - 1;
}
}
});
}

public void setSwitch(int item, boolean value) {
switch (item) {
case ANTIALIASING:
mAntialiasing = value;
break;
case GRADIENT:
mGradient = value;
break;
case OUTLINE:
mOutline = value;
break;
case TRANSFORM:
mTransform = value;
break;
case DOTTED:
mDotted = value;
break;
case AXES:
mAxes = value;
break;
case CLIP:
mClip = value;
break;
default:
break;
}
}

protected Checkbox createCheckbox(String label, final int item) {
Checkbox check = new Checkbox(label);
check.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent ie) {
setSwitch(item, (ie.getStateChange() == ie.SELECTED));
}
});
return check;
}

public void timeStep() {
Dimension d = getSize();
for (int i = 0; i < mN; i++) {
float value = mPoints[i] + mDeltas[i];
int limit = ((i % 2) == 0) ? d.width : d.height;
if (value < 0 || value > limit) {
mDeltas[i] = -mDeltas[i];
mPoints[i] += mDeltas[i];
else
mPoints[i] = value;
}
mTheta += Math.PI / 192;
if (mTheta > (2 * Math.PI))
mTheta -= (2 * Math.PI);
}

public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
setAntialiasing(g2);
setClip(g2);
setTransform(g2);
Shape shape = createShape();
setPaint(g2);

g2.fill(shape);

if (mOutline) {
setStroke(g2);
g2.setPaint(Color.blue);
g2.draw(shape);
}
drawAxes(g2);
}

protected void setAntialiasing(Graphics2D g2) {
if (mAntialiasing == false)
return;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}

protected void setClip(Graphics2D g2) {
if (mClip == false)
return;
if (mClipShape == null) {
Dimension d = getSize();
FontRenderContext frc = g2.getFontRenderContext();
Font font = new Font("Serif", Font.PLAIN, 144);
String s = "Java Source and Support!";
GlyphVector gv = font.createGlyphVector(frc, s);
Rectangle2D bounds = font.getStringBounds(s, frc);
mClipShape = gv.getOutline(
(d.width - (float) bounds.getWidth()) / 2,
(d.height + (float) bounds.getHeight()) / 2);
}
g2.clip(mClipShape);
}

protected void setTransform(Graphics2D g2) {
if (mTransform == false)
return;
Dimension d = getSize();
g2.rotate(mTheta, d.width / 2, d.height / 2);
}

protected Shape createShape() {
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD,
mPoints.length);
path.moveTo(mPoints[0], mPoints[1]);
for (int i = 2; i < mN; i += 6)
path.curveTo(mPoints[i], mPoints[i + 1], mPoints[i + 2],
mPoints[i + 3], mPoints[i + 4], mPoints[i + 5]);
path.closePath();
return path;
}

protected void setPaint(Graphics2D g2) {
if (mGradient) {
GradientPaint gp = new GradientPaint(0, 0, Color.yellow, 50, 25,
Color.red, true);
g2.setPaint(gp);
else
g2.setPaint(Color.orange);
}

protected void setStroke(Graphics2D g2) {
if (mDotted == false)
return;

Stroke stroke = new BasicStroke(1, BasicStroke.CAP_BUTT,
BasicStroke.JOIN_ROUND, 10, new float[] { 4, 4 }, 0);
g2.setStroke(stroke);
}

protected void drawAxes(Graphics2D g2) {
if (mAxes == false)
return;
g2.setPaint(getForeground());
g2.setStroke(new BasicStroke());
Dimension d = getSize();
int side = 20;
int arrow = 4;
int w = d.width / 2, h = d.height / 2;
g2.drawLine(w - side, h, w + side, h);
g2.drawLine(w + side - arrow, h - arrow, w + side, h);
g2.drawLine(w, h - side, w, h + side);
g2.drawLine(w + arrow, h + side - arrow, w, h + side);
}

public void run() {
while (trucking) {
render();
timeStep();
calculateFrameRate();
}
}

protected void render() {
Graphics g = getGraphics();
if (g != null) {
Dimension d = getSize();
if (checkImage(d)) {
Graphics imageGraphics = image.getGraphics();

imageGraphics.setColor(getBackground());
imageGraphics.fillRect(0, 0, d.width, d.height);
imageGraphics.setColor(getForeground());

paint(imageGraphics);

g.drawImage(image, 0, 0, null);

imageGraphics.dispose();
}
g.dispose();
}
}

// Offscreen image.
protected boolean checkImage(Dimension d) {
if (d.width == 0 || d.height == 0)
return false;
if (image == null || image.getWidth(null) != d.width
|| image.getHeight(null) != d.height) {
image = createImage(d.width, d.height);
}
return true;
}

protected void calculateFrameRate() {
// Measure the frame rate
long now = System.currentTimeMillis();
int numberOfFrames = previousTimes.length;
double newRate;
// Use the more stable method if a history is available.
if (previousFilled)
newRate = (double) numberOfFrames
/ (double) (now - previousTimes[previousIndex]) * 1000.0;
else
newRate = 1000.0 / (double) (now - previousTimes[numberOfFrames - 1]);
firePropertyChange("frameRate", frameRate, newRate);
frameRate = newRate;
// Update the history.
previousTimes[previousIndex] = now;
previousIndex++;
if (previousIndex >= numberOfFrames) {
previousIndex = 0;
previousFilled = true;
}
}

public double getFrameRate() {
return frameRate;
}

// Property change support.
private transient AnimationFrame mRateListener;

public void setRateListener(AnimationFrame af) {
mRateListener = af;
}

public void firePropertyChange(String name, double oldValue, double newValue) {
mRateListener.rateChanged(newValue);
}

}

class AnimationFrame extends JFrame {
private Label mStatusLabel;

private NumberFormat mFormat;

public AnimationFrame(Bouncer ac) {
super();
setLayout(new BorderLayout());
add(ac, BorderLayout.CENTER);
add(mStatusLabel = new Label(), BorderLayout.SOUTH);
// Create a number formatter.
mFormat = NumberFormat.getInstance();
mFormat.setMaximumFractionDigits(1);
// Listen for the frame rate changes.
ac.setRateListener(this);
// Kick off the animation.
Thread t = new Thread(ac);
t.start();
}

public void rateChanged(double frameRate) {
mStatusLabel.setText(mFormat.format(frameRate) + " fps");
}
}

Data Manager – Banco de Dados, Tabelas, Índices, Relacionamentos e Chaves Primárias

Criando um Banco de Dados

Para criar um banco de dados com o Data Manager, execute o Data Manager e selecione a opção File/New Database no menu principal. Um diálogo no padrão Salvar Como será aberto solicitando o nome do arquivo. Informe o nome do banco de dados que deseja criar, por exemplo Controle. A janel Tables/QueryDefs da figura abaixo surge; seu banco de dados já está criado e você está pronto para criar suas tabelas.

Criando uma Tabela

Para criar uma tabela com o Data Manager, proceda da seguinte forma: clique no botão New da janela Tables/QueryDefs e no diálogo Add Table mostrado abaixo.

Siga os seguintes passos:

  1. Informe o nome da tabela na caixa de texto Name
  2. Informe o nome do campo na caixa de texto Field Name
  3. Selecione o tipo de dado apropriado na caixa de combinação Data Type
  4. Digite o tamanho do campo, no caso do tipo Text, na caixa de texto Size
  5. Clique no botão > para incluir o campo na tabela
  6. Repita os passos 2 a 5 até que todos os campos da tabela estejam definidos e clique no botão OK para criá-la.

Alterando a Estrutura de uma Tabela

Para definir propriedades não obrigatórias de uma tabela, clique no botão Design da janela Tables/QueryDefs. O Data Manager abrirá a janela Table Editor, mostrada na figura abaixo.

Na janela Editor você pode:

  • Editar as propriedades de qualquer campo selecionado. Neste caso, os dados existentes serão perdidos.
  • Adicionar e remover campos.
  • Criar, remover e alterar índices.

Para definir as propriedades opcionais dos campos de uma tabela, selecione o campo e clique no botão Edit da janela Table Editor. O Data Manager abrirá a janela abaixo. Basta alterar as propriedades desejadas para o campo editado.

Obs.: O Data Manager não admite a edição de um campo componente de uma expressão de índice ou de um relacionamento. Nestes casos, é obrigatória a remoção do índice ou do relacionamento.

Criando e Editando Índices

A criação de um índice de uma tabela no Data Manager é simples. Basta selecionar a janela Table Editor, clicar no botão Indexes e seguir os passos:

  1. Informar o nome do índice na caixa de texto Index Name
  2. Definir as propriedades do índice, marcando as caixas de verificação apropriadas
  3. Selecionar os campos componentes na caixa de listagem apropriada
  4. Selecionar a ordem do índice, se ascendente ou descendente, clicando no botão de comando indicado

Definindo Relacionamentos

Para visualizar ou definir relacionamentos entre os campos das tabelas de um banco de dados, clique no botão Relations na janela Tables/QueryDefs e siga os passos:

  • Selecione a tabela primária na caixa de combinação Primary Table
  • Selecione a tabela dependente na caixa de combinação Related Table
  • Defina o tipo de relacionamento, selecionando o botão de opção apropriado na caixa de grupo Type
  • Selecione a chave externa na caixa de combinação Select Matching Fields
  • Marque, se for o caso, a caixa de verificação indicando se a integridade referencial dos dados deve ser garantida]

Obs.: Para definir um relacionamento, é indispensável que o campo origem seja a chave primária da tabela primária. Além disso, o campo definido como chave externa deve ser do mesmotipo de dado da chave primária.

Definindo uma Chave Primária

Para definir uma chave primária, selecione o botão Keys (janela Table Editor) e o Data Manager abre o diálogo mostrado na figura abaixo, onde a chave pode ser definida clicando-se e selecionado-a da lista Primary.

Bounce Thread

/**
* @version 1.20 1999-04-25
* @author Cay Horstmann
*/

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BounceThread {
public static void main(String[] args) {
JFrame frame = new BounceThreadFrame();
frame.show();
}
}

class BounceThreadFrame extends JFrame {
public BounceThreadFrame() {
setSize(300, 200);
setTitle("Bounce");

addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});

Container contentPane = getContentPane();
canvas = new JPanel();
contentPane.add(canvas, "Center");
JPanel p = new JPanel();
addButton(p, "Start", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
Ball b = new Ball(canvas);
b.start();
}
});

addButton(p, "Close", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
canvas.setVisible(false);
System.exit(0);
}
});
contentPane.add(p, "South");
}

public void addButton(Container c, String title, ActionListener a) {
JButton b = new JButton(title);
c.add(b);
b.addActionListener(a);
}

private JPanel canvas;
}

class Ball extends Thread {
public Ball(JPanel b) {
box = b;
}

public void draw() {
Graphics g = box.getGraphics();
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}

public void move() {
if (!box.isVisible())
return;
Graphics g = box.getGraphics();
g.setXORMode(box.getBackground());
g.fillOval(x, y, XSIZE, YSIZE);
x += dx;
y += dy;
Dimension d = box.getSize();
if (x < 0) {
x = 0;
dx = -dx;
}
if (x + XSIZE >= d.width) {
x = d.width - XSIZE;
dx = -dx;
}
if (y < 0) {
y = 0;
dy = -dy;
}
if (y + YSIZE >= d.height) {
y = d.height - YSIZE;
dy = -dy;
}
g.fillOval(x, y, XSIZE, YSIZE);
g.dispose();
}

public void run() {
try {
draw();
for (int i = 1; i <= 1000; i++) {
move();
sleep(5);
}
catch (InterruptedException e) {
}
}

private JPanel box;

private static final int XSIZE = 10;

private static final int YSIZE = 10;

private int x = 0;

private int y = 0;

private int dx = 2;

private int dy = 2;
}

Banco de Dados: Introdução

Podemos entender por banco de dados qualquer sistema que reúna e mantenha organizada uma série de informações relacionadas a um determinado assunto em uma determinada ordem.

A lista telefônica é um exemplo. Nela, percebemos que todos os dados referentes a uma pessoa estão na mesma linha. A isso chamamos registros.

O tipo ou categoria da informação (nome, telefone, etc.) sobre uma pessoa está separada em colunas, as quais chamamos campos.

Um Sistema Gerenciador de Banco de Dados Relacionais (SGBDR) é usado para armazenar as informações de uma forma que permita às pessoas examiná-las de diversas maneiras.

O Gerenciador Relacional de Bancos de Dados do Visual Basic e do Access é o Microsoft Jet. Ele pertence a uma categoria diferente dos gerenciadores tradicionais, como o Dbase e o Paradox, pois possui características em comum com os bancos de dados cliente-servidor. Tais características comuns são:

  • Todas as tabelas, índices, consultas, relatórios e código são armazenados num único arquivo MDB
  • Os campos de data suportam informação de hora
  • Admite o armazenamento permanente de comandos SQL
  • É possível forçar a integridade referencial entre tabelas
  • Os campos suportam valores nulos (Null)

No Dbase/Clipper, banco de dados significa um arquivo que contém a estrutura de dados (campos) e os dados (arquivo padrão DBF). Para o padrão MDB, este conjunto de dados e sua estrutura denomina-se Tabela.

Portanto, aquilo que o Dbase/Clipper considera um banco de dados, o Access e o Visual Basic consideram como uma tabela.

Podemos então definir tabela como um conjunto de dados dispostos em forma de linhas e colunas. Como exemplo, vejamos a tabela de endereços abaixo:

Nome Endereço Telefone
Carlos Lima Bueno Rua Pindamonhangaba , 1200 226-2356
Carlos Lima Buel Rua Voluntários de São Paulo , 2785 224-1078
Carlos Luiz Moraes Rua D. Pedro II , 123 223-0991

As linhas da tabela são os registros (nome, endereço, telefone) e as colunas são os campos. A interseção de uma linha com uma coluna define um atributo representando um valor do campo. Para a tabela representada acima, a interseção da segunda linha com a coluna nome define o valor do campo nome como Carlos Lima Buel.

Para o Access e o Visual Basic, todos os componentes do sistema estão em um único arquivo com extensão MDB. A este “pacote” consideramos o banco de dados, o qual é um conjunto das tabelas nele contidas.

Logo, quando abrimos um arquivo MDB, temos acesso a todos os componentes do sistema: tabelas, consultas, macros, relatórios, etc. A esses componentes chamamos objetos do sistema e em resumo, podemos descrevê-los a seguir:

Tabelas Onde armazenamos as informações que queremos tratar
Consultas Filtram as informações das tabelas e permitem sua visualização.Geralmente são comandos SQL
Formulários São janelas destinadas à edição e visualização dos dados
Relatórios Organizam os dados de tabelas e consultas de uma maneira que possam ser impressos
Macros Rotinas que automatizam determinadas tarefas sem necessidade de programação (utilizadas no Access)
Módulos Armazenam instruções e comandos da linguagem Access Basic/VBA e permitem melhorar e expandir os recursos do sistema

Obs.: Embora o Visual Basic utilize arquivos padrão MDB, formulários, relatórios e módulos são tratados de forma diferente pelo próprio Visual Basic e, nativamente, o Visual Basic não utiliza Macros. Além disso, no Access e Visual Basic, podemos utilizar outros arquivos além dos arquivos MDB, como arquivos DBF do Dbase/Clipper, arquivos do Paradox, do Btrieve, etc.

Os recursos de definição de dados do mecanismo Jet permitem a criação, a modificação e a exclusão de tabelas, índices e consultas. O Jet também aceita a validação de dados em nível de campo e registro. A integridade de dados tem suporte sob a forma de chaves primárias e integridade referencial entre tabelas.

Para manipulação de dados, o Jet admite o uso da SQL e de objetos de acesso aos dados. Esses objetos permitem ao programador manipular informações contidas no banco de dados através da definição das propriedades dos objetos e pela execução dos métodos associados aos objetos. A tabela abaixo relaciona esses objetos e descreve resumidamente suas funções:

Objeto Descrição
DBengine O objeto que referencia o mecanismo de bancos de dados do Microsoft Jet
Workspace Uma área na qual o usuário pode trabalhar com os bancos de dados
Database Uma coleção de informações organizadas em tabelas, juntamente com informações a respeito de índices e relações sobre as tabelas
TableDef Uma definição da estrutura física de uma tabela de dados
QueryDef Uma consulta armazenada de SQL das informações contidas no banco de dados.
Recordset Uma coleção de registros de informações sobre um único tópico
Field Uma única unidade de informações em um banco de dados
Index Uma lista ordenada de registros em um recordset, baseada em um campo chave definido
Relation Informações armazenadas a respeito do relacionamento entre duas tabelas

O poder da SQL

A linguaguem SQL (Structured Query Language) é uma linguagem de alto nível para manipulação de dados dentro do modelo relacional. Seu objetivo é fornecer uma interface de alto nível ao usuário. É uma linguagem não procedural e não cabe ao usuário definir como o gerenciador de banco de dados executará uma tarefa, mas somente o que ele deve fazer.

Uma instrução SQL consiste de três partes:

  • As declarações de parâmetros
  • A instrução manipulativa
  • As declarações de opções

Para termos uma idéia do seu poder, imagine que temos que atualizar o campo valor em 10% de uma tabela com diversos registros. Na abordagem procedural, teríamos os seguintes passos:

  1. Abrir a tabela
  2. Posicionar o ponteiro no início da tabela
  3. Atualizar o campo valor em 10%
  4. Mover o ponteiro para o próximo registro
  5. Continuar a atualização do campo valor até o final da tabela

O código poderia ter o seguinte aspecto:

Dim db as database
Dim tabela as recordset
set db=workspaces(0).Opendatabase(“c:base.mdb”)
set tabela=db.Openrecordset(“tabela”)
While not tabela.eof

tabela.edit
tabela.valor=tabela.valor*1.10
tabela .update
tabela.movenext

Wend
tabela.close

Agora utilizando uma instrução SQL, teríamos o seguinte trecho de código:

Dim db as Database
Set db=Workspaces(0).Opendatabase(“c:base.mdb”)
db.execute “UPDATE tabela SET valor=valor*1.10”
db.close

Observe a utilização da instrução SQL UPDATE, bem mais simples, não é?
Então, se você não está utilizando a SQL, está trabalhando muito e seu código sofrendo as consequências.

Veja na tabela abaixo um resumo das cláusulas manipulativas e suas finalidades:

Instrução Função
SELECT Obtém um grupo de registros e insere os registros em um dynaset ou em uma tabela
UPDATE Define os valores dos campos de uma tabela em uma atualização
TRANSFORM Cria uma tabela de resumo, utilizando o conteúdo de um campo como cabeçalho de cada coluna
DELETE FROM Remove registros de uma tabela
INSERT INTO Acrescenta um grupo de registros a uma tabela.

Veja alguns exemplos da instrução SELECT:

1) Seleciona os campos “Primeiro nome” e “Sobrenome” de todos os registros da tabela Empregados.

SELECT [Primeiro nome], [Sobrenome] FROM Empregados

2) Seleciona todos os campos da tabela Empregados. Note o uso parâmetro (*) indicando todos os campos da tabela indicada.

SELECT Empregados.* FROM Empregados

3) Conta o número de registros que têm uma entrada no campo “Código postal” e coloca o título Contagem no topo da coluna.

SELECT Count([Código postal]) AS Contagem FROM Clientes

4) Seleciona os campos “Primeiro nome” e “Sobrenome” de cada registro cujo sobrenome seja Pereira.

SELECT [Primeiro nome], [Sobrenome] FROM Empregados WHERE [Sobrenome] = ‘Pereira’

5) Seleciona os campos “Primeiro nome” e “Sobrenome” para Empregados cujos sobrenomes começam pela letra S.

SELECT [Primeiro nome], [Sobrenome] FROM Empregados WHERE [Sobrenome] Like ‘S*’

FROM – indica as tabelas utilizadas como fonte de dados

WHERE – especifica as condições que os registros devem satisfazer para compor o subconjunto de dados.