 |
ActiveDelphi .: O site do programador Delphi! :.
|
| Exibir mensagem anterior :: Exibir próxima mensagem |
| Autor |
Mensagem |
HELDERNET Novato


Registrado: Sexta-Feira, 16 de Novembro de 2012 Mensagens: 22
|
Enviada: Qui Set 26, 2013 4:39 pm Assunto: Thread com CxGrid: gerando erro cod 1400 (RESOLVIDO) |
|
|
Olá Pessoal !!
O sistema que trabalho, carrega vários grids na tela principal e isso as vezes demora quase um minuto e nesse intervalo, quando ele tenta abrir um dataset a janela trava, mas depois que termina carregar os dados ela volta. Mas para o cliente isso e muito chato, pois dá impressão que todo o sistema está travado.
Então, para melhorar isso coloquei o dataset pra ser carregado por uma Thread e a aplicação principal atualizando a tela e um ProgressBar em movimento. Até então, deu quase tudo certo, sendo que o problema é ao finalizar o sistema dá o seguinte erro: SYSTEM ERROR: CODE 1400. O IDENTIFICADOR DA JANELA E INVÁLIDO.
Baseado num modelo que achei em um forum aqui nesse site:
http://www.activedelphi.com.br/forum/viewtopic.php?p=243894
Fiz um modelo semelhante ao sistema do projeto que trabalho e nesse modelo coloquei um DBGrid e um CxGrid(DevExpress), quando o DataSet gera os dados no DBGrid NAÃO Gera o erro, mas quando gero o dataset conectado ao CxGrid, aparece o erro ao finalizar o sistema.
Alguém pelo amor de Deus, me ajuda !!
vou colocar o código do sistema aqui e o link do codigo do projeto ja pronto junto com o scritp que gera uma tabela de exemplo:
UNIT PRINCIPAL
| Código: |
unit Principal;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, DB, IBCustomDataSet, IBQuery, IBDatabase, ComCtrls, StdCtrls,
ExtCtrls, Grids, DBGrids, ThreadSQL, cxGraphics, cxControls,
cxLookAndFeels, cxLookAndFeelPainters, cxStyles, cxCustomData, cxFilter,
cxData, cxDataStorage, cxEdit, cxDBData, cxGridCustomTableView,
cxGridTableView, cxGridDBTableView, cxGridLevel, cxClasses,
cxGridCustomView, cxGrid, Provider, DBClient, ADODB;
type
TfrmPrincipal = class(TForm)
Button1: TButton;
stsbarInfo: TStatusBar;
ADOConnection1: TADOConnection;
qryteste: TADOQuery;
cds: TClientDataSet;
dspteste: TDataSetProvider;
dsteste: TDataSource;
DBGrid: TDBGrid;
cxGridDBTableView1: TcxGridDBTableView;
cxGridLevel1: TcxGridLevel;
cxGrid: TcxGrid;
Button3: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button3Click(Sender: TObject);
private
procedure ExecutarSQL;
{ Private declarations }
public
{ Public declarations }
end;
var
frmPrincipal: TfrmPrincipal;
thrSQL : TThreadSQL;
Terminou : Boolean;
implementation
{$R *.dfm}
procedure TfrmPrincipal.Button1Click(Sender: TObject);
begin
cds.Close;
cxGridDBTableView1.DataController.DataSource := nil;
DBGrid.DataSource := dsteste;
ExecutarSQL;
ShowMessage('Dados carregados com sucesso!' + #13 +
'O sistema será finalizado e NÃO irá gerar o erro');
Application.Terminate;
end;
procedure TfrmPrincipal.Button3Click(Sender: TObject);
begin
cds.Close;
DBGrid.DataSource := nil;
cxGridDBTableView1.DataController.DataSource := dsteste;
ExecutarSQL;
ShowMessage('Dados carregados com sucesso!' + #13 +
'O sistema será finalizado e irá gerar o erro do COD 1400.');
Application.Terminate;
end;
procedure TfrmPrincipal.ExecutarSQL;
begin // instância objeto do tipo TThread. Esta thread é responsável por
Terminou := False;
thrSQL := TThreadSQL.Create(False, cds); // executar sentença SQL.
{segura a aplicação até carregar todo o dataset}
while not Terminou do
Application.ProcessMessages;
thrSQL := nil;
end;
procedure TfrmPrincipal.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
action := Cafree;
end;
procedure TfrmPrincipal.FormDestroy(Sender: TObject);
begin
if thrSQL <> nil then
thrSQL := nil;
end;
end.
|
UNIT THREAD
| Código: |
unit ThreadSQL;
interface
uses Classes, SysUtils, ADODB, ComCtrls, DBClient, IBQuery, Dialogs, Controls;
type
TThreadSQL = class(TThread)
private
{ Private declarations }
cds : TClientDataSet;
procedure Termino(Sender : TObject);
procedure ExecutarProgresso;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended : boolean; pcds : TClientDataSet);
end;
TThreadProgressbar = class(TThread)
private
{ Private declarations }
procedure InicializaProgresso;
procedure PreencheProgresso;
procedure Termino(Sender : TObject);
protected
procedure Execute; override;
public
constructor Create(CreateSuspended : boolean);
end;
var
thrProgresso : TThreadProgressbar;
prgbarProgresso : TProgressBar;
implementation
uses Principal;
constructor TThreadSQL.Create(CreateSuspended : boolean; pcds : TClientDataSet);
begin
inherited Create(CreateSuspended);
OnTerminate := Termino; // OnTerminate é executado quando é encerrado a thread.
FreeOnTerminate := True; // determina se a thread é destruido automaticamente.
Priority := tpHigher; // prioridade da thread em relação aos demais processos.
cds := pcds;
end;
procedure TThreadSQL.Execute;
var
j: Integer;
begin
ExecutarProgresso; // cria e inicializa a thread do progressbar.
cds.DisableControls;
cds.Open;
cds.Last;
cds.EnableControls;
Terminou := True;
Self.Terminate;
end;
procedure TThreadSQL.Termino(Sender : TObject);
begin // seta a propriedade Terminated para True para ser encerrado a thread.
thrProgresso.Terminate;
if thrProgresso <> nil then
thrProgresso := nil;
end;
// cria e inicializa a thread do progressbar.
procedure TThreadSQL.ExecutarProgresso;
begin
thrProgresso := TThreadProgressbar.Create(false);
end;
{TThreadProgressbar}
constructor TThreadProgressbar.Create(CreateSuspended : boolean);
begin
inherited Create(CreateSuspended);
OnTerminate := Termino; // OnTerminate é executado quando é encerrado a thread.
FreeOnTerminate := True; // determina se a thread é destruido automaticamente.
Priority := tpNormal; // prioridade da thread em relação aos demais processos.
Synchronize(InicializaProgresso); // inicializa o progressbar.
end;
procedure TThreadProgressbar.Termino(Sender : TObject);
begin
FreeAndNil(prgbarProgresso); // destroi e libera o progressbar.
end;
procedure TThreadProgressbar.Execute;
begin // enquanto a execução não for forçado a terminar
while not Terminated do // (atraves do evento OnTerminate da TThreadSQL).
Synchronize(PreencheProgresso); // preenche o progressbar.
end;
// inicializa o progressbar
procedure TThreadProgressbar.InicializaProgresso;
begin
prgbarProgresso := TProgressBar.Create(nil); // instância um objeto do tipo TProgressBar.
with prgbarProgresso do
begin
Parent := frmPrincipal.stsbarInfo;
// Width := alClient;
align := alClient;
Height := 16;
Top := 3;
Left := 153;
Anchors := [akTop,akRight];
Position := 0;
Min := 0;
Max := 1000;
end;
end;
// preenche o progressbar.
procedure TThreadProgressbar.PreencheProgresso;
begin
with prgbarProgresso do
begin
if Position < Max then
Position := Position+1
else
Position := 0;
{coloca o progressbar mais lento}
sleep(10);
end;
end;
end.
|
Aqui estou utilizando o Delphi 2007 e o Banco de Dados SQLSERVER 2008.
-Baixe o codigo fonte no link postado:
| Citação: | | https://mega.co.nz/#!mY9A1CgT!RBuyfGJLBKWjuRizJnGRw3x4kX4cLiA3onjqRktLeiE |
-Crie um banco de dados com nome DBDEMO ou como desejar
-Abra o arquivo txt e gere o script do sql para gerar a tabela modelo e inserir os dados ou restaura o backup que está junto caso sua versão do sqlserver seja 2008.
-No formulario principal, configure a conexão com o ADOCONNECTION
-Executa a aplicação
Observe, quando vc gera o sistema clicando no botão gerar no DBGRID, ele gera e carrega o grid normal, e ao fechar nao dá erro, mas quado vc gera clicando no botão para gerar no CxGrid, da o erro CODE 1400 e não sei o que pode ser.
Agradeço a ajuda e a atençao de todos.
vlw
Editado pela última vez por HELDERNET em Ter Dez 03, 2013 9:13 am, num total de 1 vez |
|
| Voltar ao Topo |
|
 |
HELDERNET Novato


Registrado: Sexta-Feira, 16 de Novembro de 2012 Mensagens: 22
|
Enviada: Sex Set 27, 2013 9:26 am Assunto: Re: Thread com CxGrid: gerando erro cod 1400 Identif. Inválido. |
|
|
Curiosidade:
Peguei um banco de dados *.mdb (access), e conectei nesse modelo que fiz aqui. Abriu as tabelas no CxGrid e ao fechar não gerou o erro. Mas com o banco SQL Server que estou usando, dá o erro. Pq será ? |
|
| Voltar ao Topo |
|
 |
HELDERNET Novato


Registrado: Sexta-Feira, 16 de Novembro de 2012 Mensagens: 22
|
Enviada: Sex Out 18, 2013 4:17 pm Assunto: Re: Thread com CxGrid: gerando erro cod 1400 Identif. Inválido. |
|
|
Pessoal, estou passando por aqui só pra dizer que consegui resolver.
SOLUÇÃO: Antes de fazer a chamada da Thread, peguei todos os eventos do ClientDataSet e do DasaSet do cxgrid, atribui nil a eles, chamei a thread passando o Clientdataset no parametro e depois que terminou, voltei os eventos e o vínculo do grid. Funcionou.
EXEMPLO
cxgrid.DataController.DataSource := nil;
cdsForm.AfterScroll := nil;
{thread}
AbrirCDSTh(cdsForm);
cxgrid.DataController.DataSource := dsForm;
cdsForm.AfterScroll := cdsformAfterScroll; |
|
| Voltar ao Topo |
|
 |
TheBlueMonkey Novato


Registrado: Sexta-Feira, 28 de Dezembro de 2012 Mensagens: 32
|
Enviada: Sex Nov 08, 2013 11:43 am Assunto: Re: Thread com CxGrid: gerando erro cod 1400 Identif. Inválido. |
|
|
| HELDERNET escreveu: | Pessoal, estou passando por aqui só pra dizer que consegui resolver.
SOLUÇÃO: Antes de fazer a chamada da Thread, peguei todos os eventos do ClientDataSet e do DasaSet do cxgrid, atribui nil a eles, chamei a thread passando o Clientdataset no parametro e depois que terminou, voltei os eventos e o vínculo do grid. Funcionou.
EXEMPLO
cxgrid.DataController.DataSource := nil;
cdsForm.AfterScroll := nil;
{thread}
AbrirCDSTh(cdsForm);
cxgrid.DataController.DataSource := dsForm;
cdsForm.AfterScroll := cdsformAfterScroll; |
Heldernet, cara. Quero muito te agradecer por ter postado a solução mesmo sem que ninguém tenha respondido o tópico. Eu estava com um problema meio parecido (Access Violation ao abrir de dentro de uma thread uma query vinculada a um CxGrid) e a tua solução apesar de simples foi bastante eficiente e de grande ajuda, já havia passado toda a tarde anterior apanhando com este probema.
Obrigado com compartilhar a tua solução. |
|
| Voltar ao Topo |
|
 |
HELDERNET Novato


Registrado: Sexta-Feira, 16 de Novembro de 2012 Mensagens: 22
|
Enviada: Ter Dez 03, 2013 9:16 am Assunto: Re: Thread com CxGrid: gerando erro cod 1400 Identif. Inválido. |
|
|
| TheBlueMonkey escreveu: | | Obrigado com compartilhar a tua solução. |
Fico feliz em ter contribuído para a solução do seu problema. |
|
| Voltar ao Topo |
|
 |
|
|
Enviar Mensagens Novas: Proibido. Responder Tópicos Proibido Editar Mensagens: Proibido. Excluir Mensagens: Proibido. Votar em Enquetes: Proibido.
|
|