Getting Started with Qt/sl

From Qt Wiki
Revision as of 16:53, 18 August 2015 by AutoSpider (talk | contribs) (Convert ExpressionEngine section headers)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.

Pričetek programiranja s Qt-om

Dobrodošli v svetu Qt-a – ogrodja za grafično programiranje za več platform. V tem začetnem vodiču se boste skozi implementacijo preprostega urejevalnika besedil naučili osnov Qt-a. Po zaključku branja tega vodiča boste pripravljeni, da se poglobite v branje pregledov tehnologij in dokumentacije programskega vmesnika ter tako najdete podatke, ki jih potrebujete za razvoj svoje aplikacije.

Pozdravljen Urejevalnik

V prvem primeru preprosto ustvarimo in prikažemo polje za urejanje besedila, ki se nahaja v oknu na namizju. To predstavlja najpreprostejši možni program Qt z grafičnim uporabniškim vmesnikom.

p=. Zaslonski posnetek urejevalnika

Tukaj je koda:

#include <QApplication>
#include <QTextEdit>

int main(int argv, char *'''args)
{
 QApplication app(argv, args);

 QTextEdit textEdit;
 textEdit.show();

 return app.exec();
}

Pa se sprehodimo po vsaki vrstici kode. V prvih dveh vrsticah vstavimo datoteki z glavo za razreda QApplication in QTextEdit, ki ju potrebujemo za ta primer. Vsi razredi v Qt imajo datoteko z glavo, ki ima enako ime kot ustrezen razred.

V 6. vrstici ustvarimo objekt razreda QApplication. Ta objekt upravlja z viri za aplikacijo in je potreben za delovanje kateregakoli programa Qt, ki ima grafični uporabniški vmesnik. Parametra argv in args sta potrebna, ker Qt sprejme nekaj argumentov iz ukazne vrstice.

V 8. vrstici ustvarimo objekt razreda QTextEdit. Polje za urejanje besedila je v grafičnem uporabniškem vmesniku viden element. V Qt-u take elemente imenujemo gradniki. Primeri drugih gradnikov so drsniki, oznake in gumbi. Gradnik je lahko tudi vsebnik za druge gradnike. Tako je na primer pogovorno okno ali pa glavno okno programa.

V 9. vrstici polje za urejanje besedila prikažemo na zaslonu in sicer v svojem oknu. Ker gradniki služijo tudi kot vsebniki (npr. QMainWindow, ki vsebuje orodjarne, menije, vrstico stanja in druge gradnike), je posamezen gradnik moč prikazati v svojem oknu. Gradniki privzeto niso vidni. S klicem funkcije show() postane gradnik viden.

V 11. vrstici zaženemo dogodkovno zanko objekta app, ki je razreda QApplication. Med tekom programa Qt se sprožajo dogodki, ki se pošiljajo gradnikom programa. Primera dogodkov sta pritisk na gumb miške in pritisk tipke. Ko v gradnik polja za urejanje besedila tipkate besedilo, le-ta prejme dogodke pritiskov tipk in se odzove z izrisom natipkanega besedila.

Da zaženete program, odprite ukazno vrstico in se postavite v mapo, ki vsebuje datoteko.cpp z izvorno kodo programa. Naslednji ukazi zgradijo program:

qmake -project
qmake
make

Po tem bo v mapi ustvarjena izvršljiva datoteka (v Windows morate morda namesto make uporabiti nmake, izvršljiva datoteka pa bo v mapi debug ali release). qmake je Qt-ovo orodje za gradnjo, ki kot vhod sprejme nastavitveno datoteko (s končnico .pro). qmake le-to ustvari za nas,če mu podamo možnost -project. Pisanje lastnih nastavitvenih datotek si bomo ogledali kasneje.

Naučite se več

|. Tema|. Tu| |Gradniki in geometrija oken|Window and Dialog Widgets |Dogodki in ravnanje z dogodki|The Event System


Dodajanje gumba Končaj

V pravi aplikaciji boste običajno potrebovali več kot en gradnik. Sedaj bomo pod polje za urejanje besedila dodali gumb razreda QPushButton. Ko uporabnik pritisne (klikne z miško) na gumb, se bo program končal.

p=. Urejevalnik s gumbom Končaj

Pa si oglejmo kodo:

#include <QtGui>

int main(int argv, char'''*args)
{
 QApplication app(argv, args);

QTextEdit textEdit;
 QPushButton quitButton("Končaj");

QObject::connect(&quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));

QVBoxLayout layout;
 layout.addWidget(&textEdit);
 layout.addWidget(&quitButton);

QWidget window;
 window.setLayout(&layout);

window.show();

return app.exec();
}

V 1. vrstici vstavimo QtGui, ki vsebuje vse Qt-ove razrede za grafični uporabniški vmesnik.

V 10. vrstici uporabimo Qt-ov mehanizem signalov in rež, s čimer omogočimo da se ob pritisku gumba Končaj aplikacija konča. Reža je funkcija, ki jo lahko prek njenega imena (kot literalenega niza) sprožimo med izvajanjem. Signal je funkcija, ki bo ob klicu sprožila reže, ki so registrirane pri njej. To imenujemo povezovanje reže s signalom in oddajanje signala.

Funkcija quit() je reža razreda QApplication, ki konča aplikacijo. Funkcija clicked() je signal, ki je del razreda QPushButton in se odda, ko je gumb pritisnjen. Statična funkcija QObject::connect() poskrbi za povezavo reže s signalom. SIGNAL () in SLOT() sta dva nakra, ki sprejmeta podpisa funkcij signala in reže, ki bosta povezana. Podati moramo tudi kazalca na objekta, ki bosta poslala in prejela signal.

V 12. vrstici ustvarimo razpored razreda QVBoxLayout. Kot smo že omenili, lahko gradniki vsebujejo druge gradnike. Omejitve (položaj in velikost) vsebovanih gradnikov je moč nastaviti neposredno, vendar je običajno preprosteje uporabiti razpored. Razpored upravlja z omejitvami gradnikovih podgradnikov. QVBoxLayout podgradnike razporedi v stolpec.

V 13. in 14. vrstici urejevalno polje in gumb dodamo v razpored. V 17. razpored nastavimo na glavnem gradniku.

=== Naučite se več |. Tema|. Tu| |Signali in reže|Signals and Slots |Razporedi|Layout Management, Widgets and Layouts, Layout Examples |Gradniki, ki pridejo s Qt|Qt Widget Gallery, Widget Examples ===

Izdelava podrazreda QWidget

Morda bi želeli, da se, ko uporabnik želi končati program, prikaže pogovorno okno, ki ga vpraša, če to res želi storiti. V tem primeru bomo izdelali podrazred razreda QWidget in dodali režo, ki jo bomo povezali z gumbom Končaj.

p=. Urejevalnik z dedovanjem od QWidget

Pa si oglejmo kodo:

class Notepad : public QWidget
{
 Q_OBJECT

public:
 Notepad();

private slots:
 void quit();

private:
 QTextEdit *textEdit;
 QPushButton *quitButton;
};

Macro Q_OBJECT mora biti v definiciji razreda prvi in določa, da je naš razred QObject (seveda mora tudi dedovati od QObject). QObject običajnemu razredu C++ doda množico zmožnosti. Na primer, v času izvajanja lahko poizvedujemo po imenu razreda in imenih rež. Poizvedovati je možno tudi po tipih parametrov reže in jo izvesti.

V 13. vrstici deklariramo režo quit(). To je s pomočjo makra slots preprosto. Režo quit() lahko sedaj povežemo s signali, ki imajo ustrezen podpis (vsak signal, ki ne potrebuje nobenega parametra).

Namesto da bi postavili grafični uporabniški vmesnik in povezali režo v funkciji main(), uporabimo konstruktor razreda Notepad.

 Notepad::Notepad()
 {
 textEdit = new QTextEdit;
 quitButton = new QPushButton(tr("Končaj"));

connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));

QVBoxLayout '''layout = new QVBoxLayout;
 layout->addWidget(textEdit);
 layout->addWidget(quitButton);

 setLayout(layout);

 setWindowTitle(tr("Urejevalnik"));
 }

Kot smo videli v definiciji razreda, uporabljamo kazalce do naših QObject (textEdit in quitButton). Kot splošno pravilo: QObject naj bi vedno ustvarjali na kopici in jih nikoli kopirali.

Sedaj okoli uporabniku vidnih nizov uporabimo funkcijo tr(). Ta funkcija je potrebna, če želite svoj program ponuditi v več jezikih (npr. še v angleščini in kitajščini). Tu se ne bomo spuščali v podrobnosti, lahko pa sledite povezavi Qt Linguist v tabeli Naučite se več.

Ustvaritev datoke .pro

Za ta primer bomo napisali datoteko .pro po meri in ne bomo uporabili qmake-ove možnosti -project.

 HEADERS = notepad.h
 SOURCES = notepad.cpp  main.cpp

Naslednji ukazi zgradijo primer:

 qmake
 make

Naučite se več:

|. Tema|. Tu| |tr() in internacionalizacija|Qt Linguist Manual, Writing Source Code for Translation, Hello tr() Example, Internationalization with Qt |QObject in Qt-ov objektni model (to je osnovno za razumevanje Qt-a)|Object Model |qmake in Qt-ov sistem za gradnjo|qmake Manual


Uporaba QMainWindow

Za veliko programov bo koristno, če uporabite QMainWindow, ki ima svoj lasten razpored, v katerega lahko dodate menijsko vrstico, podokna, orodjarne in vrstico stanja. QMainWindow ima osrednje področje, ki ga lahko zapolnjuje katerikoli gradnik. V našem primeru bo to naše urejevalno polje.

p=. Urejevalnik s QMainWindow

Pa si oglejmo novo definicijo razreda Notepad:

 #include <QtGui>

 class Notepad : public QMainWindow
 {
 Q_OBJECT

 public:
 Notepad();

 private slots:
 void open();
 void save();
 void quit();

 private:
 QTextEdit *textEdit;

 QAction *openAction;
 QAction *saveAction;
 QAction *exitAction;

 QMenu '''fileMenu;
 };

Dodamo dve novi reži za odpiranje in shranjevanje dokumenta. Reži bomo implementirali v naslednjem razdelku.

Pogosto se zgodi, da želimo v glavnem oknu isto režo izvesti iz več gradnikov. Primera sta menijski vnos in gumb orodjarne. Da bi bilo to čim lažje, Qt ponuja razred QAction, ki ga lahko podamo več gradnikom in je povezan z režo. Na primer, QMenu in QToolBar lahko menijske vnose in gumbe orodjarne ustvarita iz istih QAction. Kmalu bomo videli, kako to deluje.

Kot prej bomo za postavitev uporabniškega vmesnika uporabili konstruktor Notepad-a

 Notepad::Notepad()
 {
 saveAction = new QAction(tr("&Odpri …"), this);
 saveAction = new QAction(tr("&Shrani"), this);
 exitAction = new QAction(tr("Konča&j"), this);

 connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
 connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));
 connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));

 fileMenu = menuBar()->addMenu(tr("&Datoteka"));
 fileMenu->addAction(openAction);
 fileMenu->addAction(saveAction);
 fileMenu->addSeparator();
 fileMenu->addAction(exitAction);

 textEdit = new QTextEdit;
 setCentralWidget(textEdit);

 setWindowTitle(tr("Urejevalnik"));
 }

QAction ustvarimo z besedilom, ki se pojavi na gradnikih, za katere uporabimo QAction-e (v našem primeru so to menijski vnosi). Če bi jih želeli uporabiti tudi za orodjarne, bi dejanjem lahko dodali tudi ikone.

Ko sedaj uporabnik klikne na menijski vnos, bo vnos sprožil dejanje in izvedla se bo ustrezna reža.

Naučite se več:

|. Tema|. Tu| |Glavna okna in razredi glavnih oken|Application Main Window, Main Window Examples |Program z vmesnikom z več dokumenti|QMdiArea, MDI Example


Odpiranje in shranjevanje

V tem primeru bomo implementirali delovanje rež open() in save(), ki smo ju dodali v prejšnjem primeru.

p=. Pogovorno okno za odpiranje datotek

Zaželi bomo z režo open():

 QString fileName = QFileDialog::getOpenFileName(this, tr("Odpiranje datoteke"), "",
 tr("Besedilne datoteke ('''.txt);;Datoteke C++ ('''.cpp'''.h)"));

 if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::ReadOnly)) {
 QMessageBox::critical(this, tr("Napaka"),
 tr("Datoteke ni bilo moč odpreti"));
 return;
 }
 QString contents = file.readAll().constData();
 textEdit->setPlainText(contents);
 file.close();
 }

V prvem koraku uporabnika vprašamo po imenu datoteke, ki bo odprta. Qt prihaja s QFileDialog, ki je pogovorno okno, iz katerega lahko uporabnik izbere datoteko. Gornja slika prikazuje pogovorno okno na namizju KDE Plasma na Linuxu. Statična funkcija getOpenFileName() prikaže pogovorno okno, ki je vedno nad vsemi programovimi okni in ne vrne nič, dokler uporabnik ne izbere datoteke. Pogovorno okno vrne polno pot do izbrane datoteke ali pa prazen niz, če je uporabnik preklical pogovorno okno.

Če imamo ime datoteke, datoteko poskušamo odpreti z open(), ki vrne true, če je bilo datoteko moč odpreti. V podrobnosti rokovanja z napakami se tu ne bomo spuščali, lahko pa sledite povezavam v tabeli Naučite se več. Če datoteke ni bilo moč odpreti, uporabimo QMessageBox in prikažemo pogovorno okno s sporočilom o napaki (za nadaljnje podrobnosti si oglejte opis QMessageBox).

Dejanjsko branje podatkov je zahvaljujoč funkciji readAll() preprosto. Funkcija vse podatke iz datoteke vrne v objektu QByteArray. Funkcija constData() vse podatke vrne kot const char, za kar ima QString konstruktor. Vsebino potem lahko prikažemo v urejevalnem polju. Nazadnje še zapremo datoteko s klicem funkcije close() in tako opisovalnik datoteke vrnemo operacijskemu sistemu.

Nadaljujmo še z režo save():

 QString fileName = QFileDialog::getSaveFileName(this, tr("Shranjevanje datoteke"), "",
 tr("Besedilne datoteke ('''.txt);;Datoteke C++ ('''.cpp '''.h)"));

 if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::WriteOnly)) {
 // sporočilo o napaki
 } else {
 QTextStream stream(&file);
 stream << textEdit->toPlainText();
 stream.flush();
 file.close();
 }
 }

Za zapisovanje vsebine urejevalnega polja v datoteko uporabimo razred QTextStream, ki ovija objekt QFile. Besedilni tok lahko nize QString zapisuje neposredno v datoteko. QFile s funkcijo write() iz QIODevice sprejema le surove podatke (char).

=== Naučite se več |. Tema|. Tu| |Datoteke in V/I naprave|QFile, QIODevice ===