Avatar billede x-masman Nybegynder
16. februar 2004 - 23:06 Der er 12 kommentarer og
1 løsning

2 linier i TStringGrid

Hej eksperter

Jeg skal have to linier i hver colonne i TStringGrid. Jeg har set at det kan lade sig gøre jvf. http://www.eksperten.dk/spm/400670

Men jeg kan simpelthen ikke overskue min DrawCell mere,,, Kan i hjælpe mig?

procedure TOpgaveMainForm.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  OpgNr, i, TempI: Integer;
  opgType,s1,s2,ansat,beskrivelse: string;
  BgColor, FColor: TColor;
  R : TRect;
  Opgave: boolean;
begin
  with (Sender as TStringGrid) do begin
    if (ACol = 0) or (ARow = 0) then
      Canvas.Brush.Color := clBtnFace
    else
      If Cells[ACol,ARow] <> '' Then
      begin
      // Først skal der testes om det er fravær eller en opgave.
        s1 := Cells[ACol,ARow];
        s2 := copy(s1,0,1);
        Opgave := true;
        try
          TempI := StrtoInt(s2);
          except
          on E:EConvertError do
          begin
            Opgave := false;
          end;
        end;
        if not Opgave
        then
        begin
          //Så er det fravær
          beskrivelse := s1;
          OpgKarForm.fravaerT.First;
          while not OpgKarForm.fravaerT.EOF do
          begin
            if OpgKarForm.fravaerT.FieldByName('Beskrivelse').text <> beskrivelse
            then OpgKarForm.fravaerT.next
            else
            begin
              OpgType := OpgKarForm.fravaerT.FieldByName('type').text;
              OpgKarForm.FraTypT.First;
              while not OpgKArForm.fratypT.Eof do
              begin
                if OpgKarForm.fraTypT.FieldByName('Type Navn').text = OpgType
                then
                begin
                  BGColor := StringToColor
                  (OpgKarForm.FraTypt.FieldByName('baggrunds farve').text);
                  FColor := StringToColor
                  (OpgKarForm.FraTypT.FieldByName('Tekst farve').text);
                  //showmessage(OpgKArForm.FraTypT.FieldByName('baggrunds farve').text);
                  OpgKarForm.FraTypT.last;
                end
                else OpgKArForm.FraTypT.Next;
              end;
            end;
            OpgKarForm.fravaerT.Last;
          end;
        end
        else
        begin
        //så er det en opgave
        OpgNr := FindKundeNr(Cells[ACol,ARow]);
        OpgKarForm.PlacOpgT.first;
        while not OpgKarForm.PlacOpgT.EOF do
        begin
          if OpgKarForm.PlacOpgT.FieldByName('Opgave Nr.').asInteger <> opgNr
            then OpgKarForm.placOpgT.Next
          else
          begin
            opgType := OpgKarForm.PlacOpgT['type'];
            OpgKarForm.TypeTabel.first;
            while not OpgKarForm.TypeTabel.EOF do
            begin
              if OpgKarForm.TypeTabel.fieldByName('Typenavn').text = opgType
                then
                begin
                  //showmessage('lort');
                  BGColor := StringToColor
                  (OpgKarForm.TypeTabel.fieldByName('baggrunds farve').text);
                  FColor := StringToColor
                  (OpgKarForm.TypeTabel.fieldByName('Tekst farve').text);
                  OpgKarForm.TypeTabel.last;
                end
              else OpgKarForm.TypeTabel.next;
            end;
            OpgKarForm.PlacOpgT.Last;
          end;
        end;
      end;
      //showmessage(ColorToString(BGColor));
      Canvas.Brush.color := BGColor;
      Canvas.Font.Color := FColor;
      Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top + 2, cells[acol, arow]);
      Canvas.FrameRect(Rect);
      if (TidGrid.row = Arow) and (tidGrid.col = Acol) then
      begin
        TidGrid.Canvas.Pen.Color := clBlack;
        TidGrid.Canvas.Pen.Width := 5;
        TidGrid.Canvas.DrawFocusRect(Rect);
        R := Rect;
        dec(R.Left,2);
        dec(R.Top,2);
        Inc(R.Right,3);
        Inc(R.Bottom,3);
        Canvas.Brush.color := clBlack;
        canvas.FrameRect(R);
      end;
    end;
  end;
end;
Avatar billede x-masman Nybegynder
16. februar 2004 - 23:07 #1
to linier i hver celle mener jeg!
Avatar billede x-masman Nybegynder
18. februar 2004 - 21:39 #2
er der virkelig ingen der kan hjælpe mig?
Avatar billede nop Nybegynder
20. februar 2004 - 08:13 #3
Ikke bare for at være smart, men: Skriv den om (helst fra bunden), det hjælper nogen gange. --nop
Avatar billede snowball Novice
24. februar 2004 - 12:54 #4
Har du prøvet på at implementere den ønskede funktion i din OnDrawCell, eller indeholder den kun det den skal kunne?

Jeg har tidligere brugt nedenstående OnDrawCell som virker. Den virker dog ikke helt perfekt, idet den kan finde på at "klatte" lidt hvis teksten kun fylder 1 linie, men du kan jo prøve dig frem.

procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  S: String;
  drawrect :trect;
begin
  S:= (Sender As TStringgrid).Cells[ aCol, aRow ];
  If Length(S) > 0 Then Begin
    drawrect := rect;
    DrawText((Sender As TStringgrid).canvas.handle,
              Pchar(S), Length(S), drawrect,
              dt_calcrect or dt_wordbreak or dt_left );
    If (drawrect.bottom - drawrect.top) >
      (Sender As TStringgrid).RowHeights[arow]
    Then
      (Sender As TStringgrid).RowHeights[arow] :=
        (drawrect.bottom - drawrect.top)
    Else Begin
      drawrect.Right := rect.right;
      (Sender As TStringgrid).canvas.fillrect( drawrect );
      DrawText((Sender As TStringgrid).canvas.handle,
                Pchar(S), Length(S), drawrect,
                dt_wordbreak or dt_left);
    End;
  End;
end;
Avatar billede x-masman Nybegynder
25. februar 2004 - 22:39 #5
Hej Snowball.

Undskyld jeg ikke har svaret før nu. Problemet er at min ondrawcell er al den kode jeg har smækket ind i spm'et. Det jeg ikke kan klare selv er at få flettet det sammen med den kode du har skrevet.
Avatar billede hrc Mester
26. februar 2004 - 16:43 #6
Det eneste du behøver er at lave to rect's som sammenlagt fylder den eksisterende Rect. Sæt derefter to DrawRect ind i stedet for een og det burde virke. Denne modfikation skal ind ca. 17 linier fra bunden idet det er det eneste sted der skrives tekst til canvas.

I nedenstående pseudo-kode (ikke kompileret/testet) antager jeg at strengen i cell[] indeholder en <CR><LF>. Der deles teksten. Du kan evt. benytte Canvas.TextExtent(st1); til at finde ud af hvor langt nede at st2 skal skrives.

var
  p : integer;
  st, st1, st2 : string;
  Rect1, Rect2 : TRect;
begin

  ..


  Rect1.TopLeft    := Point(Rect.Left,Rect.Top);
  Rect1.BottomRight := Point(Rect.Left,(Rect.Bottom - Rect.Top) shr 1);
  Rect2.TopLeft    := Point(Rect.Left,Rect1.Bottom+1);
  Rect2.BottomLeft  := Point(Rect.Right,Rect.Bottom);

  st := cells[acol, arow]; st2 := '';
  p := pos(#13#10,st);
  if p > 0 then begin
    st1 := copy(st,1,p-1);
    st2 := copy(st,p+2,length(st)-p-2);
  end
  else
    st1 := st;

  Canvas.TextRect(Rect1, Rect1.Left + 2, Rect1.Top + 2, st1);
  Canvas.TextRect(Rect2, Rect2.Left + 2, Rect2.Top + 2, st2);

Det er et meget banalt løsningsforslag - har næsten ikke skrevet på canvas'er selv - og prøver at skære det ud i pap for os begge. Håber det løser dit problem.

P.S. En smukkere tilgang bør evt. bygges på en TDrawgrid (eller TCostumGrid), hvor man i baggrunden vedligeholder en matrice af objekter der hver især ved hvordan de skal tegne sig selv på et stykke canvas. På den måde kan du slippe for en uforståelig OnDrawCell - og det kan ende med at blive helt objektorienteret.

Det vil blive noget med

var
  MyObj : TMyObj;
  MyGrid : TMyGrid;
begin
  MyObj := Cells[aCol,aRow];
  MyGrid := (Sender as TMyGrid);
  MyObj.Draw(MyGrid.Canvas, Rect);
  if (MyGrid.row = Arow) and (MyGrid.col = Acol) then begin // Focused
    InflateRect(Rect,-2,-2); // I stedet for dec(R.Left,2); dec(R.Top,2); Inc(R.Right,3); Inc(R.Bottom,3);
    MyGrid.Canvas.FrameRect(Rect);
  end; // if
end;
Avatar billede x-masman Nybegynder
04. marts 2004 - 16:57 #7
undskyld jeg ikke har svaret før. Jeg har ikke haft tid... Typisk! Jeg tror jeg får tid iaften.

/Jens
Avatar billede x-masman Nybegynder
22. marts 2004 - 21:07 #8
Så lykkedes det endelig at få lidt tid til det og det tog lidt tid. Løsningen blev hrc's lidt modificeret så den blev rigtig. ;)
Jeg ved ikke helt hvad du ville med shr?
Er der en af jer der ved hvordan jeg ændre fontstørrelsen? Jeg kan ikke gøre det i stringgriden, da det er canvas hvor det skal ske.

Her er den endelige løsning:
Rect1.TopLeft    := Point(Rect.Left,Rect.Top);
      Rect1.BottomRight := Point(Rect.Right,Rect.top+(Round((Rect.bottom-Rect.Top)/2)));
      Rect2.TopLeft    := Point(Rect.Left,Rect1.Bottom);
      Rect2.BottomRight  := Point(Rect.Right,Rect.Bottom+1);
      st := cells[acol, arow]; st2 := '';
      p := pos(#13#10,st);
      if p > 0 then
      begin
      st1 := copy(st,1,p-1);
      st2 := copy(st,p+2,length(st)-p-2);
      Canvas.TextRect(Rect1, Rect1.Left + 2, Rect1.Top + 2, st1);
      Canvas.TextRect(Rect2, Rect2.Left + 2, Rect2.Top + 2, st2);
      end
      else
      Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top + 2, cells[acol, arow]);
      Canvas.FrameRect(Rect);
    end;
  end;
Avatar billede hrc Mester
23. marts 2004 - 14:59 #9
x-masman (lidt udenfor sæson, ikke): mit evindelige fedten rundt med shr og shl skyldes at min første computer havde 32kb ram (goe' gamle RC Piccolo) og så tæller hver operation.

"n shr 1" svarer til at dividere med 2 og er hurtigere end "n div 2" som igen er meget meget hurtigere end din "round(n / 2)"

Du laver en flydende decimaldivision, hvilket tvinger programmet til at konvertere en int til en float, dernæst udføre en fdiv afsluttende med en konvertering tilbage til int. Det er MEGET MEGET tungt.

Man kan sige at shr er den nørdede metode. Under alle omstændigheder er div bedre end din:

      Rect1.TopLeft    := Point(Rect.Left,Rect.Top);

      // Dette er meget bedre!
      Rect1.BottomRight := Point(Rect.Right,Rect.top+((Rect.bottom-Rect.Top) shr 1);

      Rect2.TopLeft    := Point(Rect.Left,Rect1.Bottom);
      Rect2.BottomRight  := Point(Rect.Right,Rect.Bottom+1);

      st := cells[acol, arow]; st2 := '';
      p := pos(#13#10,st);
      if p > 0 then begin
        st1 := copy(st,1,p-1);
        st2 := copy(st,p+2,length(st)-p-2);
        Canvas.TextRect(Rect1, Rect1.Left + 2, Rect1.Top + 2, st1);
        Canvas.TextRect(Rect2, Rect2.Left + 2, Rect2.Top + 2, st2);
      end
      else
        Canvas.TextRect(Rect, Rect.Left + 2, Rect.Top + 2, cells[acol, arow]);
        Canvas.FrameRect(Rect);
    end;
  end;
Avatar billede hrc Mester
23. marts 2004 - 16:21 #10
Nu kører jeg ud af en tangent igen fordi jeg synes programoptimering er kørt noget i baggrunden:

Jeg bruger shl og shr hvor jeg kan, for mit program kører hurtigere. I gamle dage gangede man eksempelvis 2 med 10 på følgende måde (for et 16-bit tal):

n shl 2 -> gange med 4 (2 cycles)
dup    -> lav kopi og smid en på stakken (1 cycle)
n shl 1 -> gange med 2 (2 cycles)
add    -> læg sammen (1 cycle)
pop    -> hent fra stak eller register (1 cycle)
add    -> læg sammen (1 cycle)

Regnestykket ser sådan ud: 8 + 8 + 4 = 20

Ialt ca. 8-9 cycles mod de 13-26 som en mul(tiply) operation tager. Hvis koden sidder midt i en hyppigt kaldt operation, så bliver forskellen tydelig. Nu hvor maskinerne arbejder i GHz er det måske mindre relevant, men gammel lærdom er ret svær at glemme. Fordi programmørerne glemmer at optimere deres kode har maskinerne i øvrigt mere end rigeligt at lave i dag.

Endelig, hvis der er nogen der ikke fatter hvad jeg snakker om, så gør jeg det endnu værre her: "tal Shl n" shifter bittene i et tal n gange til venstre, svarende til at man ganger det med 2^n.

Her ganger jeg 37 med 4: 00100101b (37d) shl 2: 10010100b: (148d)

Nu skal jeg nok stoppe... ;-)
Avatar billede x-masman Nybegynder
23. marts 2004 - 19:21 #11
okay. Jeg kan godt se det nu. Det kan godt være at det er hurtigst, men det hjælper nok ikke på forståeligheden af koden, hvis der nogen sinde er en anden der skal læse min kode. ;) Al det optimering på relativt små funktioner hører vist til fordums tid. ;) Nu om dage begynder man vist først rigtigt at optimere når man kommer over polynomiel køretid.
Men du skal i hvert fald have tusinde tak for hjælpen.

Vidste du iøvrigt hvordan jeg gør skriften mindre... For at komme lidt tilbage til det praktiske igen. ;)
Avatar billede hrc Mester
23. marts 2004 - 19:36 #12
Ovenstående kode vil faktisk blive brugt ret hyppigt! Jeg ved godt at det ikke er fraktalberegninger, men du må ikke tro at optimering hører fordums tid til.
Som programmør bør man hele tiden stræbe efter forbedre sin viden og optimere sin kode. Det er god praksis og det betaler sig i længden - det er min erfaring.

Du skal i alt fald ikke bruge / og round. Det er nærmest forkert. Hvis du ikke kan lide shl og shr, så brug div.

Mht. dit tillægsspørgsmål: Det er vel noget med Canvas.Font.FonsSize := EtEllerAndet
Avatar billede x-masman Nybegynder
23. marts 2004 - 21:35 #13
Ja. Generelt er jeg enig, men at ty til assembler levn er måske overkill ;) Men det at optimere er jeg enig med dig i er vigtig. JEg siger bare at hvis det skal bruges i en algoritme med konstant køretid, er det måske ikke så vigtigt at bruge flere timer på at optimere.
Men i hvertfald tak for hjælpen.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester