Procedura zwraca kolejną część stringa oddzieloną od siebie znakiem seperatora. Przykład:
Jeśli mamy string: s=’Ala ma kota’;
to wywołanie GetSubstring(s,’ ’) będzie kolejno zwracało:
pierwsze wywołanie: ala
drugie wywołanie: ma
trzecie wywołanie: kota
UWAGA: string wejściowy ulega zmianie !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function GetSubstring(var inStr:string;const separator:string):string var t: integer; begin t := Pos(separator, inStr); if t <=0 then t := Length(inStr)+1; Result := Copy(inStr, 1, t-1); inStr := Copy(inStr, t+1, Length(inStr)); end; |
Pisząc program, który ma działać np. w Polsce i w Anglii należy pamiętać, że standardowo systemy operacyjne będą zawierały inne separatory liczb zmiennoprzecinkowych. Ta funkcja pozwoli na pozbycie się tego problemu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function StrToFloat(AStr: String): Extended; var i: Integer; begin // , i . zamien na DecimalSeparator (powinien być jeden 😉 for i := 1 to Length(AStr) do if AStr in [',', '.'] then begin AStr := DecimalSeparator; Break; end; Result := SysUtils.StrToFloat(AStr); end; |
Jeżeli tworzymy aplikację MDI i przesuniemy okno – dziecko poza obszar roboczy rodzica, to pojawią się w owym rodzicu ScrollBary, niechciane niekiedy. Natknąłem się na ten problem i znalazłem tylko jedno gotowe rozwiązanie, które na dodatek było niechlujnie (wg mnie) napisane, a poza tym nie zawierało żadnego opisu, dlatego zamieszczam kod wraz z moimi komentarzami.
OnCreate głównej formy powinno wyglądać tak:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
procedure TmainForm.FormCreate(Sender: TObject); begin // w drugim ifie sprawdzamy, czy miejsce przeznaczone do użycia przez nas jest wolne (wtedy zwrócone będzie 0) // następnie ustawiamy w tym miejscu wartość zwróconę przez zagnieżdzoną funkcję SetWindowLong - ustawiamy w niej adres // naszej funkcji obsługi okna, a funkcja ta (SetWindowLong) jako wartość zwracaną podstawia (w tym przypadku) adres poprzedniej funkcji okienkowej if ClientHandle <> 0 then if (GetWindowLong(ClientHandle, GWL_USERDATA) = 0) then SetWindowLong(ClientHandle, GWL_USERDATA, SetWindowLong(ClientHandle, GWL_WNDPROC, Integer(@ClientWindowProc))); end; |
Teraz, przed OnCreate głównej formy dodajemy tą funkcję:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
function ClientWindowProc(Wnd: HWND; Msg: Cardinal; WParam, LParam: Integer) : Integer; stdcall; var f: Pointer; begin // pobieramy spod GWL_USERDATA adres poprzedniej, domyślnej funkcji obsługi okna // potem, jeżeli ScrollBary są ustawione, to zmieniamy styl okna na taki jaki // właśnie obowiązuje z wyłączeniem ScrollBarów f := Pointer(GetWindowLong(Wnd, GWL_USERDATA)); if Msg = WM_NCCALCSIZE then if (GetWindowLong(Wnd, GWL_STYLE) and (WS_HSCROLL or WS_VSCROLL)) <> 0 then SetWindowLong(Wnd, GWL_STYLE, GetWindowLong(Wnd, GWL_STYLE) and not (WS_HSCROLL or WS_VSCROLL)); // wywołujemy główną funkcję okienkową Result := CallWindowProc(f, Wnd, Msg, WParam, LParam); end; |
Funkcja jako argument przyjmuje obiekt TStrings oraz separator, którym zostaną oddzielone kolejne elementy TStrings.
Funkcja zwraca rezultat łączenia.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function Join(ASt: TStrings; ASep: String): String; var i: Integer; begin Result := ''; for i := 0 to ASt.Count - 2 do // z -2 zeby nizej dodac bez Sep'a Result := Result + ASt + ASep; Result := Result + ASt[ASt.Count - 1]; // ostatni dodaj bez Sep'a end; |
Użyj tego kodu:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
procedure TForm1.Button1Click(Sender: TObject); var a,b,c,X1,X2,De:single; begin a:=StrToFloat(Edit1.Text); b:=StrToFloat(Edit2.Text); c:=StrToFloat(Edit3.Text); if a<>0 then begin De:=b*b-4*a*c; if de>=0 then begin X1:=(-b-sqrt(de))/(2*a); X2:=(-b+sqrt(de))/(2*a); if de=0 then begin Edit4.Text:='Jeden podwójny pierwiastek: '+FormatFloat('0.00',X1); Edit5.Text:='Jeden podwójny pierwiastek: '+FormatFloat('0.00',X1); end else begin Edit4.Text:='Dwa pierwiastki (1): '+FormatFloat('0.00',X1); Edit5.Text:='Dwa pierwiastki (2): '+FormatFloat('0.00',X2); end; end else begin Edit4.Text:='Brak pierwiasktów rzeczywistych...'; Edit5.Text:='...ale są pierwiastki zespolone :> '; end; end; end; |
Funkcja, która zwróci nam rzeczownik w odpowiedniej formie, np:
Deklinacja(1, 'bajt’, 'bajty’, 'bajtów’): zwróci 'bajt’
Deklinacja(15, 'minuta’, 'minuty’, 'minut’): zwróci: ’15 minut’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function Deklinacja(const AVal: Integer; const AWordA, AWordB, AWordC: String): String; begin if (AVal mod 10 > 1) and (AVal mod 10 < 5) and ((AVal mod 100 >= 10) or (AVal mod 100 <= 21)) then Result := IntToStr(AVal) + ' ' + AWordB else if AVal <> 1 then Result := IntToStr(AVal) + ' ' + AWordC else Result := '1 ' + AWordA; end; |
Użycie:
1 2 3 |
Deklinacja(1, 'bajt', 'bajty', 'bajtów') Deklinacja(15, 'minuta', 'minuty', 'minut') |
(kod na podstawie: http://blog.i64.pl/BlogPio/200612/05-deklinacja-rzeczownika-w-funkcji-licznika/
Sprawa jest denerwująca, ale prosta w rozwiązaniu – wystarczy, aby OnClose wyglądało tak:
1 2 3 4 5 6 7 |
procedure TformChild.FormClose(Sender: TObject; var Action: TCloseAction); begin Action := caFree; end; |
Dodam, że w mojej książce do Delphi napisane jest, że Microsoft uważa to za standardowe zachowanie, dobre ^_^