Dziennik lekcyjny - problem z zapisem/odczytem kontrolki do pliku

Dziennik lekcyjny - problem z zapisem/odczytem kontrolki do pliku
0

Piszę program, który ma służyć za dziennik lekcyjny. Oceny, sprawdzanie obecności, uwagi i ma mieć zakładkę dla każdego przedmiotu,wczytuje i zapisuje,czyści wszystkie komórki,dodaje i usuwa zakładki. Jednak utknąłem i nie wiem co robić mam problem z zapisaniem pagecontrol stringgrida do pliku, odczytaniem tego i działaniem klawiszy na otwartych zakładkach.

Oto kod

Kopiuj
unit dziennikLekcyjnyGP;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls, ComCtrls, TabNotBk, Grids, ExtCtrls, Tabs, ExtDlgs,ShellAPI;

type
  TForm1 = class(TForm)
    MainMenu: TMainMenu;
    StringGrid1: TStringGrid;
    Plik1: TMenuItem;
    Koniec2: TMenuItem;
    Nowy1: TMenuItem;
    Open: TOpenTextFileDialog;
    Save: TSaveTextFileDialog;
    Zapisz1: TMenuItem;
    Wczytaj1: TMenuItem;
    Obecnosc1: TMenuItem;
    Srednia1: TMenuItem;
    PageControl1: TPageControl;
    Dodajzak1: TMenuItem;
    Zamknijzak1: TMenuItem;
    Edit1: TEdit;
    procedure Koniec2Click(Sender: TObject);
    procedure Wczytaj1Click(Sender: TObject);
    procedure Zapisz1Click(Sender: TObject);
    procedure Nowy1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Dodajzak1Click(Sender: TObject);
    procedure Zamknijzak1Click(Sender: TObject);
    procedure Srednia1Click(Sender: TObject);
    procedure Obecnosc1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  StringGrid:TStringGrid;

implementation
  {$R *.dfm}


procedure wypelnij_tabele(var s:TstringGrid); //przypisuje nazwy do komurek
var i:integer;
begin
  with s do begin
  Cells[1,0]:='Imie';
  Cells[0,1]:='Daty lekcji';
  Cells[2,0]:='Nazwisko';
  Cells[3,0]:='Oceny';
  Cells[12,0]:='Średnia';
  Cells[13,0]:='Obecnosc';
  Cells[33,0]:='Uwagi';
  for i:=1 to 101 do
  begin
  Cells[13,i+1]:='Obecny';
  Cells[14,i+1]:='Obecny';
  Cells[15,i+1]:='Obecny';
  Cells[16,i+1]:='Obecny';
  Cells[17,i+1]:='Obecny';
  Cells[18,i+1]:='Obecny';
  Cells[19,i+1]:='Obecny';
  Cells[20,i+1]:='Obecny';
  Cells[21,i+1]:='Obecny';
  Cells[22,i+1]:='Obecny';
  Cells[23,i+1]:='Obecny';
  Cells[24,i+1]:='Obecny';
  Cells[25,i+1]:='Obecny';
  Cells[26,i+1]:='Obecny';
  Cells[27,i+1]:='Obecny';
  Cells[28,i+1]:='Obecny';
  Cells[29,i+1]:='Obecny';
  Cells[30,i+1]:='Obecny';
  Cells[31,i+1]:='Obecny';
  Cells[32,i+1]:='Obecny';
  end;
  for i:=1 to 101 do
  cells[0,i+1]:=IntToStr(i);
  end
end;

procedure TForm1.Dodajzak1Click(Sender: TObject); //Dodaje zakladke
var
  TabSheet: TTabSheet;
  nazwa:string;
  tab:string;

begin                  //Okienko z pyt o nazwe zakłądki i tworzy stringgrid w pagecontrol
  Edit1.Text:=InputBox('Zakładki','Podaj nazwe zakłądki:','Tu wpisz nazwe zakładki');
  nazwa:=(Edit1.Text);
  TabSheet := TTabSheet.Create(PageControl1);
  TabSheet.Caption := nazwa;
  TabSheet.PageControl := PageControl1;
  StringGrid := TStringGrid.Create (TabSheet);
  StringGrid.ColCount := 50;
  StringGrid.Align:=alClient;
  StringGrid.ScrollBars:=ssBoth;
  StringGrid.Options := StringGrid.Options + [goThumbTracking];
  StringGrid.Options:= StringGrid.Options + [goEditing];
  StringGrid.Options:= StringGrid.Options + [goFixedRowClick];
  StringGrid.Options:= StringGrid.Options + [goFixedColClick];
  StringGrid.Options:= StringGrid.Options + [goTabs];
  StringGrid.Options:= StringGrid.Options + [goRowSizing];
  StringGrid.Options:= StringGrid.Options + [goColSizing];
  StringGrid.Parent := TabSheet;
  wypelnij_tabele(StringGrid);
  StringGrid.RowCount := 101;
  StringGrid.Visible := True;
  end;

procedure TForm1.FormCreate(Sender: TObject);  //jest uzywana na onCreat i po nacisknieci nowy
begin                                          //wywoluje procedure wypelnij_tabele
  wypelnij_tabele(StringGrid1);

end;


procedure TForm1.Koniec2Click(Sender: TObject);  //zamyka program
begin
  Close;
end;

procedure TForm1.Nowy1Click(Sender: TObject);   //czysni stringrid i wywoluje procedure wypelnij_tabele
  var i : integer;
begin
  PageControl1.ActivePage.TabIndex;
  for i:=0 to stringgrid.ColCount do
    begin
      stringgrid.Cols[i].Clear;
    end;
  for i:=0 to stringgrid.RowCount do
    begin
      stringgrid.Rows[i].Clear;
    end;
  wypelnij_tabele(StringGrid);
end;



procedure TForm1.Obecnosc1Click(Sender: TObject);  //wpisuje nieobennosc do komurki z wybramym nazwiskiem
var
nazwisko,data: String;
i:Integer;
begin
  PageControl1.ActivePage.TabIndex;
  Edit1.Text:=InputBox('Nie obecni','Podaj nazwisko nieobecnej osoby:','Nazwisko');
  nazwisko:=(Edit1.Text);
  Edit1.Text:=InputBox('Nie obecni','Podaj date nieobecnosci:','Data');
  data:=(Edit1.Text);
  for i:=1 to StringGrid.RowCount do
  begin
  if StringGrid.Cells[0,i+15]=data then
    if StringGrid.Cells[2,i]=nazwisko then
      begin
      StringGrid.Row:=i;//zaznaczanie komorki w danym wierszy
      StringGrid.Col:=1;//zaznaczanie komorki w danej kolumnie
      StringGrid.Cells[13,i]:='Nie obecny';
      end;
    end;
end;


procedure TForm1.Srednia1Click(Sender: TObject); //oblicza srednia ocen
var
  i:Integer;
  A,B,C,D,E,F,G,H,J:real;
begin
  PageControl1.ActivePage.TabIndex;
  ShowMessage('Oblicza srednia dla 9 ocen');
  for i:=1 to StringGrid.RowCount-1 do
    begin
      A:=StrTofloat(StringGrid.Cells[3,i]);
      B:=StrTofloat(StringGrid.Cells[4,i]);
      C:=StrTofloat(StringGrid.Cells[5,i]);
      D:=StrTofloat(StringGrid.Cells[6,i]);
      E:=StrTofloat(StringGrid.Cells[7,i]);
      F:=StrTofloat(StringGrid.Cells[8,i]);
      G:=StrTofloat(StringGrid.Cells[9,i]);
      H:=StrTofloat(StringGrid.Cells[10,i]);
      J:=StrTofloat(StringGrid.Cells[11,i]);
      StringGrid.Cells[12,i]:=floatToStr((A+B+C+D+E+F+G+H+J)/9);
    end;
 end;

procedure TForm1.Wczytaj1Click(Sender: TObject);   //wczytuje stringgrid po kolumn i wierszy
var
  f:textfile;
  temp,x,y:integer;
  tempstr:string;
begin
  if open.Execute then
  begin
    if FileExists(open.FileName) then
    assignfile (f,open.filename);
    reset (f);
    readln (f,temp);
    stringgrid1.colcount:=temp;
    readln (f,temp);
    stringgrid1.rowcount:=temp;
    For X:=0 to stringgrid1.colcount-1 do
      For y:=0 to stringgrid1.rowcount-1 do
      begin
        readln (F, tempstr);
        stringgrid1.cells[x,y]:=tempstr;
      end;
    closefile (f);
  end;
end;

procedure TForm1.Zamknijzak1Click(Sender: TObject); //usuwa zakłądke
begin
  PageControl1.ActivePage.Free;
end;

procedure TForm1.Zapisz1Click(Sender: TObject);   //zapisuje tekst z stringgrid to kol i wirszy
var
f:textfile;
x,y,i:integer;
Stringgrid:Tstringgrid;
begin
 for i := 0 to PageControl1.ActivePage.ControlCount  -1 do
  if PageControl1.ActivePage.Controls[i] is TStringGrid then
   begin
   StringGrid := PageControl1.ActivePage.Controls[i] as TStringGrid;
   PageControl1.ActivePage.Caption := Save.Filename;
   end;
     if Save.Execute then
      assignfile (f,save.filename);
      rewrite (f);
      writeln (f,stringgrid1.colcount);
      writeln (f,stringgrid1.rowcount);
      For X:=0 to stringgrid1.colcount-1 do
        For y:=0 to stringgrid1.rowcount-1 do
          writeln (F, stringgrid1.cells[x,y]);
          closefile (f);
end;
end.

dodanie znacznika <code class="delphi"> - fp

edytowany 1x, ostatnio: flowCRANE
n0name_l
Jak piszesz gdzies 2x (lub wiecej) ta sama lub podobna linijke, to Twoj mozg powinien rzucac wyjatkami jak oszalaly :|
MI
Nie chce mi sie więcej bugów szukać i poprawiać kawałków kodu. Poddaje sie. :(
MI
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 9 lat
3

Ten kod nadaje sie do przepisania tylko i wyłącznie

Kopiuj
  for i:=1 to 101 do
  begin
  Cells[13,i+1]:='Obecny';
  Cells[14,i+1]:='Obecny';
  Cells[15,i+1]:='Obecny';
  Cells[16,i+1]:='Obecny';
  Cells[17,i+1]:='Obecny';
  Cells[18,i+1]:='Obecny';
  Cells[19,i+1]:='Obecny';
  Cells[20,i+1]:='Obecny';
  Cells[21,i+1]:='Obecny';
  Cells[22,i+1]:='Obecny';
  Cells[23,i+1]:='Obecny';
  Cells[24,i+1]:='Obecny';
  Cells[25,i+1]:='Obecny';
  Cells[26,i+1]:='Obecny';
  Cells[27,i+1]:='Obecny';
  Cells[28,i+1]:='Obecny';
  Cells[29,i+1]:='Obecny';
  Cells[30,i+1]:='Obecny';
  Cells[31,i+1]:='Obecny';
  Cells[32,i+1]:='Obecny';
  end;
  for i:=1 to 101 do
  cells[0,i+1]:=IntToStr(i);

zamienić na

Kopiuj
 for i:=2 to 102 do
 begin
  for j:=13 to 32 do
  begin
   Cells[j,i]:='Obecny';
  end;
  cells[0,i]:=IntToStr(i);
 end;

tutaj jest błąd

Kopiuj
  wypelnij_tabele(StringGrid);
  StringGrid.RowCount := 101;

Najpierw wywołujesz procedurę która przelatuje przez wszystkei wiersze (domyslnie 101) a potem dopiero ustawiasz ilosc wierszy na 101.

A co do pytania z tematu. Musisz opracować jakiś format danych w pliku. Zrzut rozumiem, że musiałby się tyczyć wszystkich zakładek, czyli musiałbyś zapisać nazwę zakładki i zawartośc stringgrida z danej zakładki
np:

Kopiuj
[TAB]
Nazwa zakładki
1;2;3;4;5;6;7
8;9;0;11;12;13
[/TAB]
[TAB]
Nazwa zakładki2
1;2;3;4;5;6;7
8;9;0;11;12;13
[/TAB]

Tutaj też jest błąd:

Kopiuj
if Save.Execute then
      assignfile (f,save.filename);
      rewrite (f);
      writeln (f,stringgrid1.colcount);
      writeln (f,stringgrid1.rowcount);
      For X:=0 to stringgrid1.colcount-1 do
        For y:=0 to stringgrid1.rowcount-1 do
          writeln (F, stringgrid1.cells[x,y]);
          closefile (f);

Sprawdzasz warunek i do niego zależna jest tylko pierwsza linia po ifie, brakuje begin/end

Kopiuj
if Save.Execute then
begin
 assignfile (f,save.filename);
 rewrite (f);
 writeln (f,stringgrid1.colcount);
 writeln (f,stringgrid1.rowcount);
 For X:=0 to stringgrid1.colcount-1 do
 For y:=0 to stringgrid1.rowcount-1 do
 writeln (F, stringgrid1.cells[x,y]);
 closefile (f);
end;

Ech, zacząłem czytać, i ten kod jest pełny bugów. Sprawdź ogólnie warunki i bloki kodu które są od nich zależne. Po drugie - poprawe formatowanie, bo mozna się pogubić

Ehh..

Kopiuj
procedure TForm1.Srednia1Click(Sender: TObject); //oblicza srednia ocen
var
  i:Integer;
  A,B,C,D,E,F,G,H,J:real;
begin
  PageControl1.ActivePage.TabIndex;   //po co to w ogóle? do czego to służy?
  ShowMessage('Oblicza srednia dla 9 ocen');
  for i:=1 to StringGrid.RowCount-1 do
    begin
      A:=StrTofloat(StringGrid.Cells[3,i]);
      B:=StrTofloat(StringGrid.Cells[4,i]);
      C:=StrTofloat(StringGrid.Cells[5,i]);
      D:=StrTofloat(StringGrid.Cells[6,i]);
      E:=StrTofloat(StringGrid.Cells[7,i]);
      F:=StrTofloat(StringGrid.Cells[8,i]);
      G:=StrTofloat(StringGrid.Cells[9,i]);
      H:=StrTofloat(StringGrid.Cells[10,i]);
      J:=StrTofloat(StringGrid.Cells[11,i]);
      StringGrid.Cells[12,i]:=floatToStr((A+B+C+D+E+F+G+H+J)/9);
    end;
 end;

na

Kopiuj
procedure TForm1.Srednia1Click(Sender: TObject); //oblicza srednia ocen
var
 i, j:Integer;
 sum:real;
begin
 ShowMessage('Oblicza srednia dla 9 ocen');
 for i:=1 to StringGrid.RowCount-1 do
 begin
  sum:=0;
  for j:=0 to 8 do
  sum:=sum+StrTofloat(StringGrid.Cells[j+3,i]);
  StringGrid.Cells[12,i]:=floatToStr(sum/9);
 end;
end;
edytowany 7x, ostatnio: misiakufal
0

Dzięki.

Czy można zapisać to za pomocą TFileStream.WriteComponent ??

I może jakaś pomocna komenda które pozwala ma prace buttona na aktualnie otwartej zakładce.

PageControl1.ActivePage.TabIndex; nie służy do wywoływanie zdarzenie np nacieknięcia buttona średnia na aktualnej stronie pagecontrol?
Bo szukając pomocy znalazłem coś takiego i faktycznie działało ale tylko dla aktualnej 1 zakładki .

Młody
  • Rejestracja:około 22 lata
  • Ostatnio:ponad 10 lat
  • Postów:418
0

...służy do wywoływanie zdarzenie np nacieknięcia buttona średnia na aktualnej stronie pagecontrol?...

?????????

MI
  • Rejestracja:ponad 15 lat
  • Ostatnio:prawie 9 lat
0

PageControl1.ActivePage.TabIndex;
To jest liczba całkowita, nie robi zupełnie nic.
To tak samo jakbyś napisał

Kopiuj
procedure foo;
var
 licznik:integer;
begin
 licznik;
end;

Możesz tą liczbę przypisać do jakiejś zmiennej, np

Kopiuj
procedure foo;
var
 licznik:integer;
begin
 licznik:=PageControl1.ActivePage.TabIndex;
 ShowMessage(IntToStr(licznik));
end;

W takiej postaci jak to napisałeś, to jest ona zupełnie niepotrzebna.

edytowany 3x, ostatnio: misiakufal
Patryk27
Stricte, to nie jest liczba - jest to property wywołujące wirtualną metodę GetPageIndex, czyli nie jest to tym samym, co napisanie po prostu zmienna; :P Btw, *tę liczbę.
MI
Stricte to wiem że to nie zwykła zmienna, ale sprowadza się do tego, że zwraca liczbę. Co do przykładu - racja, ale uprościłem bo widać, że Autor i tak po omacku programuje
0

Jeszcze raz dzięki.

0

Stricte, to nie jest liczba - jest to property wywołujące wirtualną metodę GetPageIndex, czyli nie jest to tym samym, co napisanie po prostu zmienna; :P Btw, *tę liczbę.

@Patryk27 : Założeniem property jest używanie tego jako zwykłej zmiennej, więc komplikujesz sprawę. Wg. twojej metody kursy Pascala powinno się zaczynać od budowy kompilatora oraz znajomości możliwych plików wykonywalnych oraz assemblerów. Natomiast śmiem zakładać że nawet ty tyle nie wiesz, więc może po prostu KISS?

Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
2

Zauważ, że nie jest to dział "newbie", i podobnie, jak jest wyraźna różnica pomiędzy napisaniem:

Kopiuj
Const I = 10;

oraz

Kopiuj
Const I: Integer = 10;

Istnieje różnica pomiędzy:

Kopiuj
Var I: Integer;
Begin
 I;
End;

A:

Kopiuj
Begin
 TMyClass.SomeProperty;
End;

:P


flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12164
0
payl napisał(a)

Założeniem property jest używanie tego jako zwykłej zmiennej, więc komplikujesz sprawę.

Nie, założeniem property jest "kontrola" modyfikacji/odczytu wartości pola przez ustalenie odpowiedniej metody dostępowej i zmieniającej, bądź w przypadku właściwości prostej bezpośrednich połączeń z polem; Na dodatek właściwości od zwykłych zmiennych odróżnia to, że podczas modyfikacji czy odczytu wartości pola można wykonać automagicznie inne dodatkowe czynności w ww. metodach niedostępne programiście wykorzystujęcemu daną klasę;

Poza tym właściwość danej klasy może działać na różne sposoby:

  • jako zmienna (setter i getter) - możliwość zapisu oraz odczytu + opcjonalnie dodatkowe czynności,
  • jako stała (tylko getter) - możliwość jedynie odczytu + opcjonalnie dodatkowe czynności,
  • jako dziwoląg (tylko setter) - możliwość jedynie zapisu + opcjonalnie dodatkowe czynności;
    Tak więc właściwości nie są zwykłymi zmiennymi i nie można ich tak traktować, a tym bardziej nie można stwierdzić, że takie było założenie o jakim piszesz;

PS: Co do trzeciej opcji - "jako dziwoląg" - nie wiedziałem jak to nazwać, jednak jest taka możliwość zarówno w Delphi, jak i FPC.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
0

A co z działaniem klawiszy na stringgrid w pagecontrol, np mam przycisk "Nowy" który czyści stringgrid ale działa on tylko na jednym stringgridzie, a potem nie chce działać ponownie i może ktoś dać jakaś podpowiedz to procedury "Obecnosc" ma ona działać tak, "program pyta o nazwiska osoby, nastepnie program pyta o datę nieobecności po podaniu tych 2 niewidomych program zmienia w komórce obecność na nie obecność.

flowCRANE
Pokaż aktualny kod, który nie spełnia założeń;
0
Kopiuj
procedure TForm1.Srednia1Click(Sender: TObject); //oblicza srednia ocen
var
 i, j:Integer;
 sum:real;
begin
 ShowMessage('Oblicza srednia dla 9 ocen');
 for i:=1 to StringGrid.RowCount-1 do
 begin
  sum:=0;
  for j:=0 to 8 do
  sum:=sum+StrTofloat(StringGrid.Cells[j+3,i]);
  StringGrid.Cells[12,i]:=floatToStr(sum/9);
 end;
end;

ok ok ale to jest dla samego stringgrid a mój stringgrid jest tworzony w pagecontrol z tego co zauważyłem to nie mogę tego wywołać jak dla zwykłego stringgrida albo nie działa w ogóle albo tylko raz jak inne przyciski które powinny coś robić na tym stinggridzie.

dodanie znacznika <code class="delphi"> - fp

ps To kod jak i cały projekt jest zamieszczony no początku.

edytowany 1x, ostatnio: flowCRANE
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12164
0

np mam przycisk "Nowy" który czyści stringgrid ale działa on tylko na jednym stringgridzie

No działa tak, jak jest napisany; Odwołujesz się statycznie do jednej kontrolki StringGrid;

Jeśli chcesz mieć to zdarzenie wspólne dla wszystkich gridów - musisz dynamicznie pobierać referencję do odpowiedniego StringGrid i dopiero na nim wykonywać operacje;

PS: Pamiętaj o wstawianiu kodu w odpowiednie znaczniki kolorujące składnię.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
0

Ok, dzięki a możecie mi powiedzieć czy opłaca się robić zapis TFileStream.WriteComponent, czy działa on dla stringgrida umieszczonego w pagecontrolu.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12164
0

Jeśli poprawnie się z niego korzysta to nie powinno być z tym problemu; Może nawet da się całego PageControl zapisać do pliku - nie wiem, ale spróbuję i dam znać; Ty też spróbuj;


EDIT: Niestety nie udało mi się poprawnie zapisać całego PageControl do pliku; Raczej nie ma większego sensu kombinować w ten sposób; W sieci jest dużo pytań właśnie o zapis/odczyt StringGrid do/z pliku i w większości wątków przedstawiony jest zapis kontrolki za pomocą dwóch zagnieżdżonych pętli przechodzącej przez każdą komórkę;

Można łatwo napisać procedury do zapisu/odczytu grida do/z pliku wykorzystując zwykłe pliki tekstowe; Trochę więcej roboty będzie przy wykorzystaniu plików amorficznych, ale jeśli chcesz uniknąć możliwości edycji takiego pliku w dowolnym wdytorze tekstowym to można z nich skorzystać;

Nie jest też problemem zapisanie wszystkich gridów do jednego pliku amorficznego; Jednak trzeba dobrze to przemyśleć i w nagłówku pliku zapisać informacje o ilości gridów, potem dla każdego grida zapisać informacje o ilości wierszy i kolumn, a potem w pętli zapisywać ilość znaków łańcucha dla danej komórki i sam łańcuch jako jej wartość; Wbrew pozorom nie jest to takie trudne, ale trzeba nieco na ten temat poczytać, jeśli się wcześniej tego nie robiło;


Furious Programming napisał(a)

Jeśli chcesz mieć to zdarzenie wspólne dla wszystkich gridów - musisz dynamicznie pobierać referencję do odpowiedniego StringGrid i dopiero na nim wykonywać operacje;

A co do tej kwestii - nie wiem dokładnie co chcesz zrobić, ale jeśli potrzebujesz wykorzystać jedną procedurę do operacji na aktywnym gridzie, to musisz go najpierw znaleźć przez odczytanie indeksu aktywnej karty w PageControl a potem samą kontrolkę; Jeśli już będziesz miał referencję do odpowiedniej kontrolki - możesz wykonać na niej odpowiednie operacje.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
madmike
Oczywiście, że się da - tylko po co? co innego formatka na dane, a co innego dane - to powinno być zawsze wyraźnie rozdzielone.
flowCRANE
Hmmm, mnie coś nie wychodzi z zapisem całego PageControl z kilkoma zakładkami, gdzie na każdym jest StringGrid, ale coś pewnie przez pośpiech robię źle ;)
olesio
  • Rejestracja:prawie 17 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Szczecin
  • Postów:4191
0

Ja tylko doradze, że skoro to nie dział Newbie. Pytającemu polecam skorzystać z własności Objects danej komórki StringGrid i stworzyć sobie klasę do przechowywania wszelkich informacji o uczniu. Następnie zapisywać to do obiektu w kolumnie z nazwiskami (począwszy od pierwszego nazwiska, czyli pewnie wiersz o indeksie 1), przy odczycie dodawać do StrigGrida. W tym typie, a najlepiej klasie dziedziczącej poTObject później zapisać sobie TMemory/TFileStreamem kolejno dane do pliku. Jeżeli chcemy mieć dane zabezpieczone przed modyfikowaniem ręcznym można plik spakować ZLibem albo prosto zaszyfrować choćby xor'em czy szyfrem Cezara. Inne rozwiązanie to zapis do pliku typu XML. Jednak według mnie zapisywanie do pliku typowanego jest łatwiejsze. Tylko wiadomo jeżeli zapisujemy stringi to albo ograniszamy długośc pól, ale lepiej według mnie "zmarnowac" dodatkowe cztery bajty i zapisywać wcześniej długośc tekstu we własnościach zawierających takowy tekst. W google znajdziesz potrzebne przykłady na wspomniane przeze mnie rozwiązanie. Na pewno o wiele lepsze niż kombinowanie z zapisaniem komponentu lub całek zakładki.


Pozdrawiam.
0

Dzięki.
Jeżeli macie jeszcze jakieś pomysły albo części kody tez z chęcią przyjmę.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12164
0

@Greho - przyjąć każdy przyjmie, tylko kto je napisze? :]

Teraz jedyne co Ci pozostaje to testować różne rozwiązania, jakie zostały zaproponowane; Jeśli będziesz miał problem z kodem (a nie z jego brakiem) to napisz - pomoże się go usprawnić.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
0

To może chociaż jakieś pomocne komendy.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12164
0

Gotowca nie dostaniesz - taka jest zasada tego forum, jednak przykładowy algorytm mogę przedstawić;


Poniżej przykład zapisu do i odczyt z pliku amorficznego; Algorytm jest na tylko "ubogi", że:

  • zapisuje jedynie krótkie łańcuchy ShortString - aby to zmienić musisz użyć innego typu dla długości każdej wartości komórki niż Byte,
  • nie obsługuje szyfrowania - zawartość pliku można łatwo odczytać i zmodyfikować w dowolnym HexEdytorze,
  • zapisuje zawartość jedynie jednego StringGrid - aby rozszerzyć go o zapis zawartości dowolnej ilości gridów należy go nieco zmodyfikować,
  • zapis obejmuje jedynie zawartości komórek - żadnych dodatkowych informacji prócz ilości kolumn i wierszy, które są niezbędne do poprawnego odczytu zawartości pliku,
  • zapisywane są zawartości wszystkich komórek, także tytułowych - aby je wykluczyć należy inaczej indeksować dolne granice pętli,
  • zapis odbywa się do pliku amorficznego o formacie *.sgf (od StringG*rid file* - przykładowe rozszerzenie),
  • nie są obsługiwane wyjątki jeśli zapis/odczyt nie powiedzie się (jeśli nie można utworzyć pliku, nie można go otworzyć czy wystąpi błąd podczas odczytywania);
    Aby wyposażyć algorytm w ww. zabezpieczenia/unowocześnienia wystarczy poświęcić pół godziny - góra godzinę pod warunkiem, że w pełni rozumie się kod i dokładnie wie się co wykonuje;

Zapis zawartości StringGrid do pliku jest rzeczą bardzo prostą, należy po kolei:

Kopiuj
1. zapisać ilość kolumn,
2. zapisać ilość wierszy,
3. w pętli (kolumny):
   1. w pętli (wiersze):
      1. pobrać długość łańcucha z komórki o współrzędnych pobranych z dwóch pętli,
      2. zapisać długość łańcucha,
      3. jeśli długość łańcucha jest większa niż 0:
         1. zapisać łańcuch;

Kod przykładowej procedury:

Kopiuj
procedure SaveGridToFile(const AFileName: TFileName; AGrid: TStringGrid);
var
  intColCnt, intRowCnt, intCol, intRow: Word;
  intValueLen: Byte;
begin
  with TFileStream.Create(AFileName, fmCreate) do
  try
    intColCnt := AGrid.ColCount;
    intRowCnt := AGrid.RowCount;
    WriteBuffer(intColCnt, SizeOf(Word));
    WriteBuffer(intRowCnt, SizeOf(Word));

    for intCol := 0 to intColCnt - 1 do
      for intRow := 0 to intRowCnt - 1 do
      begin
        intValueLen := Length(AGrid.Cells[intCol, intRow]);
        WriteBuffer(intValueLen, SizeOf(Byte));

        if intValueLen > 0 then
          WriteBuffer(AGrid.Cells[intCol, intRow][1], intValueLen);
      end;
  finally
    Free();
  end;
end;

Procedura do zapisu wykorzystuje strumień klasy TFileStream;


Aby odczytać z pliku wcześniej zapisaną zawartość StringGrid należy po kolei:

Kopiuj
1 wczytać ilość kolumn,
2. wczytać ilość wierszy,
3. ustawić w kontrolce ilość kolumn,
4. ustawić w kontrolce ilość wierszy,
5. w pętli (kolumny):
   1. w pętli (wiersze):
      1. wczytać długość łańcucha dla danej komórki,
      2. jeśli długość łańcucha jest większa niż 0:
         1. ustawić długość pomocniczej zmiennej łańcuchowej na tą wczytaną,
         2. wczytać łańcuch z pliku do zmiennej pomocniczej,
         3. ustawić wartość komórki kopiując (przypisując) łańcuch pomocniczy;

Kod przykładowej procedury:

Kopiuj
procedure LoadGridFromFile(const AFileName: TFileName; AGrid: TStringGrid);
var
  intColCnt, intRowCnt, intCol, intRow: Word;
  intValueLen: Byte;
  ansiValue: AnsiString;
begin
  with TFileStream.Create(AFileName, fmOpenRead) do
  try
    Position := 0;  // ta linia nie jest potrzebna

    ReadBuffer(intColCnt, SizeOf(Word));
    ReadBuffer(intRowCnt, SizeOf(Word));
    AGrid.ColCount := intColCnt;
    AGrid.RowCount := intRowCnt;

    for intCol := 0 to intColCnt - 1 do
      for intRow := 0 to intRowCnt - 1 do
      begin
        ReadBuffer(intValueLen, SizeOf(Byte));

        if intValueLen > 0 then
        begin
          SetLength(ansiValue, intValueLen);
          ReadBuffer(ansiValue[1], intValueLen);
          AGrid.Cells[intCol, intRow] := ansiValue;
        end;
      end;
  finally
    Free();
  end;
end;

Podobnie jak do zapisu - procedura korzysta z klasy TFileStream;


Dodatkowo w załączniku zamieszczam aplikację (bez pliku wykonywalnego), w której testowałem ww. algorytmy - pisana pod Delphi7, jednak można ją bez problemu zaimportować do Lazarusa i tam sprawdzić jej działanie (ja nie testowałem).


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
babubabu
Gotowca nie dostaniesz ale dam CI algorytm z gotowcem...
flowCRANE
Algorytm jest tak ubogi, że nie wykorzysta go w programie, bo zapisuje jedynie jeden StringGrid, a pytaczowi chodzi o zapis dowolnej ilości do jednego pliku; Napisałem na samym początku posta czego mu brakuje (części nie musi chcieć wykorzystać), więc i tak trzeba go zmodyfikować ;)
0

Tle wystarczy, Cały kod umieszczę po skończeniu.

0
Kopiuj
unit dziennikLekcyjnyGP;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls, ComCtrls, TabNotBk, Grids, ExtCtrls, Tabs, ExtDlgs,ShellAPI;

type
  TForm1 = class(TForm)
    MainMenu: TMainMenu;
    Plik1: TMenuItem;
    Koniec2: TMenuItem;
    Zapisz1: TMenuItem;
    Wczytaj1: TMenuItem;
    Obecnosc1: TMenuItem;
    Srednia1: TMenuItem;
    PageControl1: TPageControl;
    Dodajzak1: TMenuItem;
    Zamknijzak1: TMenuItem;
    Edit1: TEdit;
    procedure Koniec2Click(Sender: TObject);
    procedure Wczytaj1Click(Sender: TObject);
    procedure Zapisz1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Dodajzak1Click(Sender: TObject);
    procedure Zamknijzak1Click(Sender: TObject);
    procedure Srednia1Click(Sender: TObject);
    procedure Obecnosc1Click(Sender: TObject);
  private
    { Private declarations }
  public
  { Public declarations }
    i,k,tab:integer;
    plik: file;
    dane:string;
  end;

var
  Form1: TForm1;
  StringGrid:TStringGrid;


implementation
  {$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);  //jest uzywana na onCreat i po nacisknieci nowy
begin                                          //wywoluje procedure wypelnij_tabele
  tab:=0;
  i:=2;
  k:=3;
end;

procedure wypelnij_tabele(var s:TstringGrid); //przypisuje nazwy do komurek
var i,j:integer;
begin
  with s do begin
  Cells[1,0]:='Imie';
  Cells[0,1]:='Daty lekcji';
  Cells[2,0]:='Nazwisko';
  Cells[3,0]:='Oceny';
  Cells[12,0]:='Średnia';
  Cells[13,0]:='Obecnosc';
  Cells[33,0]:='Uwagi';
  Cells[41,0]:='Komentarze';
  begin
    for i:=2 to 52 do
      begin
      for j:=13 to 32 do
        begin
          Cells[j,i]:='Obecny';
        end;
        cells[0,i]:=IntToStr(i);
      end;
  end;
  for i:=1 to 52 do
    cells[0,i+1]:=IntToStr(i);
  end;
end;

//zapis tabeli do pliku
procedure SaveStringGrid(StringGrid: TStringGrid; const FileName: TFileName);
var
  f:    TextFile;
  i, k: Integer;
begin
  AssignFile(f, FileName);
  Rewrite(f);
  with StringGrid do
  begin
    Writeln(f, ColCount); // zapisuje liczbe kolumn i wierszy
    Writeln(f, RowCount);
    for i := 0 to ColCount - 1 do    // zapisuje wszystkie pomurki stinggrida
      for k := 0 to RowCount - 1 do
        Writeln(f, Cells[i, k]);
  end;
  CloseFile(f);
end;

//odczyt tabeli z pliku
procedure LoadStringGrid(StringGrid: TStringGrid; const FileName: TFileName);
var
  f:          TextFile;
  iTmp, i, k: Integer;
  strTemp:    String;
begin
  AssignFile(f, FileName);
  Reset(f);
  with StringGrid do
  begin
    Readln(f, iTmp);       // pobiera liczbe kolumn
    ColCount := iTmp;
    Readln(f, iTmp);      // pobiera liczbe wierszy
    RowCount := iTmp;
    for i := 0 to ColCount - 1 do      // robi petle i wylełnia komurki
      for k := 0 to RowCount - 1 do
      begin
        Readln(f, strTemp);
        Cells[i, k] := strTemp;
      end;
  end;
  CloseFile(f);
end;

procedure TForm1.Dodajzak1Click(Sender: TObject); //Dodaje zakladke
var
  TabSheet: TTabSheet;
  nazwa:string;

begin                  //Okienko z pyt o nazwe zakłądki i tworzy stringgrid w pagecontrol
  Edit1.Text:=InputBox('Dodawanie przedmiotu','Podaj nazwe przedmiotu:','Tu wpisz nazwe przedmiotu');
  if (Edit1.Text<>'') and (Edit1.Text<>'Tu wpisz nazwe przedmiotu') then
  begin
  nazwa:=(Edit1.Text);
  TabSheet := TTabSheet.Create(PageControl1);
  TabSheet.Caption := nazwa;
  TabSheet.PageControl := PageControl1;
  StringGrid := TStringGrid.Create (TabSheet);
  StringGrid.ColCount := 50;
  StringGrid.Align:=alClient;
  StringGrid.ScrollBars:=ssBoth;
  StringGrid.Options := StringGrid.Options + [goThumbTracking];
  StringGrid.Options:= StringGrid.Options + [goEditing];
  StringGrid.Options:= StringGrid.Options + [goFixedRowClick];
  StringGrid.Options:= StringGrid.Options + [goFixedColClick];
  StringGrid.Options:= StringGrid.Options + [goTabs];
  StringGrid.Options:= StringGrid.Options + [goRowSizing];
  StringGrid.Options:= StringGrid.Options + [goColSizing];
  StringGrid.Parent := TabSheet;
  wypelnij_tabele(StringGrid);
  StringGrid.RowCount := 52;
  StringGrid.Visible := True;
  tab:=tab+1;
  end;
end;

procedure TForm1.Koniec2Click(Sender: TObject);  //zamyka program
begin
  Close;
end;

procedure TForm1.Obecnosc1Click(Sender: TObject);  //wpisuje nieobennosc do komurki z wybramym nazwiskiem
var
    nazwisko,data: String;
    col,row:integer;
begin
             begin
                Edit1.Text:=InputBox('Nie obecni','Podaj nazwisko nieobecnej osoby:','Nazwisko');
                nazwisko:=(Edit1.Text);
             end;
             begin
                Edit1.Text:=InputBox('Nie obecni','Podaj date nieobecnosci:','Data');
                data:=(Edit1.Text);
             end;
              for row := 1 to 52 do
              for col := 13 to 32 do

              begin
                if (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[col,1]=data then
                if (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[2,row]=nazwisko then
                  begin
                    (PageControl1.ActivePage.Controls[0] as TStringGrid).Row:=row;//zaznaczanie komorki w danym wierszy
                    (PageControl1.ActivePage.Controls[0] as TStringGrid).Col:=col;//zaznaczanie komorki w danej kolumnie
                    (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[col,row]:=('Nie obecny');
                  end;
              end;

           end;

procedure TForm1.Srednia1Click(Sender: TObject); //oblicza srednia ocen
var
  col,row,dziel,suma:integer;
  sr:real;
begin
  for row := 1 to StringGrid.RowCount do
      begin
         suma:=0;
         dziel:=0;
         sr:=0;
         for col := 3 to 10 do
           begin
             if (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[col,row]='' then
             else
             begin
                suma:=suma+StrToInt((PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[col,row]);
                dziel:=dziel+1;
             end;
           end;
           if (dziel>0) then
             begin
                sr:=suma / dziel;
                (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[12,row]:=FloatToStr((Round(sr*100)/100));
             end;
        end;
end;


procedure TForm1.Wczytaj1Click(Sender: TObject);   //wczytuje stringgrid po kolumn i wierszy
var
q:integer;
TabSheet: TTabSheet;
nazwa:string;
w:TextFile;

begin
  AssignFile(w, '.\zapis\dane.txt');
  reset(w);
  readln(w,tab);
  for q := 0 to tab -1 do
  begin
      readln(w,nazwa);
      TabSheet := TTabSheet.Create(PageControl1);
      TabSheet.Caption := nazwa;
      TabSheet.PageControl := PageControl1;
      StringGrid := TStringGrid.Create (TabSheet);
      StringGrid.ColCount := 50;
      StringGrid.Align:=alClient;
      StringGrid.ScrollBars:=ssBoth;
      StringGrid.Options := StringGrid.Options + [goThumbTracking];
      StringGrid.Options:= StringGrid.Options + [goEditing];
      StringGrid.Options:= StringGrid.Options + [goFixedRowClick];
      StringGrid.Options:= StringGrid.Options + [goFixedColClick];
      StringGrid.Options:= StringGrid.Options + [goTabs];
      StringGrid.Options:= StringGrid.Options + [goRowSizing];
      StringGrid.Options:= StringGrid.Options + [goColSizing];
      StringGrid.Parent := TabSheet;
      StringGrid.RowCount := 52;
      wypelnij_tabele(StringGrid);
      StringGrid.Visible := True;
      PageControl1.ActivePageIndex:=q;
      LoadStringGrid((PageControl1.ActivePage.Controls[0] as TStringGrid), '.\zapis\'+nazwa+'.txt');
  end;
  CloseFile(w);
  end;

procedure TForm1.Zamknijzak1Click(Sender: TObject); //usuwa zakłądke akutalnie aktywną
begin
if FileExists('.\zapis\'+PageControl1.Pages[PageControl1.ActivePageIndex].Caption+'.txt') then
  begin
    PageControl1.Pages[PageControl1.ActivePageIndex].Free;
    tab:=tab-1;
  end
else
  begin
    PageControl1.Pages[PageControl1.ActivePageIndex].Free;
    tab:=tab-1;
  end;
end;

procedure TForm1.Zapisz1Click(Sender: TObject);   //zapisuje tekst z stringgrid to kol i wirszy
var
q:integer;
w:    TextFile;
begin
  AssignFile(w, '.\zapis\dane.txt');
  Rewrite(w);
  writeln(w,tab);
  for q := 0 to tab - 1 do
  begin
    writeln(w,PageControl1.Pages[q].Caption);
  end;
  CloseFile(w);

  for q := 0 to tab - 1 do
    begin
      PageControl1.ActivePageIndex:=q;
      SaveStringGrid((PageControl1.ActivePage.Controls[0] as TStringGrid), '.\zapis\'+PageControl1.Pages[q].Caption+'.txt');
    end;
end;

end.

dodanie znacznika <code class="delphi"> - fp

edytowany 1x, ostatnio: flowCRANE
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 6 godzin
  • Lokalizacja:Tuchów
  • Postów:12164
0

I co w związku z tym kodem? Chciałeś się tylko pochwalić, czy masz jeszcze jakies pytania?

Widzę, że skorzystałeś z najłatwiejszej opcji jaką jest zapis StringGrid do pliku tekstowego - nie jest to najlepsze rozwiązanie, bo łatwo taki plik zepsuć i program nie udławi; Jeśli takie rozwiązanie Cię satysfakcjonuje to nie ma sprawy, niemniej jednak polecam wykorzystać pliki amorficzne, nie dając tym samym takiej łatwości modyfikacji;

Poza tym masz sporo zbędnego kodu, np.:

Kopiuj
  StringGrid.Options:= StringGrid.Options + [goThumbTracking];
  StringGrid.Options:= StringGrid.Options + [goEditing];
  StringGrid.Options:= StringGrid.Options + [goFixedRowClick];
  StringGrid.Options:= StringGrid.Options + [goFixedColClick];
  StringGrid.Options:= StringGrid.Options + [goTabs];
  StringGrid.Options:= StringGrid.Options + [goRowSizing];
  StringGrid.Options:= StringGrid.Options + [goColSizing];

możesz przecież napisać tak:

Kopiuj
StringGrid.Options := [goThumbTracking, goEditing, goFixedRowClick, goFixedColClick,
                       goTabs, goRowSizing, goColSizing];

Dodatkowo trzeba zauważyć, że ten kod wykorzystujesz w dwóch miejscach, więc możesz zadeklarować sobie stałą ze zbiorem tych wartości i wykorzystywać ją wielokrotnie:

Kopiuj
const
  SG_OPTIONS_SET: TGridOptions = [goThumbTracking, goEditing, goFixedRowClick, goFixedColClick, 
                                  goTabs, goRowSizing, goColSizing];

i potem wykorzystać go w ten sposób:

Kopiuj
StringGrid.Options := SG_OPTIONS_SET

BTW: Skąd wziąłeś wartości goFixedRowClick i goFixedColClick? Typ TGridOption ani w Delphi7, ani w Lazarusie nie posiada takich wartości;

EDIT: już wiem skąd - dokumentacja XE2 rozwiała moje wątpliwości :]


Następnie ten kod:

Kopiuj
begin
  if (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[col,1]=data then
    if (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[2,row]=nazwisko then
    begin
      (PageControl1.ActivePage.Controls[0] as TStringGrid).Row:=row;//zaznaczanie komorki w danym wierszy
      (PageControl1.ActivePage.Controls[0] as TStringGrid).Col:=col;//zaznaczanie komorki w danej kolumnie
      (PageControl1.ActivePage.Controls[0] as TStringGrid).Cells[col,row]:=('Nie obecny');
    end;
end;

Można skrócić i uprościć, zamiast wielokrotnie rzutować operatorem As:

Kopiuj
var
  sgActive: TStringGrid;
  {...}
begin
  {...}

  begin
    sgActive := (PageControl1.ActivePage.Controls[0] as TStringGrid);

    if (sgActive.Cells[Col, 1] = Data) and (sgActive.Cells[2, Row] = Nazwisko) then
    begin
      sgActive.Row := Row;
      sgActive.Col := Col;
      sgActive.Cells[Col, Row] := 'Nieobecny';
    end;
  end;

  {...}

Z racji tej, że sgActive nie tworzysz, bo przypisujesz do niej referencję istniejącego komponentu - także go nie zwalniasz; Przez to kod staje się uproszczony i wydajniejszy, bo rzutowanie przez As wykonujesz raz, a później odwołujesz się już do obiektu bezpośrednio, nie przez kolejne kilka rzutowań; Poza tym wykorzystujesz zmienne o identyfikatorach takich samych, jak nazwy właściwości komponentu, więc w kodzie wyżej nie można zastosować instrukcji wiążącej With - postaraj się lepiej nazywać zmienne/stałe;

Ja wykorzystuję znienawidzoną przez większość programistów notację węgierską, przez co mogę zmienne nazywać tak samo jak właściwości klas czy pola rekordów i mogę wykorzystać do ich modyfikacji/odczytywania instrukcję wiążącą; Ale to tylko luźna sugestia;


I na koniec:

Kopiuj
procedure TForm1.Zamknijzak1Click(Sender: TObject); //usuwa zakłądke akutalnie aktywną
begin
if FileExists('.\zapis\'+PageControl1.Pages[PageControl1.ActivePageIndex].Caption+'.txt') then
  begin
    PageControl1.Pages[PageControl1.ActivePageIndex].Free;
    tab:=tab-1;
  end
else
  begin
    PageControl1.Pages[PageControl1.ActivePageIndex].Free;
    tab:=tab-1;
  end;
end;

Kod tego zdarzenia nie ma żadnego sensu - bez względu na stan warunku zostaną wykonane dokładnie te same instrukcje, a funkcja FileExists nie ma tutaj żadnego zastosowania, bo całość można skrócić do:

Kopiuj
procedure TForm1.Zamknijzak1Click(Sender: TObject);
begin
  PageControl1.Pages[PageControl1.ActivePageIndex].Free;
  Dec(Tab);
end;

i będzie robić dokładnie to samo;


Tak więc przysiądź jeszcze trochę nad tym kodem i go zoptymalizuj, bo można go znacząco skrócić.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
0

Chciałem się podzielić.

flowCRANE
Spróbuj go jeszcze zoptymalizować;
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)