Sziasztok!
Adott egy kis alkalmazás, Qt 4.7.0-n alapul, és ezt szeretném lefordítani Linux és Windows (XP) alatt is.
Linux és Windows alatt is hibátlanul lefordul a kód, de az alábbi kódrészletre Win alatt feldobja az msgBox-ot (nem találja a fájlt):
QFile allomany("./varosok.dat"); // Bemeneti állomány (varosok.dat)
if (!allomany.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox msgBox; // Üzenetablak
msgBox.setText("IO Hiba"); // Üzenet beállítása
msgBox.setInformativeText("A varosok.dat allomany nem talalhato."); // Magyarázat beállítása
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.exec();
} else {
QTextStream be(&allomany);
. . .
A kezelendő fájlt bemásoltam a (projekt.neve)-build-desktop alá, és kínomban már a forráskód mellé is, de semmi hatása.
Qt Creator ugyanaz a verzió mindkét OS alatt.
Mi lehet a gyógyír?
(Zárójelben jegyzem meg: a windows által kezelt partíción nem volt elég hely, így egy külső meghajtóra telepítettem a Qt Creator-t, és build után a projektnek létrehozott egy D:\home\richard\... (ez a Linux-on használt felh. nevem, Winen más van) könyvtárszerkezetet, és oda került a lefordított kód.)
szerk.: Cím módosítva
- 4618 megtekintés
Hozzászólások
Kevés doksi kotorgálás után javaslom az error metódus kipróbálását:
- A hozzászóláshoz be kell jelentkezni
Még csak most ismerkedem a Qt-vel, szép lassan haladok a bonyolultabb megoldások felé.
Be fogom építeni a kódba, köszi.
- A hozzászóláshoz be kell jelentkezni
Próbáld ki, ha
QFile allomany("./varosok.dat");
helyett ezt írod:
QFile allomany("varosok.dat");
Próba szerencse.
---------------------------
Oszt jónapot!
- A hozzászóláshoz be kell jelentkezni
Arra én is gondoltam, de ugyanaz volt az eredmény
- A hozzászóláshoz be kell jelentkezni
Kipróbálni most nem tudom, mert nincs winen Qtém, de ez nekem nagyon gyanús:
QFile allomany("./varosok.dat");
A "./" nekem elég unixos, próbálj ki egy windows-os abszolút útvonalat, pl: "d:/varosok.dat". Ha ez működik, akkor vagy QDir::current ()-el lehet kinyerni a program könyvtárát vagy csinálsz a kódban egy OS specifikus változatot az abszolút névvel.
- A hozzászóláshoz be kell jelentkezni
Ez is bekerül a kódba, köszi.
"D:\varosok.dat"-ot kipróbálom máris.
- A hozzászóláshoz be kell jelentkezni
Esetleg "d:\\varosok.dat"?
--
Auto correct can go straight to He'll.
- A hozzászóláshoz be kell jelentkezni
Ezután is van értelme megnézni? (csak mert Ubuntu alatt dolgozok, és egy-egy teszthez reboot kell)
- A hozzászóláshoz be kell jelentkezni
Nos, az alábbi "fejlemények" vannak:
Csak most vettem észre, hogy Warning keletkezik a fordítás során: "Qmake does not support build directores below the source directory." Nem tudom ez számít-e (ez csak Winen jelentkezik)
Átírtam a fájl elérési útját relatívról teljesre, biztos ami biztos, és a statikus hibaüzenet helyett errorString() segítségével állapítom meg a hiba okát. Futtatáskor ezt dobja: "Az eszköz nem áll készen." Az állomány nincs megnyitva más programban, nem tudom hogy mire gondol.
Ezekkel mit lehet kezdeni?
- A hozzászóláshoz be kell jelentkezni
Ez a warning tök lényegtelen, nincs köze a problémádhoz. A D:\varosok.dat lehet hogy nem jó, jobbra per jel elvileg a Qtén belül a szabvány, akárhol is dolgozol, tehát D:/varosok.dat. Bár nem hiszem, hogy ez gondot okoz. Ennek elég egyszerűen kellene működnie. Ha lesz egy kis időm délután feldobok winre egy Qtét és megrpóbálom reprodukálni a dolgot.
- A hozzászóláshoz be kell jelentkezni
Itt a teljes forrás (az egész Qt project), gondolom így egyszerűbb:
http://dl.dropbox.com/u/14078600/Neptun-Qt.tar.bz2
Átírtam a fájl nevére vonatkozó részt erre:
QDir konyvtar(QDir::current()); //Aktualis konyvtar megallapitasa
QString fajl=konyvtar.absoluteFilePath("varosok.dat"); // varosok.dat abszolUt eleresi Utjanak megallapitasa
QFile allomany(fajl); // Bemeneti allomany (varosok.dat);
Ettől már elviekben helyesen kellene megállapítania az elérési útvonalat az összes rendszeren. Linux alatt működik, Winen változatlan a dolog.
- A hozzászóláshoz be kell jelentkezni
Hmm ez a windowsos fájlnévkezelés most hirtelen nem világos, de így működik nálam:
QString fajl = "C:\\varosok.dat";
QFile allomany(fajl);
Megjegyzem, hogy a fájlt megnyitja minden alkalommal amikor a ComboBoxhoz nyúlsz, ami nem túl frankó dolog.
Na mindjárt megnézem, hogy ennek a QDir dolognak hogyan kellene működnie :)
- A hozzászóláshoz be kell jelentkezni
No a megoldásoddal nincs baj, csak annyi hogy itt keresi a fájlt:
"C:/home/richard/SzoftFejlTech/Neptun-Qt/Neptun-build-desktop/varosok.dat"
A projekt beállításaiban meg tudod jelölni mi legyen a build könyvtár és akkor ott fog nézegetni. De vannak frappánsabb megoldások is, nézd meg a QSettings dolgot, platform függetlenül tudsz elrakni mindenféle infókat a programodról.
- A hozzászóláshoz be kell jelentkezni
Köszönöm, azt megnézem.
Nekem a könyvtárszerkezetet a D-re hozta létre, oda is kerül az exe, és bemásoltam oda a fájlt, de nem működött. Akkor megnézem mégegyszer, hogy pontosan oda másolom-e.
- A hozzászóláshoz be kell jelentkezni
Nem az exe könyvtárába keres, hanem egyel feljebb, a build könyvtárba!
Utánna olvastam közben, a QDir::absoluteFilePath(QString) nem ellenőrzi, hogy a megadott fájl létezik e (varosok.dat). "Returns the absolute path name of a file in the directory. Does not check if the file actually exists in the directory;"
Azaz a futási könyvtárat kapod szerintem, ami a fentebb írt, ez az oka a dolognak.
- A hozzászóláshoz be kell jelentkezni
Ja, értem. Rebootolok, és kipróbálom, köszi.
- A hozzászóláshoz be kell jelentkezni
Megjegyzem, hogy a fájlt megnyitja minden alkalommal amikor a ComboBoxhoz nyúlsz, ami nem túl frankó dolog.
Igen, tisztában vagyok vele. Sajnos nem találtam rá jobb megoldást, hogy egy második form által módosított varosok.dat-ot újra beolvastathassam vele. Az eredeti megoldáskor csak akkor olvasta be a fájlt, mikor indult az alkalmazás, így a lista bővítése után újra kellett indítani a programot.
VC++-ban ez szépen meg lett oldva:
if (UjVaros->ShowDialog(this)==System::Windows::Forms::DialogResult::OK) // "Település felvétele" form megjelenítése
{
try // Új település rögzítése a comboboxokban és a be/kimeneti állományban
{
KiIr=File::AppendText("varos.txt");
KiIr->WriteLine(UjVaros->textUjTelepules->Text);
KiIr->Flush();
comboLakhely->BeginUpdate();
comboLakhely->Items->Add(UjVaros->textUjTelepules->Text);
comboLakhely->EndUpdate();
comboSzulHely->BeginUpdate();
comboSzulHely->Items->Add(UjVaros->textUjTelepules->Text);
comboSzulHely->EndUpdate();
}
catch (Exception^ e)
{
MessageBox::Show(e->Message);
}
finally
{
if(KiIr)
KiIr->Close();
}
}
viszont Qt megfelelőjére még nem jöttem rá. (Ugyanez a project megy VC++-ban, amit szemináriumon fejlesztgetünk, csak én szeretnék egy platformfüggetlen megoldást "tanulás" címén.)
- A hozzászóláshoz be kell jelentkezni
Ha jól értem a problémát ennél pedig nem lesz bonyolultabb.
... megnyomják az új város gombot ...
ujvarosdialog->exec();
comboLakhely->clear();
comboSzulHely->clear();
... fájl beolvas combobox feltölt ...
Gyakorlásnak megteszi, mondjuk a combo boxok ürítése elött amíg nincs beolvasva a fájl illik őket letiltani vagy valami, hogy ne legyen az, hogy véletlen akkor kattint a felhasználó amikor még nincsenek feltöltve.
- A hozzászóláshoz be kell jelentkezni
Valóban, a tiltás nem rossz.
A fájlos dolog amúgy tényleg működik, köszi.
szerk.: A feltöltés is rendben így.
- A hozzászóláshoz be kell jelentkezni
Egyetlen nagy hátránya, ha tényleg minden város benne van, akkor elég nagy, akár több másodperces frissítési periódusok is lehetnek benne. Amit nem fog az "ügyfél" nagyon szeretni.
- A hozzászóláshoz be kell jelentkezni
Nincs ügyfél, ez csak ilyen gyakorló feladat. A későbbiekben meg nem is fájlból megy a dolog, hanem adatbázisból.
- A hozzászóláshoz be kell jelentkezni
Pár gondolat ...
1. file elérés: nem jó, ha OS specifikus klienseket csinálsz. Helyette sokkal egyszerűbb, ha csinálsz valamilyen QString getDataPath() függvényt, ami mindig az OS-től függően veszi fel az adatkönyvtárad elérhetőségét. Pl:
QFile f;
f.setName(getDataPath()+"varosok.dat");
2. A többszörös GUI felület + fájlba mentés nagyon nem elegáns. Szerintem amit érdemes lenne használnod, az a model-view architektúra. Ezzel éket versz a GUI elemek és az adatforrások közé. Azon a szinten a az adatok szinkronizálása megoldott. Illetve később, ha a modellben változás van (pl adatbázisból akaros venni a városokat) akkor elegendő a modellt módosítanod, a már meglévő GUI részhez nem kell nyúlnod (nem is fogja tudni, honnan jön az adat).
Nem mellesleg, ha a model-view-t később egy proxy-val kiegészíted, akkor az adatokat tudod szűrni, sorbarendezni, stb. (Pl a kombóban elkezded beírni az első pár betűt és csak azok a városok maradnak benn, amelyek azzal a kombinációval kezdődnek.
- A hozzászóláshoz be kell jelentkezni
"jobbra per jel elvileg a Qtén belül a szabvány"
Erre is van megoldás:
http://hup.hu/node/93766#comment-1132721
- A hozzászóláshoz be kell jelentkezni
QtCreatorban az oldalsáv -> Projects -> Run settingsnél a working directory oda mutat ahol a fájlod meg a binárisod van?
- A hozzászóláshoz be kell jelentkezni
Mostmár igen, nem láttam hogy van ilyen beállítás, ezért jött létre a D: alatt a Linuxos home-om "klónja".
- A hozzászóláshoz be kell jelentkezni
Kis kiegészítés még:
- az UI classokat általában statikusan szokás megadni. Nem kell new-t hívni a member konstruktorban és delete-t a destruktorban.
- egy nyelvet használj: nem poén, hogy a föggvény ::add_city(), de benne már magyarul vannak a nevek.
- a kimenet.operator << részt nem teljesen értem. Miért kell oda az operator?
- túl sok a komment. Nem kell minden sort a végén kommentelni. Aki érti, az úgyis a forráskódot olvassa el és megérti, hogy miről szól az. Mindenki mást csak feltart a komment. Ha nagyon nem egyértelmű, hogy az adott rész mit csinál, akkor a függvény előtt vagy közben, pár sorban foglald össze a dolgot.
-
QTextStream kimenet(&allomany);
// ertekek kiirasa XML szeruen adatok.dat-ba
kimenet.operator <<("\t[textNev]\n"+ui->textNev->text()+"\n");
kimenet.operator <<("\t[textAzonosito]\n"+ui->textAzonosito->text()+"\n");
kimenet.operator <<("\t[textJelszo]\n"+ui->textJelszo->text()+"\n");
Ehhez 3 megjegyzés társul:
- ha még nem láttál XML-t, akkor ne nagyon hivatkozzál a forráskódban rá. Ennek semmi köze az XML-hez, csak frusztrációt okoz, hogy hol kellene ebbe belelátni az XML-t. Ne használj buzzwordoket, csak hogy profibbnak tűnjön.
- Ha XML-t akarsz használni, akkor a QDomDocument és a környéke a barátod.
- érdemesebb lenne itt a CSV felé menni, valamilyen "PARAM=VALUE" mentén. Első egyenlőségjelig keresel
A paraméterfájl olvasásához érdemes lenne egy QHash-et declarálnod valahol.
Így nem kellene minden egyes paramétert implementálnod a beolvasó függvényben, csak ott, ahol szükséged van rá. Pl:
QHash hash
void Class:load()
{
végigiterálsz a fájlon
minden egyes sornál megkeresed az első egyenlőségjelet
szétbontod a sort kulcsra és értékre az egyenlőségjel pozíciója alapján
berakod a hashba: hash.insert(key, value);
}
utána pl a jelszót kinyerheted a
hash.value("password", "defaultpassword").toString() hívással. Ha volt ilyen paramétered a fájlban, akkor azt adja vissza, ha nem, akkor a "defaultpassword" stringet.
Így írhatsz egy generic betöltő és paraméter mentő algoritmust, aminek nem kell tudni a paraméterekről. a paramétereket bárhol felhasználhatod, ha a hash függvényt az egyes osztályoknak átadod.
Ha nem akarsz az átadással molyolni, akkor kell egy Singleton pattern alapján létrehozott osztály, aminek egy instance-ja tartalmazza a hasht. Onnantól kezdve a program bármely pontján ez elérhető lesz.
Természetesen az adott implementáció feladatfüggő és lehetnek jobb megoldások is. Viszont mivel most kezded az ezzel való ismerkedés, a fentiek pár támpontot jelentenek a továbbhaladásra. Guglizz bátran ezekkel kapcsolatosan.
- A hozzászóláshoz be kell jelentkezni
Köszi a támpontokat.
kimenet.operator << esetén a .operator-t a QT Creator egészítette ki nekem ilyenre, valamiért a sima kimenet << "szöveg"; nem volt jó neki.
Azt az XML-es bejegyzést órai anyagból vettem át, ott a tanár hivatkozott rá így (maga a Qt projekt egy VC++ 2010 projekt alapján készül, ugyanazokat a feladatokat lehető leghasonlóbban megoldva). Magát a célt nem látjuk, mert a tanár óráról órára közöl egy-egy megoldandó részfeladatot, és így szép lassan épül a dolog, usecase diagram is csak a feladat megoldása _után_ készült. Mivel úgymond elsődleges projekt most nálam a Qt megismerése, valószínűleg elviszem más irányba a dolgot, esetleg tök más feladatot találok ki magamnak, mert haladnék az anyaggal, de így, hogy hétről hétre 2 munkaórányi feladat születik elég lassú.
Az említettekből adódóan persze sok dolgot lehetne sokkal szebben, elegánsabban megoldani, de mivel a VC++-ben így oldottuk meg, itt is erre törekedtem. Azóta pl. 1 form van, és InputDialog kéri a felhasználótól a település nevét, mert ezt könnyebb megoldásnak láttam, meg minek kínlódjak én vele.
Kommentek azért vannak ilyen sűrűn, mert így könnyebben átláthatom a saját kódom holnap, amikor már nem biztos, hogy emlékszem mi miért, de legfőképp hogyan volt. Mint írtad: "Aki érti, az úgyis a forráskódot olvassa el és megérti, hogy miről szól az.", csakhogy előfordulhat, hogy pont én nem értem meg a kódot, mert mondjuk egy hete készítettem, és azóta rengeteg dolgot néztem már Qt ügyben. Zavarni nem bánom, ha mást zavar, engem segít a tanulásban/gyakorlásban, és ennek a kódnak ez a célja.
A konstruktor/destruktor függvényeket a Qt Creator generálta, nem saját.
Az egységes nyelve majd igyekszem figyelni.
- A hozzászóláshoz be kell jelentkezni
Azt esetleg nem tudja még valaki, hogy a stringekben található ékezetes karaktereket hogyan lehetne szépen megjeleníttetni?
Pl. a
QString szoveg=QInputDialog::getText(this,tr("Új település felvétele"),tr("Település neve:"),QLineEdit::Normal,"Település neve", &ok);
hatására az InputDialog-ban az ékezetes karakterek helyére mindenféle "érdekes" karakter kerül.
- A hozzászóláshoz be kell jelentkezni
Általában UTF8-ban kódolom a forrást, ha te is így teszel, ezt kell beszúrni a main elejefelé és jó lesz a megjelenés:
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
BTW a kollégák meglátásaiban bőven van igazság, ha komolyan akarsz Qtét tanulni, akkor szerintem érdemes lenne valahogy a Qt módszereket és megoldásokat magadévá tenned. Egy VC projekt átírása helyett, néhány lépésről lépésre tutorialt végig csinálni, vannak nagyon jók.
- A hozzászóláshoz be kell jelentkezni
Persze, meg is hajoltam ajánlásuk előtt, amiket ajánlottak elkezdtem áttanulmányozni. Az ismerkedést pedig úgy képzeltem el, hogy adott ez az alap feladat, VC++-ból átvett eljárásokkal, és szép fokozatosan a megoldásokat lecserélem a Qt szemléletének megfelelően.
Az UTF8-at köszi.
- A hozzászóláshoz be kell jelentkezni