Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Combobox, tabla, campos, items (https://www.clubdelphi.com/foros/showthread.php?t=41696)

Caral 22-03-2007 21:01:26

Combobox, tabla, campos, items
 
Hola a Todos y gracias de antemano.
Vereis, estoy haciendo un programita que sirve de filto de la base de datos (access).
Tengo un combobox y un dbgrid para escoger la base de datos un combobox adicional, escoge el campo y un edit define el dato.
Que pretendo hacer:
1. Al entrar en el programa que el primer combobox carge las tablas (los Nombres) de cada Tabla.
2- Al cambiar el primer combobox se cargen en el segundo combobox los campos (nombres) de la tabla escogida.
3- Al llenar el edit, se muestre el filtro en el dbgrid.
Se como llenar un combobox con los campos de una tabla, pero no se como llenarlo con los nombres de esos campos.
Maestros si me podeis ayudar, lo agradeceria mucho.
Saludos

ArdiIIa 22-03-2007 21:10:58

Hola Caral:
No tengo el delphi a mano pero de memoria sería algo tal como supongo que haces:
Código Delphi [-]
For I := 0 To Tabla.FieldsCount-1 Do
Combobox.Items.Add( Tabla.Fields[i].FieldName);
No estoy muy seguro....

roman 22-03-2007 21:30:50

¿Usas ADO, no?

Llenar el combo cboTablas con las tablas:

Código Delphi [-]
ADOConnection.GetTableNames(cboTablas.Items);

Llenar el combo cboCampos con los campos de la tabla del combo anterior:

Código Delphi [-]
ADOConnection.GetFieldNames(cboTablas.Text, cboCampos.Items);

// Saludos

Caral 22-03-2007 21:44:20

Hola
ArdiIIa: no me camino, no se porque?, no soy muy diestro en estas cosas.:D
Roman: Que decir.:D , nada que no te alla dicho antes.:D Eres un Maestro.
Muchas Gracias a los dos por ayudarme, ya esta listo y funcionando.
Gracias pero muchas gracias.
Saludos

Caral 22-03-2007 23:12:00

Hola de nuevo.
Bueno todo va bien pero tengo una duda adicional.
Lo que estoy haciendo:
1-Cargo la tablas en el primer combobox1 (perfecto)
2-Cargo los campos en el segundo combobox2 (perfecto)
3-Introduzco un dato en el Edit para filtrar con este codigo:
Código Delphi [-]
  ADOQuery1.Open;
  ADOQuery1.Filter := ComboBox2.Text+ ' Like '''+Edit1.Text+ '*''';
  ADOQuery1.Filtered := True;
Funciona muy bien pero cuando el campo es text (String), si el campo es numerico se fastidio el invento.
Pregunta:
1-Como hago para que identifique el campo antes de filtrar?
2-Como hago para que se quede en blanco el edit1 despues de hacer la consulta.?
Código Delphi [-]
Edit1.Clear;
Esto de arriba no camina, ya que se esta filtrando:

Me ayudais por favor.
Saludos

egostar 23-03-2007 02:58:30

Hola Caral

Así de bote pronto lo que yo haría es lo siguiente

Código Delphi [-]
try
   Filtro := strtoint(edit1.text);
   ADOQuery1.Filter := ComboBox2.Text+ ' = '+Filtro;
except 
   ADOQuery1.Filter := ComboBox2.Text+ ' Like '''+Edit1.Text+ '*''';
end;

ADOQuery1.Filter := True;
ADOQuery1.Open;

No entiendo como abres primero la tabla y luego la filtras, yo imaginaría que primero se asigna el filtro y luego se abre la tabla.

Saludos

egostar 23-03-2007 06:05:53

Estimado Caral

De regreso a casa en el trafico de esta mi bella ciudad y escuchando a Alvin Lee, venia haciendo recuento de las actividades de este dia y vino a mi mente tu pregunta.

Tengo una duda.

Porque estas usando un filltro en un Query, yo he usado filtros pero en TTables no en TQuery, los datos en un Query son filtrados directamente en su sentencia SQL.

Saludos desde casa.

Lepe 23-03-2007 12:20:33

Sin detenerme en lo comentado por los demás foristas (que estoy totalmente de acuerdo), el problema que te dá son precisamente las comillas simples que añades.

Mira la diferencia, si es un campo definido como String:
Código SQL [-]
 select * from table where codigo = '33'

Si está definido como integer, el sql debe quedar así:
Código SQL [-]
 select * from table where codigo = 33

Exactamente igual que usando filter.

Si es numérico, no tendría sentido usar el operador "Like", ya que irá a un registro que no le sirve al usuario para nada, por ejemplo busca el 33 y encuentra el 3 :(.

Saludos

Caral 23-03-2007 19:27:57

Hola
egostar: Efectivamente se puede hacer el filtro por sentencia sql, posiblemente mas efectivamente pero en este caso me quedo un poco mas comodo hacerlo asi.
Gracias por tu explicacion, ya tenia mas o menos el camino, lo que pasa es que me empeño en no usar el try except, porque en diseño genera un error y particularmente no me gusta, asi es como lo tengo, pero no lo voy a dejar.
Código Delphi [-]
var
   Filtro : String;
begin
   If (Edit1.Text <> '') then
   begin
   AdoQuery1.Filtered := false;
   Filtro := ComboBox2.Text+ ' Like '''+Edit1.Text+ '*''';
   ADOQuery1.Filter := Filtro;
   //showmessage(Filtro);
   try
      ADOQuery1.Filtered := True;
   except
      try
         Filtro := ComboBox2.Text+ ' Like '+Edit1.Text;
         ADOQuery1.Filter := Filtro;
         ADOQuery1.Filtered := True;
      except
         Filtro := ComboBox2.Text+ ' >= '+Edit1.Text;
         ADOQuery1.Filter := Filtro;
         //showmessage(Filtro);
         ADOQuery1.Filtered := True;
      end;
   end
    end
   else ADOQuery1.Filtered := False;
Lepe: Gracias por la explicacion, efectivamente por ese camino estoy, entiendo bien lo de String e integer, en este filtro en especial lo que pretendo es el cambio continuo por eso en este caso el signo = no me camina, estoy tratando con >= que funciona mas adecuadamente aun asi sigo pensando y recibiendo sugerencias.
Una opcion que se me ha ocurrido es hacer el cambio en un combobox, asi definiria el tipo de campo, integer, float, string y simplemente me daria el resultado , no se que tal os parece, habra otra opcion?.Seguro que si.:D
Gracias por la ayuda que me dais.
Saludos

roman 23-03-2007 19:38:11

Hola,

Lo que creo que queda claro después del comentario de Lepe, es que no tiene mucho caso tratar de usar el mismo operador para todos los tipos de campo. ¿Por qué no mejor actuar con base al tipo de datos del campo?

Código Delphi [-]
J := cboCampos.ItemIndex;
case ADOQuery.Fields[J].DataType of
  ftString: filtro para campos string;
  ftSmallInt, ftInteger, ftWord, ftLargeInt: filtro para campos enteros;
  ftFloat, ftCurrency: filtro para campos reales;
  ftBoolean: filtro para campos lógicos;
  ftDate, ftTime, ftDateTime: filtro para campos fecha-hora;
else
  raise Exception.Create('no sé que hacer con este tipo de datos');
end;

Lo útimo es necesario para todos los datos tipo BLOB o más raros.

// Saludos

Caral 23-03-2007 19:56:35

Hola
Roman: me parece fenomenal.
Como lo aplico, no tengo ni idea?
Me quedo grande.:)
Saludos

egostar 23-03-2007 22:22:53

Hola Caral

Si no estoy tan mal, lo que hace roman es evitar el uso del try...except con el case y me parece una excelente idea.

En todo caso, yo haría lo siguiente.

Código Delphi [-]
// J debe ser el indice del campo que deseas filtrar
case ADOQuery1.Fields[J].DataType of 
   ftString   : ADOQuery.Filter := ComboBox2.Text+ ' Like "'+Edit1.Text+ '*"'; //No se si es correcto el * y mejor deberias usar el signo de %.
     ftInteger : ADOQuery.Filter := ComboBox2.Text+ ' = '+Edit1.Text;
     ftFloat,ftCurrency : ADOQuery.Filter := ComboBox2.Text+ ' >= '+Edit1.Text;
end;

Se me hace raro que no puedas usar el signo = y uses el >=, pero eso puede suceder en campos de punto flotante o de moneda, por eso lo puse en el case de ftFloat y ftCurrency. Bueno, eso creo.

Salud OS.

Caral 24-03-2007 00:06:22

Gracias egostar
Estoy tratando de hacerlo, de esta manera no hay forma, no se por que.?
Les agradezco todas sus intervenciones, me ayudan mucho.
Gracias
PD: Algun dia aprendere.:D
Saludos

Lepe 26-03-2007 10:53:15

No me gustaría que este tema se quedara así :(.

¿Por qué no te sale? Si en el combo1 tenemos los nombres de campos:
Código Delphi [-]
var idx :integer;
begin
  idx := query1.Fields.indexof(combo1.items[combo1.itemindex]);
  case Query1.Fields[idx].Datatype of
   .....
end;

Saludos

Caral 26-03-2007 19:35:41

Hola Lepe
La respuesta a esto:
Cita:

¿Por qué no te sale?
Ignorancia, desconocimiento, la opcion de Roman es fenomenal, funciona a medias, osea no pasa nada, no genera el filtro, pero no da error, por que , no se, me encantaria aplicarla, pero desconozco como, lo he intentado de varias formas (a mi alcance de conocimiento), pero no funciona.
Me gusta la forma en la que ayuda Roman, te da una pauta y luego te deja para que pienses, asi se aprende mas, bueno en este caso como que soy duro de mollera.
Saludos

egostar 26-03-2007 20:13:37

Hola Caral,

Estuve revisando el código e hice algunas pruebas, después de probar las opciones, este código me funcionó perfectamente.

Código Delphi [-]
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  Query2.Close;
  case Query1.Fields[idx].Datatype of
     ftString   : Query2.Filter := ComboBox1.Text+ ' = '''+Edit1.Text+ '*''';
     ftInteger  : Query2.Filter := ComboBox1.Text+ ' = '+Edit1.Text;
     ftFloat,
     ftCurrency : Query2.Filter := ComboBox1.Text+ ' >= '+Edit1.Text;
     ftDate,
     ftTime     : Query2.Filter := ComboBox1.Text+ ' = '''+Edit1.Text+ '''';
  end;
  Query2.Filtered := True;
  Query2.Open;
end;

procedure TForm1.ComboBox1Change(Sender: TObject);
begin
  idx := ComboBox1.ItemIndex;
end;

Utilice dos TQuery un TComboBox, Un TEdit y un BitButton.

Nota: En la propiedad filter no puedes usar el Like ni comillas.

Salud OS.

Caral 26-03-2007 21:03:42

Hola Maestros
No hay manera, me genera errores, lo tengo asi:
Os muestro el codigo completo para que lo veais mejor:
El combobox1, muestra las tablas.(bien)
El combobox2, muestra los campos.(bien)
El edit1 (en el evento onchange) hace el filtro.(Mal).
Código Delphi [-]
unit UFManTablas;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, DBCtrls, DB, ADODB, Grids, DBGrids, ExtCtrls;

type
  TFManTablas = class(TForm)
    Panel1: TPanel;
    Label2: TLabel;
    ComboBox1: TComboBox;
    DBGrid1: TDBGrid;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    DBNavigator1: TDBNavigator;
    Button1: TButton;
    ComboBox2: TComboBox;
    Label1: TLabel;
    Label3: TLabel;
    Edit1: TEdit;
    Button2: TButton;
    Button3: TButton;
    procedure ComboBox1Change(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FManTablas: TFManTablas;

implementation

uses UDM1;

{$R *.dfm}

procedure TFManTablas.ComboBox1Change(Sender: TObject);
begin
    ComboBox2.Clear;
    ADOQuery1.Close;
    ADOQuery1.SQL.Text:= 'Select * from '+ComboBox1.Text;
    ADOQuery1.Open;
    DBGrid1.Columns.Clear;
    DBGrid1.Columns.State := csCustomized;
    DBGrid1.Columns[0].Width := 64;
    // con esto veo el nombre de los campos de la tabla gracias a Roman.
    DataModule1.AC1.GetFieldNames(ComboBox1.Text, ComboBox2.Items);
    
end;

procedure TFManTablas.Button1Click(Sender: TObject);
begin
  Close;
end;

procedure TFManTablas.FormCreate(Sender: TObject);
begin
   // con esto veo el nombre de las tablas garcias a Roman
   DataModule1.AC1.GetTableNames(ComboBox1.Items);
end;

procedure TFManTablas.Edit1Change(Sender: TObject);
var
//   Filtro : String;
idx :integer;
begin
//   idx := AdoQuery1.Fields.indexof(ComboBox2.items[ComboBox2.itemindex]);
/    idx := ComboBox2.ItemIndex;
     AdoQuery1.Close;
  case AdoQuery1.Fields[idx].Datatype of
     ftString   : AdoQuery1.Filter := ComboBox2.Text+ ' = '''+Edit1.Text+ '*''';
     ftInteger  : AdoQuery1.Filter := ComboBox2.Text+ ' = '+Edit1.Text;
     ftFloat,
     ftCurrency : AdoQuery1.Filter := ComboBox2.Text+ ' >= '+Edit1.Text;
     ftDate,
     ftTime     : AdoQuery1.Filter := ComboBox2.Text+ ' = '''+Edit1.Text+ '''';
  end;
  AdoQuery1.Filtered := True;
  AdoQuery1.Open;


 {  // esta opcion da un error en tiempo de diseño no en ejecucion
   // esto es por la rutina try except, que lo produce
   // no afecta el programa, filtra bien
   If (Edit1.Text <> '') then
   begin
   AdoQuery1.Filtered := false;
   try
   Filtro := ComboBox2.Text+ ' Like '''+Edit1.Text+ '*''';
   ADOQuery1.Filter := Filtro;
   ADOQuery1.Filtered := True;
  // showmessage(Filtro + '1');
   except
         Filtro := ComboBox2.Text+ ' = '+Edit1.Text;
         ADOQuery1.Filter := Filtro;
         ADOQuery1.Filtered := True;
   //       showmessage(Filtro + '2');
   end
    end
   else ADOQuery1.Filtered := False; }
 end;

procedure TFManTablas.Button2Click(Sender: TObject);
begin
  //  ADOQuery1.Close;
    Edit1.Text:= '';
end;

end.
A ver si se os ocurre algo.
Gracias
Saludos

egostar 26-03-2007 21:26:08

Hola Caral

Veo dos cosas,

1. El idx yo lo pondría en el evento onchange del combobox de los campos.

2. en el Edit1.Change veo que hay una inconsistencia que te da error cuando inicializas a '';

Código Delphi [-]
procedure TFManTablas.Edit1Change(Sender: TObject);
begin
    if Edit1.Text <> '' then begin // Solo si hay un campo a filtrar se realiza la operación.
      AdoQuery1.Close;
      case AdoQuery1.Fields[idx].Datatype of
          ftString   : AdoQuery1.Filter := ComboBox2.Text+ ' = '''+Edit1.Text+  '*''';
          ftInteger  : AdoQuery1.Filter := ComboBox2.Text+ ' = '+Edit1.Text;
          ftFloat,
          ftCurrency : AdoQuery1.Filter := ComboBox2.Text+ ' >= '+Edit1.Text;
          ftDate,
          ftTime     : AdoQuery1.Filter := ComboBox2.Text+ ' = '''+Edit1.Text+ '''';
     end;
     AdoQuery1.Filtered := True;
     AdoQuery1.Open;
  end;
end;

Salud OS.

Caral 26-03-2007 21:45:20

Hola egostar
No hay manera, segui tus explicaciones, colocando el idx en el combobox2 y me sale este error:
Cita:

List index out of bounds(441846) (
Lo curioso es que me sale un numero en un campo string, no se no me aclaro.
Saludos

roman 26-03-2007 22:23:51

Hola,

Algunas cosas que he observado:
  • El orden en que GetFieldNames regresa los campos no necesariamente coincide con el orden natural en Fields. Por tanto, no se puede tomar tal cual el índice del combo de campos como había propuesto inicialmente. En su lugar puede hacerse:

    Código Delphi [-]
    var
      FieldName: String;
      Field: TField;
      Filter: String;
    
    begin
      FieldName := cboFieldNames.Text; // tomo el nombre del campo
      Field := AdoTable.Fields.FieldByName(FieldName); // buscamos el campo por nombre
    
      case Field.Datatype of
        ..
      end;
  • Al menos en mi caso, el tipo de datos que regresa Access para un campo Texto es ftWideString y no ftString, así que hay que considerar esto en el case:

    Código Delphi [-]
      case Field.Datatype of
        ftString, ftWideString: ....
      end;
  • Luego de algunas pruebas llego al conclusión de que el #$%&@ Access (¿o será el ADO?) no acepta el '=' en la comparación de cadenas con comodín *. Debe ser como decía Caral desde un principio: like.

// Saludos


La franja horaria es GMT +2. Ahora son las 03:59:33.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi