Jak zapisać i odczytać ustawienia "font" dla TForm?

0

Hejka,

Mam taki kawałek kodu:

Form1.Font := TDialogFont.Font;

i to ładnie działa. Potrzebowałbym teraz zapisać ustawienia tego font'a do pliku/rejestru i przy ponownym uruchomieniu to odczytać.

Oczywiście mogę to zrobić ręcznie ale mam nadzieje, że podpowiecie mi rozwiązanie gdzie zrobię tylko SAVE i RESTORE. Ustawienia FONT'a mam też dla poszczególnych komponentów więc np zapisywanie każdego z osobna ... no po prostu mi się nie chce. Podpowiecie jak to się ogarnia w tych nowszych delphi?

4

Może zapis ustawień całej formy: https://stackoverflow.com/questions/3163586/how-to-save-and-restore-a-form
a jeżeli tylko konkretnych właściwości to: https://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvFormStorage

0

Wiecie mogę tak:

uses Inifiles;
 
procedure SaveFont(FName: string; Section: string; smFont: TFont);
var
  FStream: TIniFile;
begin
  FStream := TIniFile.Create(FName);
  try
    FStream.WriteString(Section, 'Name', smFont.Name);
    FStream.WriteInteger(Section, 'CharSet', smFont.CharSet);
    FStream.WriteInteger(Section, 'Color', smFont.Color);
    FStream.WriteInteger(Section, 'Size', smFont.Size);
    FStream.WriteInteger(Section, 'Style', Byte(smFont.Style));
  finally
    FStream.Free;
  end;
end;
 
procedure LoadFont(FName: string; Section: string; smFont: TFont);
var
  FStream: TIniFile;
begin
  FStream := TIniFile.Create(Fname);
  try
    smFont.Name    := FStream.ReadString(Section, 'Name', smFont.Name);
    smFont.CharSet := TFontCharSet(FStream.ReadInteger(Section, 'CharSet', smFont.CharSet));
    smFont.Color   := TColor(FStream.ReadInteger(Section, 'Color', smFont.Color));
    smFont.Size    := FStream.ReadInteger(Section, 'Size', smFont.Size);
    smFont.Style   := TFontStyles(Byte(FStream.ReadInteger(Section, 'Style', Byte(smFont.Style))));
  finally
    FStream.Free;
  end;
end;
 
//Save Font
procedure TForm1.Button1Click(Sender: TObject);
begin
  SaveFont('font.ini', 'label', label1.Font);
end;
 
procedure TForm1.Label1DblClick(Sender: TObject);
begin
  if FontDialog1.Execute then
    label1.Font := FontDialog1.Font
end;
 
//Load Font
procedure TForm1.Button2Click(Sender: TObject);
begin
  LoadFont('font.ini', 'label', label1.Font);
end;

ale tak to się robiło 15 lat temu albo i wcześniej ... na bank to nowe GUI/VCL/FMX ma jakiś automat :)

1
woolfik napisał(a):

ale tak to się robiło 15 lat temu albo i wcześniej ... na bank to nowe GUI/VCL/FMX ma jakiś automat :)

Tylko po co ci automat i jakieś cudaczne mechanizmy serializacji, skoro masz raptem kilka parametrów do zapisania/odczytnia? Automat byłby przydatny np. wtedy, kiedy ilość informacji do zapisania byłaby nieznana w trakcie kompilacji, albo gdyby chociaż tych danych były tysiące i ręczne pisanie kodu zapisu/odczytu po prostu trwałoby za długo. Dla kilku parametrów po prostu się nie opłaca.

ale tak to się robiło 15 lat temu albo i wcześniej ...

No nie, tak się robi nadal. Z plików Ini korzysta się wtedy, kiedy ma to uzasadnienie — dla niedużych ilości prostych danych, które powinny być reprezentowane w formie tekstu, format ten jest odpowiedni. W końcu do tego został opracowany.

0

Nie, tak się nie robi nadal. Pliki .ini są deprecated w systemie Windows i pisze o tym sam Microsoft:
https://devblogs.microsoft.com/oldnewthing/20071126-00/?p=24383

0

@gajusz800 Ogólnie nie ma znaczenia czy sobie zapisze w pliku jako JSON, XML, wykorzysta rejestr Windows (tu chyba trzeba by z wszystkie właściwości czcionki danego komponentu połączyć w jeden string z określonym separatorem jak CSV) czy cokolwiek a nawet wymyśli własny format to zależy tylko i wyłącznie od fantazji programisty. Chodzi o to, że w Delphi nie ma wbudowanego mechanizmu pozwalającego na zapis i odczyt danej właściwości (w tym przypadku Font) wszystkich komponentów (ewentualnie w zależności od potrzeb tylko danego typu) i trzeba sobie to napisać samemu. Po prostu trzeba napisać sobie funkcję (wykorzystującą rekurencję) która przeleci po wszystkich komponentach sprawdzając czy mają daną właściwość i ją zapisywać i oczywiście podobnie z odczytem. Do tego aby to było optymalniej sprawdzać czy to akurat nie jest ustawiona domyślna czcionka dziedzicząca po danym TForm. Taka zabawa, nic bardzo trudnego spokojnie do zrobienia w jeden wieczór nawet w formie uniwersalnego modułu (nawet komponentu).
@Paweł Dmitruk wspomniał o istniejącym TJvFormStorage ale nigdy tego nie używałem i nie wiem jak działa czy to nie przypadkiem z wykorzystaniem RTTI a jeżeli tak to JEDI jest dość stare (chyba że ostatnio coś ruszyło, bo wydaje mi się że miało zastój w rozwoju) i czy czasem nie wykorzystuje starych że tak powiem dużo skromniejszych możliwości niż te z Delphi serii XE i nowszych. Po prostu trzeba by zobaczyć źródła.

0

Ja tylko mówię, że pliki .ini są deprecated na rzecz rejestru lub plików xml w katalogu domowym użytkownika.

Po prostu trzeba napisać sobie funkcję (wykorzystującą rekurencję) która przeleci po wszystkich komponentach sprawdzając czy mają daną właściwość i ją zapisywać i oczywiście podobnie z odczytem

No tak, czyli trzeba samemu napisać serializację i deserializację

2
gajusz800 napisał(a):

Nie, tak się nie robi nadal. Pliki .ini są deprecated w systemie Windows i pisze o tym sam Microsoft:
https://devblogs.microsoft.com/oldnewthing/20071126-00/?p=24383

Ten artykuł dotyczy obsługi plików w kontekście systemowego API, w dodatku w porównaniu do systemowego rejestru. A jak wiadomo, systemowe API jest niezwykle stare i ubiogie, jeśli chodzi o przetwarzanie plików tego formatu. Autor sam wyjaśnia, że to najzwyklejszy plik tekstowy, a w dalszej części narzeka, że nie jest thread-safe, że brak podziału na uprawnienia, że dane wrażliwe nie są chronione. Ciekawe czy też narzeka, że ledówka mu kawy nie robi i że nie da się nią dywanu odkurzyć.

Wysokopoziomowe klasy dostępne w Delphi i Free Pascalu (i dowolnym innym wysokopoziomowym języku z porządną biblioteką standardową) nie mają takich problemów. Co prawda klasy np. z Free Pascala nie są domyślnie thread safe (choć nikt nie ci broni synchronizować zapisu/odczytu), ale nie ma problemu z Unicode, nie ma problemu z wydajnością (zawartość jest cache'owana) i nie ma problemu z zapisem danych dowolnego typu (np. danych binarnych i innych, bo RTL i FCL mają do konwersji masę funkcji oraz RTTI i różne mechanizmy serializacji). Nie ma też limitu co do rozmiaru pliku, a one same mogą się znajdować gdziekolwiek (nie tylko w katalogu systemowym).

Cienki ten artykuł, w dodatku na połowę jego punktów można odpowiedzieć jednym słowem — PEBKAC.

gajusz800 napisał(a):

No tak, czyli trzeba samemu napisać serializację i deserializację

Na tym polega programowanie, że się pisze kod. Dla leniwych jest SO i ChatGPT. :D

0

Cienki ten artykuł. Ciekawe, że Microsoft pisze cienkie artykuły na temat zaleceń dotyczących programowania na swój własny system operacyjny. Może i tak, można być mądrzejszym i robić po swojemu.

Na tym polega programowanie, że się pisze kod. Dla leniwych jest SO i ChatGPT. :D

No na tym. Tylko na szczęście nie zawsze na tym, żeby wymyślać koło na nowo tak jak tu. Ale skoro nie ma obsługi serializacji to trzeba napisać ją samemu, tzn tracić na to czas, trudno.

1

Dla mnie też jest ciekawe, że argumentujesz przestarzałość formatu na podstawie 16-letniego artykułu, traktującego o porównaniu INI i rejestru w kontekście ich przestarzałego API, co nie ma za wiele wspólnego z tym, co oferuje Delphi/Free Pascal i ich wysokopoziomowe klasy do obsługi tego formatu. Tzn. to akurat u ciebie normalne, dlatego jeśli nie masz nic mądrego do napisania (a w tej kategorii forum z reguły nie masz), to ogranicz się co najwyżej do czytania jej zawartości.

0

Czyli podsumujmy:

  • pliki ini były deprecated już 16 lat temu. Dla @furious programming dziwne jest, że argumentuję przestarzałość tego formatu artykułem, który mówił że były one przestarzałe już 16 lat temu
  • Delphi oferuje tak bardzo dużo do obsługi formatu, który był deprecated już 16 lat temu, że przez to ten format przestał być deprecated
  • Microsoft nie wie jakie są najlepsze praktyki programowania na jego własny system, @furious programming wie to lepiej
  • twórca systemu Windows nie oferuje już żadnego wsparcia dla plików .ini bo dalej utrzymuje że ten format jest deprecated, po tylu latach pewnie już nawet zapominano że taki był

Tak, wszytko już zostało wyjaśnione.

0
gajusz800 napisał(a):
  • pliki ini były deprecated już 16 lat temu. Dla @furious programming dziwne jest, że argumentuję przestarzałość tego formatu artykułem, który mówił że były one przestarzałe już 16 lat temu

W kontekście funkcji z Win32 API są przestarzałe, w kontekście używania za pośrednictwem współczesnych wysokopoziomowych klas (o których nie masz bladego pojęcia, jak zresztą i o całym Pascalu) nie są i nadal można je bez problemu (i ograczeń systemowego API) wykorzystywać do celów, do których format ten został opracowany.

  • Microsoft nie wie jakie są najlepsze praktyki programowania na jego własny system, @furious programming wie to lepiej

Microsoft zna swoje API, natomiast nie ma pojęcia (podobnie jak ty) co jest dostępne w Pascalu i w bibliotekach standardowych wszystkich języków, które pozwalają na tworzenie oprogramowania i obsługę tego formatu na różnych wersjach Windows.

  • twórca systemu Windows nie oferuje już żadnego wsparcia dla plików .ini bo dalej utrzymuje że ten format jest deprecated, po tylu latach pewnie już nawet zapominano że taki był

Microsoft może zaprzestać jego wspierania z poziomu funkcji systemowych, natomiast ludzie będą korzystać z tego z czego korzystać chcą, bez względu co o tym myśli Microsoft. Dlatego też rozbudowane wsparcie dla formatu INI istniało, istnieje i będzie istnieć w bibliotekach standardowych m.in. Delphi i Free Pascala.

Tak, wszytko już zostało wyjaśnione.

Tak, dlatego idź się poniewierać gdzieś indziej.

0
furious programming napisał(a):

Dla mnie też jest ciekawe, że argumentujesz przestarzałość formatu na podstawie 16-letniego artykułu, traktującego o porównaniu INI i rejestru w kontekście ich przestarzałego API, co nie ma za wiele wspólnego z tym, co oferuje Delphi/Free Pascal i ich wysokopoziomowe klasy do obsługi tego formatu

Z czystej ciekawości - co oferuje współczesna implementacja INI w Delphi?
Z tego co wiem, klasyczna implementacja Microsoft sprzed lat, była ograniczona do ilości znaków lub coś podobnego...

Czy implementacja INI w współczesnym Delphi ma jakieś niedomagania, ograniczenia? Ja chętnie używam tego formatu, dla ustawień programu, czasem nawet do przechowywania prostych danych...
Osobiście uważam, że formaty XML czy JSON są o wiele trudniejsze w użyciu (ale oferują więcej), a format INI jest bardzo prosty.
Czy jest limit np. rozmiaru pliku, albo ilości linii (dla sekcji) lub ilości znaków w linii (klucz=wartość)?
-Pawel

0

@Pepe
Ale na jakiej podstawie twierdzisz że są trudniejsze w użyciu? Chyba że w Delphi tak jest, to zależy od tego jak jest ten format wspierany.

1
Pepe napisał(a):

Z czystej ciekawości - co oferuje współczesna implementacja INI w Delphi?
Z tego co wiem, klasyczna implementacja Microsoft sprzed lat, była ograniczona do ilości znaków lub coś podobnego...

Napisałem w jednym poprzednich swoich postów — brak ograniczeń w stosunku do systemowego API. Przede wszystkim brak limitu wielkości pliku, plik konfiguracyjny nie musi się znajdować w katalogu systemowym, zawartość jest cache'owana w RAM, pełne wsparcie Unicode, brak ograniczeń co do typu danych zapisywanych w kluczach (Delphi ma masę gotowych funkcji do konwersji wszelkich typów danych) itp. itd.

Czy implementacja INI w współczesnym Delphi ma jakieś niedomagania, ograniczenia? Ja chętnie używam tego formatu, dla ustawień programu, czasem nawet do przechowywania prostych danych...

Delphi daje mniej więcej to samo co i Free Pascal, czyli wygodną obsługę plików tego formatu. I też sam z niego korzystam, jeśli potrzebuję przechować kilka(dziesiąt) prostych wartości pokroju liczb czy stringów w formie tekstowej. XML-e i inne złożone formaty to armata na muchę.

Osobiście uważam, że formaty XML czy JSON są o wiele trudniejsze w użyciu (ale oferują więcej), a format INI jest bardzo prosty.

Zaiste. ;)

0

@gajusz800

Ale na jakiej podstawie twierdzisz że są trudniejsze w użyciu? Chyba że w Delphi tak jest, to zależy od tego jak jest ten format wspierany.

Niezależnie od narzędzia programistycznego xml i json są trudniejsze w obsłudze od ini, ponieważ mogą mieć niemal dowolną logiczną strukturę.
Pliki ini są dwuwymiarowe... sekcja i klucz w sekcji.
XML i Json mogą mieć dowolnie wiele wymiarów i stopni zagnieżdżenia.

0

Poza tym, każdorazowy zapis/odczyt danych zawsze wymaga tylko jednej instrukcji.

0
grzegorz_so napisał(a):

@gajusz800

Ale na jakiej podstawie twierdzisz że są trudniejsze w użyciu? Chyba że w Delphi tak jest, to zależy od tego jak jest ten format wspierany.

Niezależnie od narzędzia programistycznego są trudniejsze w obsłudze, ponieważ mogą mieć niemal dowolną logiczną strukturę.
Pliki ini są dwuwymiarowe... sekcja i klucz w sekcji.
XML i Json mogą mieć dowolnie wiele wymiarów i stopni zagnieżdżenia.

No tak. Czyli mamy obiekt klasy z zagnieżdżeiami, 2 linijki kodu i powstaje z tego xml lub json. Potem 2 linijki kodu i z pliku powstaje z powrotem obiekt. Nazywamy to serializacją i deserializacją, a to ile jest tam zagnieżdżeń nie ma żadnego znaczenia dla trudności. Stopień skomplikowania struktury i wielowymiarowość nie mają znaczenia, bo struktura jest generowana automatycznie z modelu i odwzorowuje model. Będzie tak skomplikowane jak jest to wymagane.

Nie rozumiem czemu twierdzisz że wielowymiarowość powoduje to, że obsługa w kodzie jest bardziej skomplikowana. Po to przecież wymyślono automatyczną serializację obiektów żeby obsługa była elastyczna i prosta, wszytkie współczesne znane mi technologie to potrafią. Albo następuje to automatycznie, albo odpowiedni kod może być wygenerowany automatycznie z modelu i ukryty przed programistą

Więc nie zgadzam się z tym:

Niezależnie od narzędzia programistycznego xml i json są trudniejsze w obsłudze od ini, ponieważ mogą mieć niemal dowolną logiczną strukturę.

Tak z ciekawości spytam - jakich technologii i narzędzi programistycznych używałeś?

3
Pepe napisał(a):

Czy implementacja INI w współczesnym Delphi ma jakieś niedomagania, ograniczenia?

Metoda odczytu z INI TIniFile.ReadString ma limit 2048 znaków, przynajmniej w starszych wersjach przed serią XE. W zamian można użyć jej poprawionej implementacji, ale też czyta tylko do 42 396 znaków i to wcale nie przez rozmiar zadeklarowanego bufora buffer.

function ReadIniString(iniFileName, section, ident, default: string): string;
var                                                                               
  buffer: array[0..42395] of Char; //metoda TIniFile.ReadString ma tu array[0..2047] of Char;
begin
  SetString(result, buffer, GetPrivateProfileString(PChar(section), PChar(ident), PChar(default), buffer, length(buffer), PChar(iniFileName)));
end;
3

Tutaj właśnie mamy przykład tego, jak wygląda używanie przestarzałego API systemu Windows.

Funkcja GetPrivateProfileString nie powinna być w ogóle używana współcześnie, dlatego że ona istnieje w Win32 API tylko ze względu na wsteczną kompatybilność z 16-bitowymi aplikacjami, których nie da się uruchomić w środowiskach 64-bitowych (od Windows XP 64-bit wydanego w 2005 roku, czyli od 18 lat). Poza tym posiada szereg wad, o których rozmawialiśmy od początku wątku.

We Free Pascalu ten problem nie istnieje, bo klasa TIniFile nie używa żadnych funkcji specyficznych dla platformy. Zawartość pliku jest parsowana, dzielona na listy sekcji i kluczy, do których dostęp ma się natychmiastowy i bez żadnych ograniczeń.

1 użytkowników online, w tym zalogowanych: 0, gości: 1