Qt - QSettings

0

Bawię się klasą QSettings aby nauczyć się używać tej klasy. Utworzyłem plik ini zapisałem tam jakieś ustawienia używając polskich znaków i po otwarciu pliku zobaczyłem dziwne znaki i nie wiem w jakim jest to kodowaniu. Poniżej przykład

[Nazwa%20u%U017Cytkownika]

[Ustawienia%20IP]

mój problem polega na tym, jak funkcji setValue nakazać wpisywanie znaków w kodowaniu UTF8 i aby po otwarciu pliku było widać normalne polskie znaki, spacje itp... ?

0

Używaj angielskiej terminologii. Dane pewnie są serializowane i się nie da, bo właśnie po to są serializowane aby zachować zgodność z formatem INI, który najwyraźniej oczekuje url encodingu dla znaków niealfanumerycznych - a przynajmniej tak jest w rozumieniu Qt.

0

próbowałem ale wnioski są takie

@kq ma rację - bo Qt domyślnie koduje w UTF-8 (wczoraj przeglądałem to co podałeś @alagner)

void QSettings::setIniCodec(const char *codecName)

idąc dalej zaglądając do dokumentacji wymienione są rodzaje kodowania plików

więc tak naprawdę nic nie wskóram, musiałbym to konwertować na ASCII albo najlepiej iść za radą @kq i używać angielskiej terminologii

w sumie przy wątku poruszę jeszcze jedną kwestię. Jest jedna funkcja która wydaje mi się taka z tylnej części ciała, bo jej dwa argumenty przeczą same sobie i o to ponizej ta "wspaniała" funkcja

void QSettings::setPath(QSettings::Format format, QSettings::Scope scope, const QString &path)

która przyjmuje trzy argumenty

  • Pierwszy argument to format pliku w jakim chcemy przetrzymywać ustawienia
  • Drugi argument to zakres - wynika z tego, że jest to coś w rodzaju domyślnej ścieżki zapisu pliku z ustawieniami - opis
  • Trzeci argument to ścieżka do katalogu gdzie ten plik będzie zapisany

argumenty drugi i trzeci wzajemnie się wykluczają - bo powinno być albo "domyślny zakres" albo "podaje się na sztywno ścieżkę".

żeby plik miał właściwą nazwę, to trzeba mu nadać nazwę organizacji

QCoreApplication::setOrganizationName("test");

a poniżej cały kod

    QHostAddress ip;
    ip.setAddress("192.168.0.1");
   
    QCoreApplication::setOrganizationName("test");

    QSettings setting;
    setting.setIniCodec("UTF-8");
    setting.setPath(QSettings::IniFormat,QSettings::UserScope,"/home//Projekty-Qt/konsolówki/konsolowe-Debug/");
    setting.beginGroup("Ustawienia IP");
    setting.setValue("IP_addr",ip.toString());
    setting.endGroup();

    setting.beginGroup("Nazwa użytkownika");
    setting.setValue("Jakiś User",2);
    setting.endGroup();

    qDebug()<< setting.status();

powyższy kod zapisuje mi tylko w lokalizacji QSettings::UserScope - a ścieżka do tego jest taka /home/user/.config

więc skoro tak, to po co jest ten TRZECI ARGUMENT ? Jeżeli nie jest brany pod uwagę ?

wiem, że jest konstruktor

QSettings(const QString &fileName, QSettings::Format format, QObject *parent = nullptr)

który stworzy mi odpowiedni format pliku i zapisze plik tam gdzie chcę, ale niech mi ktoś wyjaśni, po co taka bezsensowna funkcja z wzajemnie wykluczającymi się argumentami ?

2

Sets the path used for storing settings for the given format and scope, to path.
Czyli umożliwia Ci ustawienie lokalizacji dla danego formatu i scope.
Czyli mniej więcej

QSettings s1("settings.ini", QSettings::IniFormat);  // użycie domyślnej lokalizacji
QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, "C:\kopytko");
QSettings s2("settings.ini", QSettings::IniFormat); // użycie C:\kopytko

Zauważ, że:
Warning: This function doesn't affect existing QSettings objects.

Przenieś w swoim kodzie linijkę 8 przed linijkę 6 i zobacz co się stanie ;)

1

Tu nie chodzi o to, że ścieżka może być w relacji do katalogu scope? Jak podajecie bezwzględną to nic dziwnego że jest to samo.

2

@kq nie, jest odwrotnie. setPath ustawia katalog domyślny dla danego scope'a (zamiast systemowego, czyli dla UserScope ${HOME}/.config w Linuxie - aczkolwiek tam nie testowałem tego; %APPDATA% na Win).
EDIT: i tak, zgadzam się, że jest to średnio intuicyjne ;)

0

szczerze ? Funkcja setPath jest beznadziejnie przemyślana, nie dość, że jest nieintuicyjna, to uparcie zapisuje w jednej lokalizacji i nie jest istotne czy podam ścieżkę względną czy bezwzględną, może czegoś nie rozumiem, może coś robię źle ? Ale ta funkcja nie tak powinna być zaimplementowana

0

dla zainteresowanych.

Ogólnie myślę, że udało mi się dojść dlaczego funkcja nie działa jak trzeba. Pomijam już to, że jest ona w ogóle nieprzemyślana... taka z tylnej części ciała

w pliku z projektem "pro" należy ustawić zmienną np w taki sposób

DESTDIR = /home/user/.config/test

w kodzie cpp należy zrobić coś takiego

    QSettings::setPath(QSettings::IniFormat,QSettings::UserScope,"tu może być dowolny string zwany ścieżką, który i tak nie zadziała");

    QSettings setting("test.ini",QSettings::IniFormat);

jak ustawimy w zmiennej DESTDIR ścieżkę, to plik konfiguracyjny będzie właściwie zapisywany uwzględniając ścieżkę z tej zmiennej.

Tak jest przynajmniej pod linuchem, nie wiem jak jest pod windozą

Ciekawe do kogo można słać bluzgi i reklamacje w sprawie tej bezsensownej funkcji ?

0
kq napisał(a):

Tu nie chodzi o to, że ścieżka może być w relacji do katalogu scope? Jak podajecie bezwzględną to nic dziwnego że jest to samo.

Racja!
Jest jeszcze ciekawiej, bo wszystko zależy od tego którego konstruktora się użyje. Trzeba się dobrze wczytać który czego używa i co ignoruje...

Okazuje się, że jeśli nie poda się formatu w konstruktorze to wybierany jest QSettings::NativeFormat.
A setDefaultFormat ma rację bytu jedynie w przypadku użycia domyślnego konstruktora QSettings::QSettings(QObject* parent = nullptr).

Faktycznie trochę tu zakręcili.

0

@tajny_agent: - podpowiesz co jest lepsze od ini ?
@kq - masz rację aby używać angielskiej terminologii, zrobiłem jak mówiłeś i mam w związku z tym jedno pytanie.

Po użyciu angielskiej terminologii nie mam już krzaków

[IP_Settings]
IP_addr=192.168.0.1

[User_name]
User=User Żółąźć

ale po prawej stronie znaku "=" mogę używać polskich znaków, znaków specjalnych i nie mam żadnych krzaków. Jak to można wyjaśnić ?

0

Klucze i dane najwyraźniej są traktowane inaczej. Z tego co pamiętam Qt narzuca tutaj swój własny sposób serializacji nietypowych danych, o czym przekonasz się jak spróbujesz serializować QVariant albo QByteArray

0

Mam jeszcze pytanie, bardziej mi chodzi o ideę czy dobrze projektuję rozwiązanie jeżeli nie, to może podsuniecie mi pomysł na rozwiązanie.

Moje założenie jest takie, aby do tego dorobić otoczkę w postaci GUI które będzie zawierało kilka opcji do uzupełnienia/wybrania przez użytkownika.

Napisałem poniższy kod (na razie jest to bardziej idea), który zapisuje ustawienia w pliku INI. Wpadłem na pomysł, że jeżeli user przy pierwszym uruchomieniu programu ustawi wszystkie opcje i je zapisze, to stworzy mu się plik z ustawieniami. No dobra, to jest proste ale co jeśli użytkownik znowu odpali okno z ustawieniami i zmieni choćby jedną rzecz i potem to wszystko zapisze ?

Wpadłem na pomysł, aby ustawienia z pliku INI załadować do obiektu typu QMap i potem jak użytkownik coś zmieni, to do pliku zrzuci się całość z QMap ale z uwzględnieniem tej jednej opcji która została zmieniona. Poniżej pokazuję jedno z rozwiązań i pytanie jest takie czy dobrze myślę ? Czy może jest lepszy sposób ?

int main(void)
{
    QHostAddress ip;
    ip.setAddress("192.168.0.1");

    QStringList strList;
    QList <QVariant> list;
    QVariant var;

    QCoreApplication::setOrganizationName("test");

    QSettings setting("/home/user/Projekty-Qt/konsolówki/tylko-konsolwe/konsolowe-Debug/test.ini",QSettings::IniFormat);

    setting.setIniCodec("UTF-8");

//przykładowe dane które sobie user zapisał
    setting.beginGroup("IP_Settings"); 
    setting.setValue("IP_addr",ip.toString());
    setting.endGroup();

    setting.beginGroup("User_name");
    setting.setValue("User","Test Żąłóźćł");
    setting.endGroup();

//tworzę mapę do pobrania wartości aby móc przeprowadzać na nich jakieś czynności
    QMap <QVariant, QVariant> maps;

    strList << setting.allKeys(); //pobieram jakie są klucze

    for(int i=0; i<strList.size(); ++i){
//pobrane klucze zapisuję do obiektu QMap razem z ich wartościami
        maps[strList[i]] = setting.value(strList[i]).toString();
    }

    qDebug()<<"klucze"<<maps.keys(); //upewniam się czy klucze się dodały do QMap

    for(int i=0; i<maps.size(); ++i){
        qDebug()<<"wartosci"<<maps.values(strList[i]);

//Wybieram wszystkie wartości "nie klucze" i zapisuję je do obiektu QList 
//w celu dalszej obróbki
        list << maps.values(strList[i]);
    }

    var = list.value(0); //wybieram konkretną wartość i user może ją modyfikować
    qDebug()<< var.toString();
}

0

A po co mapa jak jest QSettings? Tak poza tym, pomysł ok.

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