51

(4 replies, posted in General)

vovka3003 wrote:

Может под wine.

I run MVD applications with PlayOnlinux on Linux and on Macbook through PlayOnMac. It is necessary to install the plugin through playonlinux or playonmac: msxml. Below is an example of an application I developed to run on a Macbook (OSX).

https://www.youtube.com/watch?v=gUu7wrpQZKY&t=12s

52

(5 replies, posted in General)

It's also a good option and you understand my intention to interact with the keyboard as little as possible...

53

(5 replies, posted in General)

Hi brian.zaballa, putting // is also a good alternative. Thanks for the feedback

54

(5 replies, posted in General)

This is my solution to help with debugging errors. If anyone can improve this idea or offer better alternatives, I would appreciate it.


procedure m(txt: variant; v: integer);
//*** minha solução para depurar...
begin
   if v = 1 then
       showmessage(vartostr(txt));
end;

Examples:

a = 1;
b = 'one';

displays message
m(a,1) 
m(b,1) 

or keep it in the code to display if necessary:

m(a,0);
m(b,0);

55

(0 replies, posted in General)

Based on code snippets taken from the forum and what I learned here, below is the script I am using to audit changes to a given database table. Works 100%

procedure triggers_employee;
//*** Proc 845 - auditar alterações em tabela
begin
    SQLExecute('DROP TRIGGER IF EXISTS log_insert_employee'); // how to remove trigger
    SQLExecute('DROP TRIGGER IF EXISTS log_update_employee'); // how to remove trigger
    SQLExecute('DROP TRIGGER IF EXISTS log_delete_employee'); // how to remove trigger


    // trigger when insert new a record
    SQLExecute(
    'CREATE TRIGGER IF NOT EXISTS log_insert_employee AFTER INSERT ON employees '+
    'BEGIN '+
    '    INSERT INTO tbl_auditoria_employee(employee_id,  new_lastname, new_firstname, new_dateofbirth, ocorrencia, status, nome_user) VALUES '+
    '    (NEW.id, NEW.lastname, NEW.firstname, NEW.dateofbirth,datetime(''now'', ''localtime''), ''New'',"'+nome_user+'"); '+
    'END;'
    );

    // trigger when update a record
    SQLExecute(
    'CREATE TRIGGER IF NOT EXISTS log_update_employee AFTER UPDATE ON employees '+
    'BEGIN '+
    '    INSERT INTO tbl_auditoria_employee(employee_id, old_lastname, old_firstname, old_dateofbirth, new_lastname, new_firstname, new_dateofbirth, ocorrencia,status, nome_user) VALUES '+
    '    (NEW.id, OLD.lastname, OLD.firstname, OLD.dateofbirth, NEW.lastname, NEW.firstname, NEW.dateofbirth,datetime(''now'', ''localtime''), ''Update'',"'+nome_user+'"); '+
    'END;'
    );

    // trigger when delete a record
    SQLExecute(
    'CREATE TRIGGER IF NOT EXISTS log_delete_employee AFTER DELETE ON employees '+
    'BEGIN '+
    '    INSERT INTO tbl_auditoria_employee(employee_id, old_lastname, old_firstname, old_dateofbirth, ocorrencia,status, nome_user) VALUES '+
    '    (OLD.id, OLD.lastname, OLD.firstname,OLD.dateofbirth, datetime(''now'', ''localtime''), ''Delete'',"'+nome_user+'"); '+
    'END;'
    );
end;

procedure Form1_OnShow (Sender: TObject; Action: string);
begin
    triggers_employee; //*** Proc 845 - auditar alterações em tabela
end;
procedure frmLogin_chk_menu_OnClick (Sender: TObject);
//*** Proc 834 - menu invisível do sistema é tornado vísivel pelo usuário
begin
   if frmLogin.BorderStyle = bsDialog then
      frmLogin.BorderStyle := bsSingle
   else frmLogin.BorderStyle := bsDialog;
end;

*** work

57

(14 replies, posted in General)

Hello dear K245! Thank you very much for responding promptly and for your willingness fam to do so.

58

(14 replies, posted in General)

$<

59

(14 replies, posted in General)

Does anyone know if it's possible to work with styles in version 5.6 of MVD (that's the one I bought)? I saw in the K245 projects (many good ones) that the FindComponent class or function used by him in the Camaleão project does not exist in version 5.6. I'm not a programmer, but just someone who likes programming and I've learned a lot from the forum. It's surprising to see how many want to learn and how many want to help. Congratulations to all!

60

(3 replies, posted in Reports)

Hello Sparrow, I saw your project only now. Congratulations for the initiative. This tool will greatly assist in the fast development of forms, which can be made available to the end user. Hugs.

Hi Derek, thanks for showing another alternative!
I always use the options you put in the attachment. But my script is for the case of data that will be inserted and edited only through a tablegrid. I would like to know more about triggers. For example, how to update the stock balance with each entry and exit of items. But my idea would be to place the trigger inside the database using the freeware SqliteExpert, which is what I did with the "capital letters" for the data inserted and edited through the tablegrid. If you know of any sources of information, I would appreciate it.

I share here what I have used as a solution to convert filled text fields directly through the tablegrid into uppercase. Insertion or change of record.


SQLexecute(' CREATE TRIGGER IF NOT EXISTS [nome_categoria_upper_insert] AFTER INSERT ON [tbl_categorias] '+
' BEGIN '+
'   UPDATE '+
'     [tbl_categorias] '+
'   SET '+
'     [nome_categoria] = UPPER ([nome_categoria]) '+
'   WHERE '+
'     [rowid] = [NEW].[rowid]; '+
' END; ')

SQLexecute(' CREATE TRIGGER IF NOT EXISTS [nome_categoria_upper_insert] AFTER UPDATE ON [tbl_categorias] '+
' BEGIN '+
'   UPDATE '+
'     [tbl_categorias] '+
'   SET '+
'     [nome_categoria] = UPPER ([nome_categoria]) '+
'   WHERE '+
'     [rowid] = [NEW].[rowid]; '+
' END; ')

Hi Derek, once again I gratefully receive your help. I didn't know how to materialize the idea of 2 fields and the project you sent solved the problem! Thank you very much. I'm also thinking about taking advantage of another project that you sent to Adam, where the RTF is saved in an external file. Hugs.

Hello everybody! Does anyone know how I can perform a query, using MVD's native search button, on a table that contains a field formatted in RTF?
The query, if possible, should be done with good performance and without having problems with the formatting codes, which are behind a text field edited with RTF. I've even thought about the possibility of having two fields: one in plain text format and a copy of it in another RTF field. Thank you in advance.

Hi Derek,

Very good and thank you very much for your response and promptness.

Does anyone know how to select the first row of the tablegrid after an ""aftersort"". I've tried several commands, but to no avail. I want to keep the tablegrid on the first line when sorting.

67

(5 replies, posted in General)

functions created from the substrings project written by Derek, above


//=================================================================
function left_mid_str(word:string;pos_ini:integer;len_sub:integer): string;
begin
    result := copy(word,pos_ini,len_sub);
end;
//=================================================================
function rigth_str(word:string;len_sub:integer): string;
begin
    result := copy(word,(length(word)-len_sub+1),len_sub);
end;
//=================================================================
procedure Form1_OnShow (Sender: TObject; Action: string);
begin
    showmessage(left_mid_str('1234567890',1,3));
    showmessage(rigth_str('1234567890',3));
end;

Hi Sparrow, thanks with the syntax of the "case". I will use your code to adjust mine. Hugs.

Hi Derek, thanks again for your generosity. I set up another solution, which follows below, because I have 32,000 records in a table and 12,000 in another. The solution you suggested is also quite interesting and I intend to use it in other applications. I looked in the forum if there is the condition "case and end case", which exists in other languages, such as visual foxpro. In the script below I used "if" a lot, when I could perhaps use "case" if it existed in the MVD. Hugs.

var
   limit_grid: integer = 5000; //limita linhas da consulta
   Chart: TChart;  //usado no overview

procedure frmOverview_TableGrid1_OnCellDoubleClick (Sender: TObject; ACol, ARow: Integer);
//quando uma das combobox (cbDim1 ou cbDim2) contiver nome cliente (opção 8), o registro do
//cliente poderá ser acessado via frm_clientes se houver um doubleclick no grid
var
    posicao, id_cliente : integer;
    campo_txt: string;
begin
    campo_txt := '';
    if frmOverview.cbDim1.ItemIndex = 8 then
       campo_txt := frmOverview.TableGrid1.Cells[0,Arow]
    else if frmOverview.cbDim2.ItemIndex = 8 then
       campo_txt := frmOverview.TableGrid1.Cells[1,Arow];

    posicao := pos('ID:',campo_txt);
    if posicao <> 0 then
    begin
       id_cliente := strtoint(rigth_left(campo_txt,posicao+3,10));
       frm_clientes.ShowRecord('tbl_clientes',id_cliente);
    end;
end;

procedure frmOverview_btn_mais_linhas_OnClick (Sender: TObject; var Cancel: boolean);
begin
    limit_grid := 10000000;  //retira limita de linhas da consulta
    atualiza_overview;
    limit_grid := 5000; //retoma limite
end;

function rigth_left(word:string;pos_ini:integer;num_char:integer): string;
//*** extrai substring partir da posição e número de caracteres informados na chamada
begin
    result := copy(word,pos_ini,num_char);
end;


procedure frmOverview_TableGrid1_OnAfterSort (Sender: TObject; ACol: Integer);
begin
//   frmOverview.TableGrid1.SelectedRow := 0;
end;

procedure frmOverview_btn_limpa_OnClick (Sender: TObject; var Cancel: boolean);
begin
    //limpa compos usados no filtro da cláusula Where  (clear compounds used in Where clause filter)
    frmOverview.cbo_ano.dbItemID := -1;
    frmOverview.cbo_aparelho.dbItemID := -1;
    frmOverview.cbo_marca.dbItemID := -1;
    frmOverview.cbo_mes.dbItemID := -1;
    frmOverview.Edit_bairro.Text := '';
    frmOverview.Edit_cliente.Text := '';
    frmOverview.Edit_ID.text := '';
    frmOverview.Edit_modelo.text := '';
    frmOverview.Edit_pagto.text := '';
    frmOverview.DateTimePicker_ate.Checked := false;
    frmOverview.DateTimePicker_de.Checked := false;
end;

procedure frmOverview_btn_update_OnClick (Sender: TObject; var Cancel: boolean);
begin
    atualiza_overview;
end;

procedure frmOverview_cbDim2_OnChange (Sender: TObject);
var c: integer;
begin
    atualiza_overview;
end;

procedure frmOverview_cbDim1_OnChange (Sender: TObject);
begin
          atualiza_overview;
end;

procedure Form1_OnShow (Sender: TObject; Action: string);
begin
    frmoverview.BorderIcons := 5;

    //CBDIM1
    frmOverview.cbDim1.Items.Clear;
    frmOverview.cbDim1.Items.Add ('0 Bairro');
    frmOverview.cbDim1.Items.Add ('1 Aparelho');
    frmOverview.cbDim1.Items.Add ('2 Marca');
    frmOverview.cbDim1.Items.Add ('3 Modelo');
    frmOverview.cbDim1.Items.Add ('4 Ano Entrada');
    frmOverview.cbDim1.Items.Add ('5 Mês Entrada');
    frmOverview.cbDim1.Items.Add ('6 Ano-Mês Entrada');
    frmOverview.cbDim1.Items.Add ('7 Forma Pagto');
    frmOverview.cbDim1.Items.Add ('8 Cliente');
    //CBDIM2
    frmOverview.cbDim2.Items.Clear;
    frmOverview.cbDim2.Items.Add ('0 Bairro');
    frmOverview.cbDim2.Items.Add ('1 Aparelho');
    frmOverview.cbDim2.Items.Add ('2 Marca');
    frmOverview.cbDim2.Items.Add ('3 Modelo');
    frmOverview.cbDim2.Items.Add ('4 Ano Entrada');
    frmOverview.cbDim2.Items.Add ('5 Mês Entrada');
    frmOverview.cbDim2.Items.Add ('6 Ano-Mês Entrada');
    frmOverview.cbDim2.Items.Add ('7 Forma Pagto');
    frmOverview.cbDim2.Items.Add ('8 Cliente');

    //fixa primeiro item na abertura do formulário (fixed first item on form opening)
    frmOverview.cbDim1.ItemIndex := 4;
    frmOverview.cbDim2.ItemIndex := 4;

    //carrega dados nas combobox utilizadas na busca cláusula Where  (// load data in the combobox used in the Where clause search)
    frmOverview.cbo_ano.dbSQLExecute('select strftime("%Y",tbl_orderm_servico.entrada) as ano from tbl_orderm_servico group by ano order by 1');
    frmOverview.cbo_mes.dbSQLExecute('select strftime("%m",tbl_orderm_servico.entrada) as mes from tbl_orderm_servico group by mes order by 1');
    frmOverview.cbo_aparelho.dbSQLExecute('select aparelho, id from tbl_aparelhos order by 1');
    frmOverview.cbo_marca.dbSQLExecute('select marca, id from tbl_marcas order by 1');

{== BAR CHART ====}    //parâmetros para o gráfico de barras
    Chart := TChart.Create(frmOverview);
    Chart.Parent := frmOverview.panelbar1;
    Chart.Align := alClient;
    Chart.AddSeries(ThorizBarSeries.Create(Chart));
    Chart.View3D := true;
    //frmOverview.bLineUpdate.Click;
{== BAR CHART ====}

    atualiza_overview;
end;

procedure atualiza_overview;
//**** aciona geração da consulta e do gráfico de barras
var
    txt_sel, txt_sel1, txt_where: string;
    c,i: integer;
    total_grid: real = 0;
    Results: TDataSet;
    x_value: string;
    cf_y: string;
    y: integer;
begin

    //Usuário define que campos da query serão exibidos na primeira e segunda coluna da consulta
    //User defines which query fields will be displayed in the first and second column of the query

  txt_Sel := '';
  txt_Sel1 := '';
  //contribuição do Sparrow - campos que serão utilizados na consulta
  CASE frmOverview.cbDim1.itemindex of
    0:  txt_Sel1 := 'tbl_clientes.bairro AS Bairro';
    1:    txt_Sel1 := 'tbl_aparelhos.aparelho AS Aparelho';
    2:    txt_Sel1 := 'tbl_marcas.marca AS Marca';
    3:    txt_Sel1 := 'tbl_orderm_servico.modelo AS Modelo';
    4:    txt_Sel1 := 'strftime("%Y",tbl_orderm_servico.entrada) AS Ano';
    5:    txt_Sel1 := 'strftime("%m",tbl_orderm_servico.entrada) AS Mês';
    6:    txt_Sel1 := 'strftime("%Y-%m",tbl_orderm_servico.entrada) AS Ano_Mês';
    7:    txt_Sel1 := 'tbl_orderm_servico.pagamento AS "Forma Pagto"';
    8:    txt_Sel1 := 'tbl_clientes.nome||" - ID:"||tbl_clientes.id AS Cliente';
  end;

  CASE frmOverview.cbDim2.itemindex of
    0:  txt_Sel := txt_Sel1 + ', tbl_clientes.bairro AS Bairro';
    1:    txt_Sel := txt_Sel1 + ', tbl_aparelhos.aparelho AS Aparelho';
    2:    txt_Sel := txt_Sel1 + ', tbl_marcas.marca AS Marca';
    3:    txt_Sel := txt_Sel1 + ', tbl_orderm_servico.modelo AS Modelo';
    4:    txt_Sel := txt_Sel1 + ', strftime("%Y",tbl_orderm_servico.entrada) AS Ano';
    5:    txt_Sel := txt_Sel1 + ', strftime("%m",tbl_orderm_servico.entrada) AS Mês';
    6:    txt_Sel := txt_Sel1 + ', strftime("%Y-%m",tbl_orderm_servico.entrada) AS Ano_Mês';
    7:    txt_Sel := txt_Sel1 + ', tbl_orderm_servico.pagamento AS "Forma Pagto"';
    8:    txt_Sel := txt_Sel1 + ', tbl_clientes.nome||" - ID:"||tbl_clientes.id AS Cliente';
  end;

    txt_where :=
    '(CASE WHEN '+inttostr(frmOverview.cbo_ano.ItemIndex)+'     = -1 THEN 1=1 ELSE strftime("%Y",tbl_orderm_servico.entrada) = "'+frmOverview.cbo_ano.Text+'" END) AND '+
    '(CASE WHEN '+inttostr(frmOverview.cbo_mes.ItemIndex)+'     = -1 THEN 1=1 ELSE strftime("%m",tbl_orderm_servico.entrada) = "'+frmOverview.cbo_mes.Text+'" END) AND '+
    '(CASE WHEN '+inttostr(frmOverview.cbo_aparelho.dbitemid)+' = -1 THEN 1=1 ELSE tbl_orderm_servico.id_tbl_aparelhos = '+inttostr(frmOverview.cbo_aparelho.dbitemid)+' END) AND '+
    '(CASE WHEN '+inttostr(frmOverview.cbo_marca.dbitemid)+'    = -1 THEN 1=1 ELSE tbl_orderm_servico.id_tbl_marcas = '+inttostr(frmOverview.cbo_marca.dbitemid)+' END) AND '+
    '(CASE WHEN LENGTH("'+frmOverview.Edit_cliente.Text+'")     =  0 THEN 1=1 ELSE tbl_clientes.nome LIKE "%'+frmOverview.Edit_cliente.Text+'%" END) AND '+
    '(CASE WHEN LENGTH("'+frmOverview.Edit_ID.Text+'")          =  0 THEN 1=1 ELSE tbl_clientes.id = "'+frmOverview.Edit_ID.Text+'" END) AND '+
    '(CASE WHEN LENGTH("'+frmOverview.Edit_bairro.Text+'")      =  0 THEN 1=1 ELSE tbl_clientes.bairro LIKE "%'+frmOverview.Edit_bairro.Text+'%" END) AND '+
    '(CASE WHEN LENGTH("'+frmOverview.Edit_modelo.Text+'")      =  0 THEN 1=1 ELSE tbl_orderm_servico.modelo LIKE "%'+frmOverview.Edit_modelo.Text+'%" END) AND '+
    '(CASE WHEN LENGTH("'+frmOverview.Edit_pagto.Text+'")       =  0 THEN 1=1 ELSE tbl_orderm_servico.pagamento LIKE "%'+frmOverview.Edit_pagto.Text+'%" END) AND '+
    '(CASE WHEN '+frmOverview.DateTimePicker_de.sqlDateTime+' IS NULL THEN 1=1 ELSE strftime("%Y-%m-%d %H:%M:%f",tbl_orderm_servico.entrada) >= '+frmOverview.DateTimePicker_de.sqlDatetime+' END) AND '+
    '(CASE WHEN '+frmOverview.DateTimePicker_ate.sqlDateTime+' IS NULL THEN 1=1 ELSE strftime("%Y-%m-%d %H:%M:%f",tbl_orderm_servico.entrada) <= '+frmOverview.DateTimePicker_ate.sqlDatetime+' END)';


    //Query que preencherá o tablegrid1   (Query that will populate the tablegrid1)
    frmoverview.TableGrid1.dbSQL :=
    ' SELECT '+
              txt_sel+' , '+
    '         SUM( "tbl_orderm_servico"."valor_servicos" + "tbl_orderm_servico"."valor_pecas") as "Vlr Total" , '+
    '         0 as "Perc%", '+
    '         COUNT( "tbl_orderm_servico"."id" )  AS "Qtde os" '+
    ' FROM     "tbl_clientes" '+
    ' INNER JOIN "tbl_orderm_servico"  ON "tbl_clientes"."id" = "tbl_orderm_servico"."id_tbl_clientes" '+
    ' LEFT OUTER JOIN "tbl_aparelhos"  ON "tbl_aparelhos"."id" = "tbl_orderm_servico"."id_tbl_aparelhos" '+
    ' LEFT OUTER JOIN "tbl_marcas"  ON "tbl_marcas"."id" = "tbl_orderm_servico"."id_tbl_marcas" '+
    ' WHERE '+txt_where+
    ' GROUP BY 1, 2 ORDER by 1, 2 LIMIT '+inttostr(limit_grid);
    frmoverview.TableGrid1.dbSQLExecute; //executa o query

    c := frmOverview.TableGrid1.RowCount - 1;
    for i := 0 to c do  //soma e obtém total da coluna de valores
    begin
        if strtofloat(frmOverview.TableGrid1.Cells[2, i]) <0 then i := i + 1 else
        total_grid := total_grid + strtofloat(frmOverview.TableGrid1.Cells[2, i]);
    end;

    if total_grid <> 0 then  //evita dividir por zero
    begin
        c := frmOverview.TableGrid1.RowCount - 1;
        for i := 0 to c do  //calcula partipação de cada valor sobre o total acima
        begin
            if strtofloat(frmOverview.TableGrid1.Cells[2, i]) <0 then i := i + 1 else
            frmOverview.TableGrid1.Cells[3, i] := floattostr((strtofloat(frmOverview.TableGrid1.Cells[2, i]) / total_grid)*100);
        end;
    end;

    frmOverview.TableGrid1.CalculateFooter;

    frmOverview.TableGrid1.EndUpdate;

    //frmOverview.TableGrid1.BestFitColumns(bfBoth);
    //*** deve ser colocado no begin-end do final    frmOverview.TableGrid1.Options := frmOverview.TableGrid1.Options + goFooter;

    TNxNumberColumn(frmOverview.TableGrid1.Columns[3]).FormatMask := '##0.00%';
    TNxNumberColumn(frmOverview.TableGrid1.Columns[3]).Footer.FormatMask := '##0.00';

    //formata colunas numéricas (format numeric columns)
    TNxNumberColumn(frmoverview.TableGrid1.Columns[2]).FormatMask := '###,###,##0.00';
    TNxNumberColumn(frmoverview.TableGrid1.Columns[3]).FormatMask := '##0.00';
    frmoverview.TableGrid1.Columns[2].Alignment := taRightJustify;

    //preenche rodapé com totais para determinadas colunas
    //fills footer with totals for certain columns
    frmOverview.TableGrid1.Columns[0].Footer.Caption := 'Total Linhas: ';
    frmOverview.TableGrid1.Columns[1].Footer.FormulaKind := fkCount;
    frmOverview.TableGrid1.Columns[2].Footer.FormulaKind := fkSum;
    TNxNumberColumn(frmOverview.TableGrid1.Columns[2]).Footer.FormatMask := '###,###,##0.00';
    TNxNumberColumn(frmOverview.TableGrid1.Columns[3]).Footer.FormatMask := '##0.0';
    frmOverview.TableGrid1.Columns[3].Footer.FormulaKind := fkSum; //soma qtde
    frmOverview.TableGrid1.Columns[4].Footer.FormulaKind := fkSum; //soma qtde

    frmOverview.TableGrid1.CalculateFooter; //gera totais no rodapé (generate totals in footer)

    //frmOverview.TableGrid1.BestFitColumns(bfboth); // ajusta largura colunas automátciamente

    Chart.Series[0].Clear;
    Chart.Legend.Visible := false;


   //grava dados na tabela que alimenta gráfico
    y:= 1;
    SQLexecute('DELETE FROM bar_data');
    SQLExecute('INSERT INTO bar_data (eixo_x, eixo_y) '+
    ' SELECT '+
              txt_sel1+' , '+
    '         SUM( "tbl_orderm_servico"."valor_servicos" + "tbl_orderm_servico"."valor_pecas") as "Vlr Total" '+
    ' FROM    "tbl_clientes" '+
    ' INNER JOIN "tbl_orderm_servico"  ON "tbl_clientes"."id" = "tbl_orderm_servico"."id_tbl_clientes" '+
    ' LEFT OUTER JOIN "tbl_aparelhos"  ON "tbl_aparelhos"."id" = "tbl_orderm_servico"."id_tbl_aparelhos" '+
    ' LEFT OUTER JOIN "tbl_marcas"  ON "tbl_marcas"."id" = "tbl_orderm_servico"."id_tbl_marcas" '+
    ' WHERE '+txt_where+
    ' GROUP BY 1 ORDER by 1 LIMIT '+inttostr(limit_grid));

    SQLQuery('SELECT eixo_x, sum(round(eixo_y,0)) As cf_eixo_y FROM bar_data group by eixo_x order by eixo_x desc' , Results);

    while not Results.Eof do
    begin
        x_value := Results.FieldByName('eixo_x').asString;
        cf_y := Results.FieldByName('cf_eixo_y').asstring;
        if ValidInt(cf_y) then Chart.Series[0].AddXY(strtoint(cf_y),y,x_value);
        Results.Next;
        inc(y);
    end;
    Results.Free;
   //grava dados na tabela que alimenta gráfico

end;


begin

end.

Hi Derek, thank you so much for your prompt reply! I'm studying the project you sent to adapt it to my needs. Thank you one more time! Roberto

I would like to create an MVD application, which allows the user to include fields from a table in a tablegrid from a list of fields. My idea is to create a view containing several database tables, totaling numerical fields and, as the user changes the grid fields, this would affect these sums of values. For example: grid header: Categories, sales value. The user could exchange category for customers. Thus, the total sales values per category would be presented by customers. I hope I managed to explain myself. Thanks for any help.

K245, obrigado pelo exemplo que enviou.

Acabei criando minha própria solução, mas pretendo analisar melhor a sua proposta. Abraços.

procedure frm_lista_os_btn_busca_OnClick (Sender: TObject; var Cancel: boolean);
var
   dados_filtro : string;
begin
   dados_filtro := '';

   dados_filtro :=
   frm_lista_os.Edit_ID.text +
   frm_lista_os.cbo_cliente.text +
   frm_lista_os.cbo_aparelho.text +
   frm_lista_os.cbo_marca.text +
   iif2(frm_lista_os.chk_impresso.sqlValue = 'NULL','','*') +
   iif2(frm_lista_os.DateTimePicker_aprovacao.sqlDate = 'NULL','','*') +
   iif2(frm_lista_os.DateTimePicker_entrada.sqlDate = 'NULL','','*') +
   iif2(frm_lista_os.DateTimePicker_entrega.sqlDate = 'NULL','','*') +
   frm_lista_os.Edit_modelo.text +
   frm_lista_os.Edit_obs.text +
   frm_lista_os.Edit_pagto.text +
   frm_lista_os.Edit_pecas.text +
   frm_lista_os.Edit_serie.text;

   //showmessage(dados_filtro);
   //frm_lista_os.TableGrid_OS.dbLimit := 500;

   if length(dados_filtro) then
       frm_lista_os.TableGrid_OS.dbLimit := 0
   else
   begin
         if messagedlg('Exibe: (Yes) todos ou (No) somente 500 ?',mtwarning,mbyes+mbno,0) = mryes then
            frm_lista_os.TableGrid_OS.dbLimit := 0
         else
            frm_lista_os.TableGrid_OS.dbLimit := 500;
   end;
end;

Function IIF2( bln:boolean; TruePart:string; FalsePart:string):string;
begin
  if bln then
    Result := TruePart
  else
    Result := FalsePart;
end;

I've been using a form with a tablegrid to access 32,000 records. The tablegrid is loaded through a button with the search function, native to MVD, and the grid line colors are alternated with the script below, which I got from this forum. I know that if the grid has many columns, it will take a longer time to load the data. Does anyone know if there's a solution for this? MVD is fantastic, but I've run into this problem in a few applications I've built. Would it be the case of having a script that loaded only part of the tablegrid and loaded the rest of the records as the user clicked on pageup or pagedown?

procedure alterna_cor_linha_os;
//*** Proc 741 - alterna cor nas linhas de um grid - procedure serve para qualquer grid
begin
  ColorRowGrid(frm_lista_os.TableGrid_OS,clWindow,$00C6E2FF, false);
end;

procedure ColorRowGrid (Grid:TdbStringGridEx;ColorEven,ColorOdd:TColor;ajusta:boolean);
//*** Proc 741 - alterna cor nas linhas de um grid - procedure serve para qualquer grid
var
   iRow ,c: integer;
   q, iCol: integer;
begin
     Grid.BeginUpdate;
     c := Grid.RowCount - 1;
     q := Grid.Columns.Count-1;
     for iRow := 0 to c do
         for iCol := 0 to q do
         begin
             if iRow mod 2 = 0 then Grid.Cell[iCol,iRow].Color := ColorEven
             else
             Grid.Cell[iCol,iRow].Color := ColorOdd;
         end;
         if ajusta then Grid.BestFitColumns(bfBoth); //ajusta conteúdo no tablegrid
     Grid.EndUpdate;
end;

Derek and Pavlenko, muito obrigado e parabéns a vocês dois.

Can someone help me? The code below doesn't work, because when the record is deleted, sqlite ignores ID that has already been deleted. For example: ID 200 deleted. The statement "sqlexecute('select max(id) from people') + 1" will generate an ID 200, but sqlite will provide ID 201. Is there any routine that informs which new ID will be provided by sqlite?


procedure form2_OnShow (Sender: string; Action: string);
begin

  if action <> 'NewRecord' then form2.edit1.Value:= sqlexecute('select id from people where id =' +inttostr(form1.tablegrid1.dbitemid));
  if action = 'NewRecord' then form2.edit1.value:= sqlexecute('select max(id) from people') + 1;

end;