[Delphi] zjednodušení code

C++, C#, Visual Basic, Delphi, Perl a ostatní

Moderátor: Moderátoři Živě.cz

Odeslat příspěvekod dyžon 27. 9. 2017 07:35

zdravím profíci,
dneska bych vás chtěl poprosit o posouzení code, co jsem napsal a jeho případné zjednodušení.
mám v programu kalendář.
2017-09-27_081527.png

Jednotlivy dny vytvářím v proceduře:
Kód: Vybrat vše
procedure TProcedury_Kalendar.Nakresli_Mesic_Kalendare(Rok, Mesic: Integer);
var I, pX, pY, Dnu_vMesici, Den_vTydnu, zaznamu: Integer;
    sql, datum, den: String;
begin
  Vymaz_Starej_Mesic(PocetDnuStaryhoMesice);  //smaže panely staryho měsíce

  Dnu_vMesici:= DaysinAMonth(Rok, Mesic);
  PocetDnuStaryhoMesice:= Dnu_vMesici;        // nastaví hodnotu pro mazání vytvořených panelů

  Den_vTydnu:= DayOfTheWeek(EncodeDate(Rok, Mesic, 1));

  datum:= IntToStr(Rok);
  if Mesic <= 9 then datum:= datum + '0' + IntToSTr(Mesic) else datum:= datum + IntToStr(Mesic);

  pX:= 0; pY:= Den_vTydnu -2;

  SetLength(FPanelDne, Dnu_vMesici);

  for I := 1 to Dnu_vMesici do begin
    inc(pY); if pY > 6 then begin pY:= 0; inc(pX); end;
      if pY = -1 then pY:= 6;                      // pozice řádků po týdnech

    FPanelDne[I-1]:= TPanelDne.Create(FASP_Zakazky.Panel_Kalendar);
    with FPanelDne[I-1] do begin
      parent:= FASP_Zakazky.Panel_Kalendar;
      parentBackGround:= False; ShowCaption:= False; DoubleBuffered:= True;
      Width:= 107;
      Height:= 50;
      Left:= (pY * 108)+ 22; // 22 je odsazení z leva PKalendáře
      Top:= (pX * 51)+ 80;   // 80 je odszení z vrchu PKalendáře
      Tag:= I;
      Caption:= HSvatek.VratSvatek(EncodeDate(Rok, Mesic, I));
      PoziceVKalendáři:= Point(pX, pY);

      if (pY=5)or(pY=6) then begin color:= $004D93D9; BarvaSvatku:= $0023EBE6; Je_Vikend:= True;
                                     end else begin
                                   color:= clScrollBar; BarvaSvatku:= $00AA8080; Je_Vikend:= False end;
        if (Rok = AktRok) and (Mesic = AktMesic)and((i)= AktDen) then begin
          Je_Dneska:= True; color:= $0094FEC9; end;

      datum:= ''; datum:= IntToStr(Rok);
      if Mesic <= 9 then datum:= datum + '0' + IntToSTr(Mesic) else datum:= datum + IntToStr(Mesic);
      if I <=9 then datum:= datum + '0' + IntToStr(I) else datum:= datum + IntToStr(I);

      sql:= Format('select * from DIAR where Upper(%s) like ''%%%s%%''Order by DATUM DESC',
              ['DATUM', AnsiUpperCAse(datum)]);
      ASP_DM.IBQ_Kalendar.Close; ASP_DM.IBQ_Kalendar.SQL.Clear;
      ASP_DM.IBQ_Kalendar.SQL.Add(sql); ASP_DM.IBQ_Kalendar.Open;

      Eva:= barvaDochazky(ASP_DM.IBQ_Kalendar.Fields[2].AsString);  // pro vykreslení docházky 1: zelena - v práci
      Vladka:= barvaDochazky(ASP_DM.IBQ_Kalendar.Fields[3].AsString);                          // 2: červená - volno a pod.
      Dusan:= barvaDochazky(ASP_DM.IBQ_Kalendar.Fields[4].AsString);

      Poznamka:= ASP_DM.IBQ_Kalendar.Fields[1].AsString;  // poznámka k aktuálnímu dni.
      OnMouseEnter:= PanelyDne_MouseEnter;
      OnMouseLeave:= PanelyDne_MouseLeave;
      OnMouseMove:= PanelyDne_MouseMove;
      OnClick:= PanelyDne_MouseClick;

      if I < 9 then den:= '0' + IntToStr(I) else den:= IntToStr(I);

      ASP_DM.IBQ_Kalendar.Close; ASP_DM.IBQ_Kalendar.SQL.Clear;
      sql:= 'SELECT ZAKAZKA, NAZEV, DOKONCIT FROM ZAKAZKY where DOKONCIT = :datum';
      ASP_DM.IBQ_Kalendar.SQL.Add(sql);
      ASP_DM.IBQ_Kalendar.ParamByName('datum').AsString:= den +'.'+ IntToStr(Mesic) +'.'+ IntToStr(Rok);
      ASP_DM.IBQ_Kalendar.Open;

      zaznamu:= 0;
      ASP_DM.IBQ_Kalendar.First;
       while(not ASP_DM.IBQ_Kalendar.Eof) do begin
         SetLength(Termin, Length(termin) +1);
         Termin[i-1]:= TImage.Create(FPanelDne[i-1]);
         with Termin[i-1] do begin
           parent:= FPanelDne[i-1];  // pokud má den nějakej termín dokončení zakázky, vytvoří se TImage;
           Top := 30; Left := (zaznamu * 17)+ 25;
           Stretch:= True; Width:= 16; Height:= 16;
           hint:= IntToStr(ASP_DM.IBQ_Kalendar.Fields[0].AsInteger)+' - '+ASP_DM.IBQ_Kalendar.Fields[1].AsString;
           ShowHint:= True;
           FASP_Zakazky.RSTream:= TResourceStream.Create(HInstance, 'finish', RT_RCDATA);
            try
              FASP_Zakazky.PngIkona.LoadFromStream(FASP_Zakazky.RSTream);
              picture.Graphic:= FASP_Zakazky.PngIkona;
            finally  end;
        OnClick:= Finish_Click;
        OnMouseEnter:= Finish_Enter;
        OnMouseLeave:= Finish_Leave;

        BringToFront;
      end;
        inc(zaznamu);
    ASP_DM.IBQ_Kalendar.Next;
      end;
    end;
end;

RSTream je TResourceStream;
PngIkona je TPNGImage;
obojí vytvářím a likviduju v OnCreate a OnDestroy hlavního Formu
FASP_Zakazky je hlavní Form;
Vykreslování FPanelDne mám v téhle proceduře:
Kód: Vybrat vše
procedure TPanelDne.Paint;
var Elipsa, Datum, Svatek: TColor;
begin
  inherited;
  if Assigned(FOnPaint) then FOnPaint(Self);

  if Je_Vikend then begin Datum:= $0000396C; Elipsa:= clMaroon; Svatek:= $0023EBE6;
    end else begin        Datum:= $006B6B6B; Elipsa:= $006B6B6B; Svatek:= $00AA8080; end;
  if Je_Dneska then begin Datum:= clGreen; Elipsa:= clGreen; Svatek:= $0051B101; end;

  with canvas do begin
    Brush.Style:= bsClear;
      Font.Size:= 12; Font.Style:= [fsBold]; Font.Color:= Datum;
        if Tag <= 9 then TextOut(92, 2, IntToStr(tag)) else TextOut(82, 2, IntToStr(tag)); // Datum;
      Font.Size:= 7; Font.Style:= [fsBold]; Font.Color:= Svatek;
        TextOut(5, 3, caption);  // Svatek;

  // vykreslení docházky
    if Eva <> clWhite then begin
      pen.Color:= Elipsa; pen.Width:= 1;
      RoundRect(69, 21, 103, 34, 5, 5);  // Elipsa
      Font.Size:= 7; Font.Style:= [fsBold]; Font.Color:= Eva;
          TextOut(72, 22, 'E');  // Docházka Eva
      Font.Size:= 7; Font.Style:= [fsBold]; Font.Color:= Vladka;
          TextOut(82, 22, 'V');  // Docházka Vladka
      Font.Size:= 7; Font.Style:= [fsBold]; Font.Color:= Dusan;
          TextOut(92, 22, 'D');  // Docházka Dusan
    end;

    if Poznamka <> '' then begin
    FASP_Zakazky.RStream:= TResourceStream.Create(HInstance, 'poznamka', RT_RCDATA);
  try
    FASP_Zakazky.PngIkona.LoadFromStream(FASP_Zakazky.RStream);
    draw(5, 30, FASP_Zakazky.PngIkona);
  finally
  end;
    end;
  end;
end;

a tady je ještě deklarace TPanelDne:
Kód: Vybrat vše
type                                                                           
  TPanelDne = class(Vcl.ExtCtrls.TPanel)                                       
    protected                                                                 
     FOnPaint: TNotifyEvent;
     Je_Vikend: Boolean;
     Je_Dneska: Boolean;
     FEva, FVladka, FDusan: Integer;
     FPoznamka: String;
     PoziceVKalendáři: TPoint;
     Procedure Paint; Override;
     procedure PanelyDne_MouseEnter(Sender: TObject);
     procedure PanelyDne_MouseLeave(Sender: TObject);
     procedure PanelyDne_MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
     procedure PanelyDne_MouseClick(Sender: TObject);
     procedure Finish_Click(Sender: TObject);
     procedure Finish_Enter(Sender: TObject);
     procedure Finish_Leave(Sender: TObject);
    public
     Property Canvas;
     Property OnPaint: TNotifyEvent read FOnPaint write FOnPaint;
     Property Vikend: Boolean read Je_Vikend write Je_Vikend;
     Property Dneska: Boolean read Je_Dneska write Je_Dneska;
     Property Eva: Integer read FEva write FEva;
     Property Vladka: Integer read FVladka write FVladka;
     Property Dusan: Integer read FDusan write FDusan;
     Property Poznamka: String read FPoznamka write FPoznamka;
end;

dřív jsem v FPanelDne vytvářel pro každej string TLabel a pro každou ikonu TImage, teď jsem se rozhodl, že většinu věcí zkusím rovnou vykreslit, ale zdá se, že se to moc nezrychlilo, hlavně když se připojuji z PC na síti.
je to zřejmě množstvím přístupů do databáze v cyklu For při vytváření FPanelDne, ale nenapadá mě, jak to obejít.
jediny, co mě napadlo je, vytvořit nějakej typ, kam se vloží všechny data všech dnů ještě před cyklem For, kdy se vytváří jednotlivy FPanelyDnů a v cyklu už jen přiřadit hodnoty do proměnných FPanelDne.
ale to si myslím, že moc časově nepomůže.
prosím o jakýkoliv nápad k věci, určitě to jde udělat líp.
AMD FX-6300; Gigabyte 970A-DS3P; DDR3 8192MBytes; AMD Radeon HD 6700 Series
dyžon
Junior
Uživatelský avatar

Odeslat příspěvekod Just_jo 27. 9. 2017 07:57

Kdysi jsem si také dělal kalendář - ta doba pro vykreslení apod. - to prostě nešlo.

Asi bych to řešil permanentními panely, kde se bude jen měnit obsah.
SQL bych spojil pro celý view a postupně vytahoval data pro jednotlivé dny.
Ostatně jaký vliv má sql dotaz lze jednoduše zjistit prostým vynecháním dotazu.
Just_jo
Junior
Uživatelský avatar

Odeslat příspěvekod JanFiala 27. 9. 2017 08:59

Proč nepoužiješ nějaký Grid (DrawGrid) a neřešíš to vykreslováním v OnDrawCell?
Při spuštění programu si vygeneruješ pole s vlastnostmi pro vykreslení (při změně ho aktualizuješ) a pak už jen vykreslíš.
Co můžeš udělat dnes, odlož na včerejšek
JanFiala
Expert
Uživatelský avatar

Odeslat příspěvekod dyžon 27. 9. 2017 12:25

to Just_jo:
to samotny vykreslení je rychlý, právě to tahání dat z databáze to hrozně brzdí.
jak jsi myslel to
SQL bych spojil pro celý view a postupně vytahoval data pro jednotlivé dny

něco jako
Kód: Vybrat vše
sql:= 'select DATUM from DIAR where DATUM BETWEEN '''
        + ZacatekM + ''' AND ''' + KonecM + '''';
ASP_DM.IBQ_Kalendar.First;
       while(not ASP_DM.IBQ_Kalendar.Eof) do begin
      bla bla
      ASP_DM.IBQ:Kalendar.Next;
     end;

myslíš, že by to bylo rychlejší ??
určitě vyzkouším.

To JanFiala:
jak už jsem psal, to vytváření a vykreslování není zase takovej problém.
takže bych měl udělat něco jako:
Kód: Vybrat vše
type
  TDen = Record
    Fdatum: array of TDate;
    FPoznamka: array of String;
    .....
    .....
  end;

načíst do toho všechny data z celyho měsíce a při vykreslování brát data z toho ??
to by mohlo být rychlejší, určitě taky zkusím ...

díky oboum, o víkendu se na to podívám, ještě bych vás poprosil, jestli nemáte nějakou dobrou a přesnou funkci na měření času v malých jednotkách abych to mohl přesně měřit ...
díky zatím.
AMD FX-6300; Gigabyte 970A-DS3P; DDR3 8192MBytes; AMD Radeon HD 6700 Series
dyžon
Junior
Uživatelský avatar

Odeslat příspěvekod JanFiala 27. 9. 2017 13:58

Pouzij Time() na zacatku a na konci. Odecti to od sebe a dostanes pocet milisekund.
Muzes pouzit i GetTickCount(), ale to jen pro srovnani, co je rychlejsi. Z toho zadne presne info nedostanes.
Co můžeš udělat dnes, odlož na včerejšek
JanFiala
Expert
Uživatelský avatar


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 0 návštevníků