Page 1 of 2 1 2 LastLast
Results 1 to 15 of 16

Thread: At beginning of table

  1. #1

    Red face At beginning of table

    Goedemiddag,

    Ik maak gebruik van een cxgrid en heb in de clientdataset een autoinc veld staan.
    Nu wil ik een regel (record) tussen voegen en daarvoor maak ik eerst een lege record aan (append).
    Daarna verschuif ik net zo lang alle records naar onderen totdat ik bij mijn record aankom waar de focus op lag.
    Deze record maak ik tenslotte helemaal leeg, behalve het autoinc veld natuurlijk niet.

    Deze procedure roep ik aan via een popupmenu met de onderstaande code...

    Code:
    procedure TForm1.Tussenvoegennieuweregel1Click(Sender: TObject);
    Var aField : Variant;
        i, Lus1, CurrentRecordNr, TotaalAantaRecords: Integer;
    
    begin
    CurrentRecordNr:=ClientDataSetInhoudB.RecNo;
    TotaalAantaRecords:=ClientDataSetInhoudB.RecordCount;
    ClientDataSetInhoudB.DisableControls;
    ClientDataSetInhoudB.Last;
      // Append een nieuw record
      aField := VarArrayCreate(
                   [0,ClientDataSetInhoudB.Fieldcount-1],
                                 VarVariant);
      for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
      begin
         aField[i] := ClientDataSetInhoudB.fields[i].Value ;
      end;
      ClientDataSetInhoudB.Append ;
      for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
      begin
         ClientDataSetInhoudB.fields[i].Value := aField[i] ;
      end;
      ClientDataSetInhoudB.Post;
    
    for Lus1 := TotaalAantaRecords downto CurrentRecordNr do
       begin
        ClientDataSetInhoudB.RecNo:=Lus1;
          aField := VarArrayCreate(
                       [0,ClientDataSetInhoudB.Fieldcount-1],
                                     VarVariant);
          for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
          begin
             aField[i] := ClientDataSetInhoudB.fields[i].Value ;
          end;
          ClientDataSetInhoudB.Next;
          ClientDataSetInhoudB.edit;
          for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
          begin
             ClientDataSetInhoudB.fields[i].Value := aField[i] ;
          end;
          ClientDataSetInhoudB.Post;
       end;
    
    ClientDataSetInhoudB.Prior;
    ClientDataSetInhoudB.edit;
     for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do ClientDataSetInhoudB.Fields[i].Clear;
    ClientDataSetInhoudB.FieldByName('Geleverd').AsBoolean:= False;
    ClientDataSetInhoudB.FieldByName('IngevoerdDoorUser').AsString:=User;
    ClientDataSetInhoudB.Post;
    ClientDataSetInhoudB.EnableControls;
    end;
    Dit werkt feilloos

    Maar als ik deze procedure aanspreek doormiddel van een druk op een button...

    Code:
    Tussenvoegennieuweregel1Click(self);
    Dan krijg ik na een aantal keer op de button te hebben gedrukt de foutmelding AT BEGINNING OF TABLE en loopt de gehele dataset vast zodat ik eerst het programma moet afsluiten.

    Heeft iemand hier een logische verklaring voor?

  2. #2
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Gebruik nooit loops (for..to..do, while..do, repeat..until) in datasets icm RecordCount.

    RecordCount is slechts een indicatie van het aantal records, niet alle DB's geven de echte count weer.
    Ook is RecordCount niet het laatste record en de property RecNo geeft niet per se de index aan van
    het huidige record (data is niet zomaar sequencieel).

    Te allen tijde gebruik je bij datasets First (eerste), Last (laatste), Next (volgende), Prior (vorige) om
    te navigeren door de data en Bof ("Beginning Of File") en Eof ("End Of File") om te kijken of je aan
    het begin danwel einde van je dataset zit.

    RecordCount is alleen leuk voor een TProgressBar e.d.
    TMemoryLeak.Create(Nil);

  3. #3
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    En ik snap het tweede gedeelte niet. Het lijkt erop dat je alles 1 plaats naar beneden plaatst. De laatste lukt niet omdat het al de eerste record heeft bereikt. Ik sla Peters raad in de wind en denk dat dit je oplossing is:
    Delphi Code:
    1. repeat
    2.    begin
    3.     ClientDataSetInhoudB.RecNo:=Lus1;
    4.       aField := VarArrayCreate(
    5.                    [0,ClientDataSetInhoudB.Fieldcount-1],
    6.                                  VarVariant);
    7.       for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
    8.       begin
    9.          aField[i] := ClientDataSetInhoudB.fields[i].Value ;
    10.       end;
    11.       ClientDataSetInhoudB.Next;
    12.       ClientDataSetInhoudB.edit;
    13.       for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
    14.       begin
    15.          ClientDataSetInhoudB.fields[i].Value := aField[i] ;
    16.       end;
    17.       ClientDataSetInhoudB.Post;
    18.    until ClientDataSetInhoudB.bof;
    (niet getest)
    Delphi is great. Lazarus is more powerfull

  4. #4
    Quote Originally Posted by jkuiper View Post
    En ik snap het tweede gedeelte niet. Het lijkt erop dat je alles 1 plaats naar beneden plaatst. De laatste lukt niet omdat het al de eerste record heeft bereikt.
    In het 2e gedeelte plaats ik inderdaad alles naar beneden tot aan het record waar de focus op lag.
    Dit is dus niet het begin van de cliënt dataset maar kan bijvoorbeeld het 5e record zijn.

    De repeat - until voorbeeld dat je geeft loopt door tot aan het 1e record
    Last edited by willempie123; 20-Apr-18 at 00:26.

  5. #5
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Ja, maar ik zie nu in je code dat dat niet zal moeten.
    Waarom moet de focus liggen op het pas aangemaakte record?
    Al het iets te maken heeft met planning, dan kan je het beste gebruik maken van fieldindexen.
    Nu ben je records aan het verplaatsen, wat helemaal niet nodig is en gebruikt veel te veel resources voor één ding.

    Ik snap dan ook niet wat je precies aan het doen bent.
    Mischien als je uitlegt wat de bedoeling is dat ik (of een ander) een beter voorbeeld voor je kunnen maken wat veel effectiever is dan alle records te verplaatsen.
    Delphi is great. Lazarus is more powerfull

  6. #6
    Ik ben bezig met een factuur programma zoals te zien is in de afbeelding

    Click image for larger version. 

Name:	Schermafbeelding 2018-04-20 om 08.36.43.jpg 
Views:	189 
Size:	87.9 KB 
ID:	7748

    Nu was mijn bedoeling dat ik dus een record tussen bijvoorbeeld de 2e en de 3e record toe wil voegen.
    De dataset heeft een Autoinc veld waardoor ik dus geen normale insert comando kan geven.

    Ik begin dus met de focus van het record op te slaan in de variabel "CurrentRecordNr".

    Code:
    CurrentRecordNr:=ClientDataSetInhoudB.RecNo;
    TotaalAantaRecords:=ClientDataSetInhoudB.RecordCount;
    ClientDataSetInhoudB.DisableControls;
    ClientDataSetInhoudB.Last;
    Daarvna ga ik dus eerst een lege regel toevoegen en vul deze met de onderste bestaande record...

    Code:
      // Append een nieuw record
      aField := VarArrayCreate(
                   [0,ClientDataSetInhoudB.Fieldcount-1],
                                 VarVariant);
      for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
      begin
         aField[i] := ClientDataSetInhoudB.fields[i].Value ;
      end;
      ClientDataSetInhoudB.Append ;
      for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
      begin
         ClientDataSetInhoudB.fields[i].Value := aField[i] ;
      end;
    Daarna verschuif ik net zolang de bestaande record naar onderen tot de record waar de focus op lag in het factuur programma.

    Code:
    for Lus1 := TotaalAantaRecords downto CurrentRecordNr do
       begin
        ClientDataSetInhoudB.RecNo:=Lus1;
          // Create a variant Array
          aField := VarArrayCreate(
                       [0,ClientDataSetInhoudB.Fieldcount-1],
                                     VarVariant);
          // read values into the array
          for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
          begin
             aField[i] := ClientDataSetInhoudB.fields[i].Value ;
          end;
          ClientDataSetInhoudB.Next;
          ClientDataSetInhoudB.edit;
          // Put array values into new the record
          for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do
          begin
             ClientDataSetInhoudB.fields[i].Value := aField[i] ;
          end;
          ClientDataSetInhoudB.Post;
       end;
    Tot slot nog een kleine afhandeling zodat het nieuw tussengevoegd record wordt gevuld met de belangrijkste gegevens.

    Code:
    ClientDataSetInhoudB.Prior;
    ClientDataSetInhoudB.edit;
     for i := 1 to (ClientDataSetInhoudB.Fieldcount-1) do ClientDataSetInhoudB.Fields[i].Clear;
    ClientDataSetInhoudB.FieldByName('Geleverd').AsBoolean:= False;
    ClientDataSetInhoudB.FieldByName('IngevoerdDoorUser').AsString:=User;
    ClientDataSetInhoudB.Post;
    ClientDataSetInhoudB.EnableControls;
    Nu heb ik aan de xgrid een popupmenu toegevoegd waarbij een druk op de knop in het popupmenu deze code wordt aangeroepen.
    Ik kan tig keer via de popupmenu een lege regel toevoegen zonder problemen.

    Click image for larger version. 

Name:	Schermafbeelding 2018-04-20 om 08.52.37.png 
Views:	121 
Size:	38.8 KB 
ID:	7749

    Als ik echter via devolgende manier een regel tussenvoeg dan krijg ik na een aantal keer die vervelende foutmelding

    Code:
    procedure TForm1.cxGridDBTableView5EditKeyDown(Sender: TcxCustomGridTableView;
      AItem: TcxCustomGridTableItem; AEdit: TcxCustomEdit; var Key: Word;
      Shift: TShiftState);
    begin
    if Key=VK_INSERT then Tussenvoegennieuweregel1Click(self);

  7. #7
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Mag ik vragen waarom er een record tussen moet en niet aan het eind?
    De dataset heeft een Autoinc veld waardoor ik dus geen normale insert comando kan geven.
    Als dat de primary key is, zal ik daar niet mijn probleem opleggen, maar meer op de index / filter van het bestand.
    Delphi is great. Lazarus is more powerfull

  8. #8
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Ik denk dat je een veel gemaakte (beginners) fout maakt, Willem.
    De opslag en weergave van data moet je gescheiden zien (en maken).

    Data sla je gewoon achter elkaar op (kunnen zelfs factuurregels van totaal verschillende facturen
    achter elkaar zijn) en om een autoinc-veld op te nemen is geen slecht idee, maar dit veld is dan
    alleen om regels uniek te maken en tussen verschillende tabellen onderling aan elkaar te kunnen
    linken (master-detail e.d.).

    De weergave van de data staat helemaal los van de data zelf en regel je door je query aan te passen
    aan de eis of door gebruik te maken van filtering/sortering bij het ophalen.
    TMemoryLeak.Create(Nil);

  9. #9
    Ik maak dagelijks heel veel fouten en ben blij dat er mensen zijn zoals jullie die mij daarop wijzen.

    Als ik dus Videoripper goed begrijp zou ik dus een extra field in de tabel inhoudB moeten maken waarin ik de volgorde van de regels van de begroting bijhoud en de cxgrid op deze field gaan sorteren en dus niet het Autoinc field zoals ik nu doe.

    Als dit dus de oplossing hoort te zijn dan snap ik de reactie van jkuiper ook
    Ik hoor dus niet met het unieke veld te gaan knoeien.

    Ik heb het Autoinc field nodig om de clientdataset te updaten via Unidac.
    Deze heeft daarvoor een uniek veld nodig.

  10. #10
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Als het inderdaad wenselijk is dat je op data-niveau een sortering aanbrengt (dat kán een keuze zijn),
    dan is het toevoegen van een index-veld een goede optie.
    In je dataset die aan de grid hangt sorteer je dan op dit index-veld.

    Bij het aanmaken van de initiële factuurregels laat je een teller meelopen die dit index-veld ophoogt
    (eventueel kun je ook een "-1"-optie inbouwen voor als volgorde niet van belang is voor die regel)
    en als je een regel tussen wil voegen, dan verhoog je de index-kolom van iedere regel die ná deze
    factuurregel komt met één.

    Wanneer je klaar bent met het invoegen van regels ververs je de dataset die aan je grid hangt.
    TMemoryLeak.Create(Nil);

  11. #11
    John Kuiper
    Join Date
    Apr 2007
    Location
    Almere
    Posts
    8,747
    Als dit dus de oplossing hoort te zijn dan snap ik de reactie van jkuiper ook
    Ik hoor dus niet met het unieke veld te gaan knoeien.
    Het is niet wenselijk en het zorgt voor heel veel stress om het goed voor elkaar te krijgen.
    Je begrotingstabel heeft klaarblijkelijk een detail tabel waarin je dus die verschillende regels plaatst. Geef in de detail dat nummer mee. Dan heb je altijd gescheiden data, die je altijd kan koppelen aan je master. Je haalt dan ook alleen maar de records op, die gekoppeld zijn aan de master tabel. Met property fieldindex kan je dan sorteren in je grid. Moet er toevallig een record toevoegen die er eigenlijk er tussen moet, kan je deze aan het einde aanmaken. De fieldindex zorgt er dan weer voor dat die regel netjes tussen de andere regels komt, zoals de sortering wenst.
    Delphi is great. Lazarus is more powerfull

  12. #12
    Na ruim 10 uur denken, denken en denken kan de vlag uit.

    Het werkt eindelijk zoals ik het in gedachten had.

    Code:
    procedure TForm1.Tussenvoegennieuweregel1Click(Sender: TObject);
    Var CurrentRecordNr, CurrentGridRecordNr: Integer;
    
    begin
    CurrentRecordNr:=ClientDataSetInhoudB.FieldByName('Autoinc').AsInteger;
    CurrentGridRecordNr:=cxGridDBTableView5.Controller.FocusedRow.Index;
    ClientDataSetInhoudB.DisableControls;
    
    ClientDataSetInhoudB.First;
     repeat
      if ClientDataSetInhoudB.FieldByName('Autoinc').AsInteger>=CurrentRecordNr then
        begin
          ClientDataSetInhoudB.Edit;
          ClientDataSetInhoudB.FieldByName('Autoinc').AsInteger:=ClientDataSetInhoudB.FieldByName('Autoinc').AsInteger+1;
          ClientDataSetInhoudB.Post;
        end;
      ClientDataSetInhoudB.Next;
     until ClientDataSetInhoudB.Eof;
    
    ClientDataSetInhoudB.AppendRecord([nil,nil,CurrentRecordNr,nil,nil,nil,nil,nil,nil,nil,False,nil,User]);
    Databasebijwerken;
    CheckLegeRegelInhoudB;
    inc(TellerInhoudB);
    ClientDataSetInhoudB.RecNo:=CurrentGridRecordNr+1;
    cxGridDBTableView5.Controller.FocusRecord(cxGridDBTableView5.Controller.FocusedRow.Index,True);
    ClientDataSetInhoudB.EnableControls;
    end;

  13. #13
    Ik zou er alleen een while not Eof lus van maken. Met repeat until ga je ook een regel editen als de dataset leeg is, en dat levert waarschijnlijk een foutmelding op.
    1+1=b

  14. #14
    Kijk ook eens op:

    http://caryjensen.blogspot.nl/2013/0...n-dbgrids.html

    Hier staat naar mijn idee exact wat je zoekt.

  15. #15
    TDigitalTrain user Hans Brenkman's Avatar
    Join Date
    Mar 2002
    Location
    Weert
    Posts
    1,861
    Volgens mij is het behoorlijk linke soep.

    Op de 1e plaats zou je absoluut van dat AutoInc field af moeten blijven.
    Op de 2e plaats krijgt een zelf aangepast AutoInc veld mogelijk een reeds bestaande waarde. Immers, als CurrentRecordNr 2 is, dan wordt 2 -> 3, maar wellicht bestaat er al een record met de AutoInc waarde 3. Daarbij bestaan er mogelijk waardes die in deze factuur niet opgehaald zijn omdat die factuurregels bij een andere factuur horen (een factuur met een hoger factuurnummer). Als je na iedere wijziging van het AutoInc field een Post doet, dan moet je haast wel dubbele AutoInc waardes hebben en dat is niet mogelijk met een AutoInc field, dus het klopt gewoon niet. Behalve als het echt de laatste factuur en de laatste factuurregels zijn want dan is de hoogste AutoInc waarde nog vrij.

    Of het dan goed gaat als je een nieuwe factuur toevoegt weet ik niet (kijkt een AutoInc veld bij een nieuw record naar de laatste waarde ook als deze handmatig verhoogd is ?), maar bij een echt RDBMS waarvan het ID door een trigger of sequence gegenereerd wordt kan en mag je dit absoluut niet doen en moet je het genereren van het ID (AutoInc) aan de database overlaten. Zo'n ID mag je wel genereren, opvragen en toekennen aan je ID-veld in je CLientDataSet, ook al bestaat deze nog niet in de database, maar dan is dat unieke nummer vergeven en weet je zeker dat deze uniek is.

    Mijn werkwijze zou kunnen zijn een veld t.b.v. de volgorde (nummer) toe te voegen, hierop een index te maken en als je dan regel tussen wilt voegen dien je achteraan te beginnen, dus van eof naar bof : factuur regel 4 wordt 5, 4 is vrij dus 3 wordt 4, 3 is vrij dus 2 wordt 3, 2 is vrij dus voilá je kunt nummer 2 tussen voegen, ook al heeft deze een ID (AutoInc) waarde dat totaal anders is.
    Testen kan niet de afwezigheid van fouten aantonen, slechts de aanwezigheid van gevonden fouten.

    Het is verdacht als een nieuw ontwikkeld programma direct lijkt te werken: waarschijnlijk neutraliseren twee ontwerpfouten elkaar.

Page 1 of 2 1 2 LastLast

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •