Li Xiaoping/Universidade dos Trabalhadores do Petróleo do Norte da China em Gu'an, província de Hebei
---- Não importa que tipo de programa seja desenvolvido, a entrada de dados é indispensável. A geração rápida de uma bela interface de entrada, sem dúvida, melhorará muito a eficiência do desenvolvimento do programa. Os controles originais do sistema são muitas vezes insatisfatórios. No Delphi, se for para um determinado campo, os controles opcionais são DBLabel, DBEdit, etc.; se for para entrada de toda a tabela, existe o DBGrid. Ao usar controles como o Dbedit, os usuários devem organizar totalmente as posições de cada campo. Embora possa obter belos efeitos, sem dúvida será muito problemático se houver muitos campos. Se o DBGrid for usado, não importa quantos campos existam, apenas um controle é suficiente. É simples, mas os campos são organizados um por um, o que é um pouco inconveniente de usar. Para usuários comuns, a entrada em forma de tabela é conveniente e bonita. Este é o problema que este artigo pretende resolver.
---- Chave técnica
----A principal função deste controle é editar campos do banco de dados. De acordo com as regras gerais, o controle deve conter um objeto TdataLink e implementar uma série de métodos relacionados ao TdataLink, porém, que consumirão muito código; Quanto maior a quantidade de código, mais complexo será o sistema e maior será o potencial de erros. A ideia de desenvolvimento deste controle é alcançar o máximo de funções com o mínimo de código. Portanto, edite os campos de dados diretamente usando o controle TDBComboBox.
---- Para alcançar a universalidade, uma matriz de controle de edição de campo e uma matriz de título de campo são mantidas dentro do controle. do seguinte modo:
Editores: array de TDBComboBox;
->Uma matriz específica de controles de dados usados para edição, gerados dinamicamente
Rótulos: matriz de TLabel;
->O título de cada campo é gerado dinamicamente
----A vantagem de usar TDBComboBox é que ele não apenas possui funções gerais de edição, mas também pode adicionar informações de prompt correspondentes a cada campo. O código é o seguinte:
{Método para adicionar informações de prompt ao campo I}
Procedimento TDBPanel.AddHits
(ItemIndex: Inteiro; Hits: array de string);
var
m,n,i: Inteiro;
começar
n := Comprimento(Editores);
m := Comprimento(Hits);
se ItemIndex< n então comece
para i:=0 a m-1 faça Editors[ItemIndex].Items.Add(Hits[i]);
fim;
fim;
---- As aplicações específicas variam amplamente, portanto, o controle também precisa deixar interfaces de processamento de eventos suficientes para que os programadores implementem funções especiais para aplicações específicas. Isso requer a definição de determinados métodos de processamento de eventos no controle para implementação pelos usuários. O que é fornecido aqui é um evento OnOkClick, que é o processamento realizado quando todos os campos são editados. O código é o seguinte:
OkButton: TButton;
->O último botão OK adicionado é usado para implementar a ação de envio.
propriedade OnOkClick: TNotifyEvent lê FCClick escreve FCClick;
---- Ao implementar o método OnOKClick, os usuários podem concluir diversas tarefas de processamento, como envio e testes de racionalidade de dados. Outra coisa que requer tratamento especial é o controle da conversão entre vários campos. O padrão é clicar com o mouse. No entanto, o hábito dos usuários costuma usar as quatro teclas de seta “para cima, para baixo, para a esquerda e para a direita” do teclado. Para implementar esta função, os dois métodos a seguir precisam ser definidos:
procedimento AKeyPress(Remetente: TObject; var Chave: Char);
procedimento AKeyDown(Remetente: TObject;
var Chave: Palavra; Shift: TShiftState);
---- Atribua os dois métodos acima aos Editores gerados dinamicamente para obter resposta às teclas de seta.
---- Tabelas diferentes têm números diferentes de campos e podem não ser exibidas, o que requer uma função de rolagem. Assim, um controle TscrollBox é inserido no controle. A última coisa a notar é a anulação dos controles dinâmicos e a liberação de memória. A destruição da matriz de controle e a liberação de memória estão em ordem – a ordem de criação exatamente oposta. Caso contrário, algo dará errado.
----Uso de controles
---- Primeiro coloque o controle DBPanel no formulário e, em seguida, defina as propriedades da fonte de dados, o número de colunas do formulário de entrada de dados e outras propriedades. No programa, após abrir a fonte de dados, basta chamar o método para criar o controle de edição dos dados. Agora mesmo:
Query1.Open;->Abrir fonte de dados
DBPanel1.CreateEditors; ->Criar controles de edição para cada campo
DBPanel1.AddHits(0,['1111','11222','eeee']);
-> Definir informações de prompt para um determinado campo
DBPanel1.AddHits(1,['1111','11222','eeee']);
-> Definir informações de prompt para um determinado campo
O programa de controle e de amostra foram depurados no ambiente Win98+Delphi 5.0.
---- Anexo: Código fonte do TDBPanel
unidade DBPanel;
interface
usa
Windows, Mensagens, SysUtils, Classes,
Gráficos, controles, formulários, caixas de diálogo,
ExtCtrls, dbctrls, stdctrls, banco de dados;
tipo
TDBPanel = classe(TPanel)
privado
{Declarações privadas}
FEsquerda: Inteiro;
FTop: Inteiro;
maxTextLen: Inteiro;
maxLabelLen: Inteiro;
FScrollBox: TScrollBox;{controle de rolagem}
FLineHeight: Inteiro;
FClique: TNotifyEvent;
Editores: array de TDBComboBox;
->Uma matriz específica de controles de dados usados para edição, gerados dinamicamente
Rótulos: matriz de TLabel;
->O título de cada campo é gerado dinamicamente
OkButton: TButton;
->O último botão OK adicionado é usado para implementar a ação de envio.
{fonte de dados}
FDataSource: TDataSource;
Colunas: Inteiro;
->Insira o número de colunas da tabela
protegido
{Declarações protegidas}
procedimento Editores Livres;
->Libere memória de controle de entrada de dados
público
procedimento CriarEditores;//
(DS: TDataSource; ColCount: Inteiro);
->Crie controles de entrada de dados para cada campo
construtor Criar(AOwner:
substituição de TComponent);
substituição do destruidor;
procedimento AKeyPress(Remetente:
TObject; var Chave: Char);
procedimento AKeyDown(Remetente:
TObject; var Chave: Palavra;
TShiftEstado);
procedimento ClearHits (ItemIndex: Integer);
procedimento AddHits(ItemIndex:
Inteiro; Hits: array de string);
Editor de função (Índice: Inteiro):
TDBComboBox;
{Declarações públicas}
publicado
propertyLeftLimit: leitura de número inteiro
FLeft escreve FLeft padrão 10;
propriedade TopLimit: leitura de número inteiro
FTop escreve FTop padrão 10;
propriedade EditorLen: leitura de número inteiro
maxTextLen escreve maxTextLen;
propriedade LabelLen: leitura de número inteiro
maxLabelLen escreve maxLabelLen padrão 100;
propriedade LineHeight: leitura de número inteiro
FLineHeight escreve FLineHeight padrão 15;
propriedade OnOkClick: TNotifyEvent
ler FCClick escrever FCClick;
propriedade DataSource: TDataSource
leia FDataSource escreva FDataSource;
->Fonte de dados
Colunas de propriedade: leitura de número inteiro
FColumns escreve FColumns;->Número de colunas da tabela
{Declarações publicadas}
fim;
Cadastro de procedimento;
implementação
Cadastro de procedimento;
começar
RegisterComponents('Adicional', [TDBPanel]);
fim;
{Método para adicionar informações de prompt ao campo I}
procedimento TDBPanel.AddHits(ItemIndex:
Inteiro; Hits: array de string);
var
m,n,i: Inteiro;
começar
n := Comprimento(Editores);
m := Comprimento(Hits);
se ItemIndex< n então comece
para i:=0 a m-1 faça Editors[ItemIndex].Items.Add(Hits[i]);
fim;
fim;
procedimento TDBPanel.AKeyDown
(Remetente: TObject; var Chave: Word;
Shift: TShiftState);
começar
if (Sender é TDBComboBox) então comece
caso Chave de
VK_Next: (Remetente como TDBComboBox)
.DataSource.DataSet.Next;
VK_PRIOR: (Remetente como TDBComboBox)
.DataSource.DataSet.Prior;
fim;
fim;
fim;
procedimento TDBPanel.AKeyPress(Remetente: TObject; var Chave: Char);
começar
if (Sender é TDBComboBox) então comece
if Key=#13 then (Proprietário como TForm).Perform(WM_NEXTDLGCTL, 0, 0);
fim;
fim;
procedimento TDBPanel.ClearHits(ItemIndex: Integer);
var
n: Inteiro;
começar
n := Comprimento(Editores);
se ItemIndex< n então Editors[ItemIndex].Items.Clear;
fim;
construtor TDBPanel.Create(AOwner: TComponent);
começar
Herdado Criar (AOWNer);
FEsquerda:=10;
FTop := 10;
maxTextLen := 100;
maxLabelLen := 100;
FLineHeight := 15;
fim;
{Método para criar controles de entrada de dados para cada campo}
procedimento TDBPanel.CreateEditors;//
(DS: TDataSource; ColCount: Inteiro);
var
i, n, RowCount: Inteiro;
TextHeight: Inteiro;
começar
se DataSource.DataSet.Active então comece
n := DataSource.DataSet.FieldCount;
{Calcule o comprimento máximo do título e o comprimento da exibição}
DataSource.DataSet.First;
{calcular altura}
TextHeight := Canvas.TextHeight(DataSource
.DataSet.Fields[0].DisplayLabel) + FLineHeight;/10;
{Calcule o número de linhas e colunas}
RowCount := n div Colunas;
se n mod Colunas < > 0 então inc(RowCount);
{Alocar memória}
Editores Gratuitos;
SetLength(Editores, n);
SetLength(Rótulos, n);
{Criar caixa de rolagem}
FScrollBox := TScrollBox.Create(Proprietário);
FScrollBox.Parent := Próprio;
FScrollBox.Align := alClient;
{CriarEditar}
para i:=0 a n-1 comece
{Criar título}
Rótulos[i] := TLabel.Create(Proprietário);
Rótulos[i].Parent := FScrollBox;
Etiquetas[i].Caption := DataSource.DataSet.Fields[i].DisplayLabel;
Rótulos[i].Left := FLeft + (maxLabelLen +
maxTextLen + 10) * (i div RowCount);
Rótulos[i].Largura := maxLabelLen;
Etiquetas[i].Top := FTop + (i mod RowCount) * TextHeight + 5;
{Criar objeto de edição}
Editores[i] := TDBComboBox.Create(Proprietário);
Editores[i].Parent := FScrollBox; //Self;
Editores[i].Esquerda := Etiquetas[i].Esquerda + Etiquetas[i].Largura;
Editores[i].Largura := maxTextLen;
Editores[i].Top := FTop + (i mod RowCount) * TextHeight;
Editores[i].DataSource := DataSource;
Editores[i].DataField := DataSource.DataSet.Fields[i].FieldName;
Editores[i].OnKeyPress := AKeyPress;
Editores[i].OnKeyDown := AKeyDown;
fim;
{Botão Criar OK}
OkButton := TButton.Create(Proprietário);
OkButton.Parent := FScrollBox;
OkButton.Left := Editores[n-1].Left;
OkButton.Top := Editores[n-1].Top + TextHeight;
OkButton.Caption := 'OK';
OKButton.OnClick := FCClick;
fim;
fim;
destruidor TDBPanel.Destroy;
começar
Editores Gratuitos;
Destruição Herdada;
fim;
função TDBPanel.Editor(Índice: Inteiro): TDBComboBox;
começar
if Índice<Comprimento(Editores) então Resultado:= Editores[Índice]
senão Resultado: = nulo;
fim;
procedimento TDBPanel.FreeEditors;
var
eu,n: Inteiro;
começar
{A memória deve ser liberada em ordem! Deve ser feito na ordem inversa da criação!
Especialmente quando há uma relação pai-filho entre os componentes}
se OkButton< >nil então OkButton.Free;
se Editores< >nil então comece
n := Comprimento(Editores);
para i:=0 a n-1 faça Editors[i].free;
Editores := nulo;
n := Comprimento(Rótulos);
para i:=0 a n-1 faça Labels[i].Free;
Rótulos := nulo;
fim;
se FScrollBox< >nil então comece
FScrollBox.Free;
FScrollBox := nulo;
fim;
fim;
fim.