Fórum Combobox multiplos objetos #623779

15/07/2025

0

Pessoal, tenho hoje um combobox que é alimentado com os dados resultantes de uma consulta SQL, desta forma

      with FrmPgtoCheque.qryAux do
      begin
        SQL.Clear;
        SQL.Add('SELECT CODIGO, CEDENTE, COD_GRUPO_CONTAS FROM TBCEDENTES');
        SQL.Add('WHERE STATUS = :ST');
        SQL.Add('ORDER BY CEDENTE');
        ParamByName('ST').AsString := 'ATIVO';
        Open;

        while not Eof Do
        begin
          FrmPgtoCheque.Edobs.Items.AddObject(FieldByName('CEDENTE').AsString, TObject(Integer(FieldByName('CODIGO').AsInteger)));
          Next;
        end;
      end;



Ocorre que nessa consulta eu estou precisando trazer um terceiro campo chamado COD_GRUPO_CONTAS e não estou conseguindo adicionar ele ao combobox, para posteriormente recuperar ele
Alguém tem uma dica?
Renan

Renan

Responder

Posts

15/07/2025

Arthur Heinrich

Eu consigo imaginar várias "gambiarras" (ou ajustes técnicos), kkk.

A propriedade TObject é um ponteiro de 32 bits, que você, convenientemente, utilizou para armazenar o código do Cedente.

Sabemos que um número de 32 bits pode armazenar pouco mais de 4 bilhões de códigos.

Se os seus códigos de Cedente e Grupo de Contas possuem valores limitados, dá para tentar compor os 32 bits de forma que dê para armazenar os dois.

Por exemplo, se você não tiver mais de 256 grupos de conta e no máximo 16 milhões de cedentes, dá para utilizar 1 byte para o grupo de contas e 3 para o código do cedente.

TObject( (FieldByName('COD_GRUPO_CONTAS').AsInteger shl 24) or FieldByName('CODIGO').AsInteger)


Para recuperar, você desfaz esta codificação:

COD_GRUPO_CONTAS:=Integer(FrmPgtoCheque.Edobs.Objects[FrmPgtoCheque.Edobs.ItemIndex]) shr 24;
CODIGO:=Integer(FrmPgtoCheque.Edobs.Objects[FrmPgtoCheque.Edobs.ItemIndex]) and $00FFFFFF;


Se isto não puder ser assumido, você precisará de outras estruturas para armazenar os dados extras. Por exemplo, pode construir dinamicamente o TStringGrid para armazenar dados completos do resultado da query e, na propriedade TObject do Combo Box, pode armazenar o índice (linha) do StringGrid que corresponde ao cedente.
Responder

Gostei + 0

16/07/2025

Renan

Oá, Arthur.

Acredito que poderia resolver, mas estou pensando em uma forma mais simples.

Armazeno os dados no combo para depois pesquisar eles via OnChange e isso funciona bem para 2 campos armazenados(codigo e descrição)

Uma solução seria não usar o combo, mas um edit e um dbbrig para buscar os dados e depois armazenar eles numa variavel.

Outra solução que vi, mas não consegui implementar, foi o uso de records via typecasting, no caso deste link, o terceiro exemplo poderia me ser util, mas obtenho erro de invalid typecast
https://wiki.portugal-a-programar.pt/dev_geral/pascal/delphi/associar_dados_list_combo/
Responder

Gostei + 0

16/07/2025

Arthur Heinrich

Oá, Arthur.

Acredito que poderia resolver, mas estou pensando em uma forma mais simples.

Armazeno os dados no combo para depois pesquisar eles via OnChange e isso funciona bem para 2 campos armazenados(codigo e descrição)

Uma solução seria não usar o combo, mas um edit e um dbbrig para buscar os dados e depois armazenar eles numa variavel.

Outra solução que vi, mas não consegui implementar, foi o uso de records via typecasting, no caso deste link, o terceiro exemplo poderia me ser util, mas obtenho erro de invalid typecast
https://wiki.portugal-a-programar.pt/dev_geral/pascal/delphi/associar_dados_list_combo/


O exemplo #3 citado falha porque o Type Cast pressupõe que tanto o tipo original como o tipo novo ocupam o mesmo tamanho. O Type Cast apenas interpreta o conteúdo da memória como um valor distinto. Um byte contendo o valor 65, pode ser interpretado como Byte 65 ou como Char 'A', por exemplo.

No exemplo descrito, o record contém ponteiros para strings e outros valores, que constituem uma estrutura muito maior e mais complexa do que o TObject, que nada mais é um ponteiro que faz referência a uma instância da classe TObject. Por isso o cast falha.

A outra opção, de consultar dinamicamente no banco a cada vez que o item selecionado muda, embora tecnicamente viável, torna a usabilidade prejudicada devido ao tempo para consultar o banco, além de prejudicar o banco com consultas desnecessárias e tráfego de rede. Pode parecer pouco, mas em um ambiente com múltiplos usuários e muitas consultas, isto se acumula e causa impacto significativo.

Você pode, por exemplo, criar um TStringList para cada cedente retornado, armazenando os dados nele e, ao adicionar o cedente ao ComboBox, adicionar o StringList.

O StringList pode ser utilizado para armazenamento de propriedades, também, além de uma simples lista de strings.

var
  SL : TStringList;
begin
  SL:=TStringList.Create;
  SL.Values['COD_GRUPO_CONTAS']:=FieldByName('COD_GRUPO_CONTAS').AsString;
  SL.Values['CODIGO']:=FieldByName('CODIGO').AsString;
end;

Para recuperar os valores e transformá-los em inteiro novamente:

  COD_GRUPO_CONTAS:=StrToInt(SL.Values['COD_GRUPO_CONTAS']);
  CODIGO:=StrToInt(SL.Values['CODIGO']);


Só não tenho certeza se o ComboBox vai destruir as instâncias de StringList apontadas, ou se você terá que fazer isso via código.
Responder

Gostei + 0

17/07/2025

Renan

Obrigado pelas explicações.

Optei por buscar CEDENTE, CODIGO, COD_GRUPO_CONTAS via um simples select que traz os dados no dbgrid.
Então ao selecionar o CEDENTE, armazeno os codigos em variaveis, para usar posteriormente
Responder

Gostei + 0

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar