Pagina principala
Informatii
Internationalizarea
pROgrame KDE/Qt
Download
Documentatii
Despre LKR
Contact
Resurse
Harta site-ului

Tutorial programare KDE 3


   Antonio Larrosa
   14 martie 2002

P7: Inainte si inapoi

In acest exemplu sintem pregatiti sa marim functionalitatea lui P5 in ideea de a invata cum sa folosim citeva clase standard KDE care ar trebui folosite in aproape toate aplicatiile.


#include <kapp.h>
#include "p7.h"

int main( int argc, char **argv )
{
  KApplication a( argc, argv, "p7" );

  MainWindow *mywindow=new MainWindow("Tutorial - p7");
  mywindow->resize( 300, 200 );

  a.setMainWidget( mywindow );
  mywindow->show();

  return a.exec();
}
main.cpp


#include <dcopobject.h>

class p7Iface : virtual public DCOPObject
{
   K_DCOP

k_dcop:
   virtual void setURL( QString s )=0;

};
p7Iface.h


#include "p7Iface.h"
#include <kmainwindow.h>
#include <kurl.h>
#include <kparts/browserextension.h>
#include <qvaluestack.h>

class QLineEdit;
class KHTMLPart;

class MainWindow : public KMainWindow, virtual public p7Iface
{
  Q_OBJECT
  public:
    MainWindow ( const char * titulo );
 
    virtual void setURL ( const QString url );
 
  public slots:
    void fileSetDefaultPage();
    void changeLocation();
    void bookLocation();
    void gotoPreviousPage();
    void openURLRequest(const KURL &url, const KParts::URLArgs &);
 
  private:
    QLineEdit *location;
    KHTMLPart *browser;
    QValueStack <QString> history;
};
p7.h


#include "p7.h"
#include <qvbox.h>
#include <qlineedit.h>
#include <dcopclient.h>
#include <kfiledialog.h>
#include <kapp.h>
#include <kmenubar.h>
#include <ktoolbar.h>
#include <klocale.h>
#include <kpopupmenu.h>
#include <khtml_part.h>
#include <kdebug.h>
#include <kconfig.h>
#include <kiconloader.h>
 
 

MainWindow::MainWindow(const char * name) : KMainWindow(0L, name),
					  DCOPObject("browser")
{
  setCaption("KDE Tutorial - p7");

  QPopupMenu * filemenu = new QPopupMenu;
  filemenu->insertItem( i18n( "&Set default page" ),
		this, SLOT( fileSetDefaultPage() ) );
  filemenu->insertItem(i18n("&Quit"), kapp, SLOT(quit()));
  QString about =
   i18n("p7 1.0\n\n"
   "(C) 1999-2002 Antonio Larrosa Jimenez\n"
   "larrosa@kde.org\t\tantlarr@supercable.es\n"
   "Malaga (Spain)\n\n"
   "Simple KDE Tutorial\n"
   "This tutorial comes with ABSOLUTELY NO WARRANTY \n"
   "This is free software, and you are welcome to redistribute it\n"
   "under certain conditions\n");
 
  QPopupMenu *helpmenu = helpMenu(about);
  KMenuBar * menu = menuBar();
  menu->insertItem( i18n( "&File" ), filemenu);
  menu->insertSeparator();
  menu->insertItem(i18n( "&Help" ), helpmenu);
 
  KToolBar *toolbar=new KToolBar(this);

  toolbar->insertButton(BarIcon("reload"), TOOLBAR_ID_ADDBOOKMARK,
                        SIGNAL(clicked(int)),this,
                        SLOT(bookLocation()),TRUE,
                        i18n("Add to Bookmarks"));
  toolbar->insertButton(BarIcon("back"), TOOLBAR_ID_BACK,
                        SIGNAL(clicked(int)),this,
                        SLOT(gotoPreviousPage()),
                        FALSE, i18n("Back to previous page"));
  toolbar->insertButton(BarIcon("exit"), TOOLBAR_ID_QUIT,
                        SIGNAL(clicked(int)),kapp,SLOT(quit()),
                        TRUE,
                        i18n("Quit the application"));
  addToolBar(toolbar);
 
  QVBox * vbox = new QVBox ( this );
 
  location = new QLineEdit ( vbox );
 
  KConfig *config=kapp->config();
  config->setGroup("Settings");
  location->setText( config->readEntry( "defaultPage",
		"http://localhost") );

  connect(location , SIGNAL( returnPressed() ),
          this, SLOT( changeLocation() ) );
 
  browser=new KHTMLPart( vbox );
  browser->openURL( location->text() );
 
  connect(browser->browserExtension(),
  SIGNAL(openURLRequest(const KURL &, const KParts::URLArgs &)),
  this,
  SLOT(openURLRequest(const KURL &, const KParts::URLArgs &)));

  setCentralWidget( vbox );
 
  DCOPClient *client = kapp->dcopClient();
  client->attach();
  client->registerAs("p7");
}
 
 
void MainWindow::changeLocation()
{
  history.push(browser->url().url());
  toolBar()->setItemEnabled(TOOLBAR_ID_BACK, TRUE);
  browser->openURL(location->text());
}
 
void MainWindow::setURL( QString url )
{
  location->setText( url );
  changeLocation();
}
 
void MainWindow::openURLRequest(const KURL &url,
                                const KParts::URLArgs &)
{
  setURL( url.url() );
}

void MainWindow::gotoPreviousPage()
{
  location->setText( history.pop() );
  if (history.isEmpty())
    toolBar()->setItemEnabled( TOOLBAR_ID_BACK, FALSE);
  browser->openURL( location->text() );
}

void MainWindow::bookLocation()
{
  DCOPClient *client=kapp->dcopClient();
  QByteArray params;
  QDataStream stream(params, IO_WriteOnly);
  stream << location->text();
  if (!client->send("p8-*", "bookmarkList", "add(QString)", params))
     kdDebug << "Error with DCOP\n";
}

void MainWindow::fileSetDefaultPage()
{
  KConfig *config=kapp->config();

  config->setGroup("Settings");
  config->writeEntry("defaultPage", browser->url().url());
}
p7.cpp

Primul lucru pe care il facem este sa adaugam interfata DCOP la P7 pentru a fi folosita de P8 (urmatoarea generatie de lista de semne de carte). Este asemanator cu P6 de aceea nu-l voi mai comenta.

#define TOOLBAR_ID_ADDBOOKMARK 1
#define TOOLBAR_ID_BACK 2
#define TOOLBAR_ID_QUIT 3

Sintem la inceputul fisierului p7.cpp. Aici definim citiva identificatori pentru butoanele barei de unelte. Asta nu este intotdeauna necesar. Puteti crea bare de unelte (toolbars) lasind clasa barei de unelte sa atribuie identificatori impliciti. Dar vom activa/dezactiva butoane de pe bara de unelte, asa ca este mai clar sa facem in felul acesta.

MainWindow::MainWindow(const char * name) : KMainWindow(0L, name),
            DCOPObject("browser")
{
  QPopupMenu * filemenu = new QPopupMenu;
  filemenu->insertItem( i18n( "&Set default page" ),
		this, SLOT( fileSetDefaultPage() ) );

Clasa MainWindow acum mosteneste p7Iface, asa ca trebuie sa apelam si constructorul DCOPObject. Vom numi obiectul browser. In meniul File mai adaugam un element pe care il vom folosi sa setam pagina actuala ca pagina implicita cind vom mai rula aplicatia. Astfel vom invata si cum sa salvam variabilele de configurare.

KToolBar *toolbar=new KToolBar(this);

Folosind clasa KToolBar vom crea o bara de unelte care va avea o infatisare standard cu un mic indicator de care se poate apuca si muta bara in afara ferestrei sau repozitiona in alta parte etc.

toolbar->insertButton(BarIcon("reload"),
          TOOLBAR_ID_ADDBOOKMARK,
          SIGNAL(clicked(int)),this,SLOT(bookLocation()),
          TRUE,
          i18n("Add to Bookmarks"));
toolbar->insertButton(BarIcon("back"), TOOLBAR_ID_BACK,
          SIGNAL(clicked(int)),this,SLOT(gotoPreviousPage()),
          FALSE, i18n("Back to previous page"));
toolbar->insertButton(BarIcon("exit"), TOOLBAR_ID_QUIT,
          SIGNAL(clicked(int)),kapp,SLOT(quit()),
          TRUE,
          i18n("Quit the application"));

O sa adaugam trei butoane. Primul il vom folosi in locul acelui buton mare (si urit) pe care l-am folosit in P5. Al doilea buton il vom folosi ca sa ne ducem la pagina precedenta si al treilea ca sa inchidem aplicatia. (Retineti: se recomanda sa nu se foloseasca un in bara de unelte un buton pentru terminarea aplicatiei. Ce facem noi nu este o aplicatie reala si de aceea vom omite acest avertisment serios).

BarIcon("reload") este o functie care cauta automat iconita reload (oriunde s-ar afla: $KDEDIR/share/toolbar sau $KDEDIR/share/apps/<appname>/toolbar) si intoarce un obiect valid QPixmap cu acea iconita.

Urmatorul parametru este identificatorul pe care o sa-l folosim mai tirziu pentru a ne referi la acest buton. Paramentrul al treilea este semnalul pe care il conectam la obiectul care il va primi, urmat de slotul care va fi apelat. Retineti ca nu intotdeauna trebuie sa dam un identificator valid. Putem sa folosim 0. Folosim identificatori pentru a activa/dezactiva un buton, asa cum vom face cu butonul back.

addToolBar(toolbar);

Am terminat de construit bara de unelte, asa ca o adaugam la widget-ul principal cu addToolBar. addToolBar nu urmeaza aceeasi logica ca setMenu, deoarece nu suntem obligati sa folosim o singura bara de unelte (ca in cazul meniurilor) de aceea nu setam, ci adaugam bara.

KConfig *config=kapp->config();
config->setGroup("Settings");
location->setText( config->readEntry( "defaultPage",
	"http://localhost") );

Stim deja ce este kapp dar nu am folosit pina acum metoda config(). Aceasta metoda va intoarce obiectul KConfig al aplicatiei. KConfig este folosit pentru a salva variabilele de configurare ale unei aplicatii. El salveaza automat inregistrarile cu informatii de configurare Ón fisierul de configurare al aplicatiei si le reincarca atunci cind aplicatia este rulata din nou.

O data ce avem obiectul de configurare, setam grupul activ in care lucram ca fiind Settings. Grupurile sunt folosite pentru a structura mai bine fisierele de configurare.

In cele din urma in loc sa folosim "http://localhost" ca pagina implicita, citim din fisierul de configurare. defaultPage este numele inregistrarii pe care vrem sa o citim, "http://localhost" este valoarea implicita care va fi intoarsa in cazul in care fisierul de configurare nu contine valoarea pentru defaultPage.

Puteti citi valori intregi cu KConfig::readNumEntry, valori de adevar cu KConfig::readBoolEntry etc.

DCOPClient *client = kapp->dcopClient();
client->attach();
client->registerAs("p7");

Atasam aplicatia la serverul DCOP si o inregistram ca p7, deoarece vrem ca P8 sa o poata apela sa seteze o pagina.

void MainWindow::setURL( QString url )
{
  location->setText( url );
  changeLocation();
}

Acest membru este folosit sa seteze legatura. Acum functia poate fi apelata de catre interfata DCOP sau cind utilizatorul da clic pe o legatura. Setam prima data textul pentru a afisa legatura si apelam functia changeLocation.

void MainWindow::changeLocation()
{
  history.push(browser->url());
  toolBar()->setItemEnabled(TOOLBAR_ID_BACK, TRUE);
  browser->openURL(location->text());
}

changeLocation (care este folosit si de semnalul enterPressed() al obiectului location) este folosit pentru a incarca o pagina noua atunci cind legatura este setata in bara de locatie. Am facut in asa fel pentru a implementa in P7 functia de istoric de navigare.

Observam ca am definit in P7 un obiect history de tipul QValueStack<QString>. QValueStack este o clasa Qt care implementeaza o stiva, folosind template ca tip de date. Diferenta intre QValueStack si QStack consta in faptul ca prima stocheaza valorile elementelor creind o copie a fiecarui element pe care il adaugati, in timp ce a doua doar salveaza pointeri la acele elemente. Trebuie sa aveti grija sa nu stergeti elementul cit timp mai este pe stiva.

Intrucit clasa QString partajeaza datele pentru toate copiile sirului de caractere pina cind este efectuata o modificare intr-una din ele, nu prezinta o problema sa efectuati copii ale legaturilor.

Acum obtinem bara de unelte implicita (daca sint mai multe, putem sa le obtinem pe celelalte utilizind un identificator ca parametru la toolBar) si activam butonul back pentru a permite utilizatorului sa il apese.

In final incarcam noua legatura in widget-ul browser preluind legatura din bara de locatie.

void MainWindow::gotoPreviousPage()
{
  location->setText( history.pop() );

Cind utilizatorul doreste sa se intoarca in pagina anterioara, preluam ultimul element inserat in stiva de istoric si il plasam in bara de locatie. Sirul de caractere este sters din stiva, astfel ca data viitoare cind extragem de pe stiva vom prelua locatia anterioara si tot asa pina cind stiva devine goala.

  if (history.isEmpty())
	  toolBar()->setItemEnabled(TOOLBAR_ID_BACK, FALSE);
  browser->openURL( location->text());
}

Daca stiva este goala, dezactivam butonul back. O data ce am adaugat un alt element butonul este activat din nou de metoda changeLocation(). Apoi deschidem in navigator locatia extrasa.

void MainWindow::fileSetDefaultPage()
{
  KConfig *config=kapp->config();

  config->setGroup("Settings");
  config->writeEntry( "defaultPage", browser->url() );
}

In cele din urma, implementam metoda care este conectata la elementul din meniu Set default page. Aceasta metoda salveaza locatia curenta in fisierul de configurare al aplicatiei.

Mai intii preluam obiectul KConfig si setam grupul Settings cum am facut in constructor. Apoi scriem o noua inregistrare cu ajutorul functiei writeEntry.

Primul parametru este numele cheii si al doilea reprezinta valoarea la care setam cheia. Este de mentionat ca multumita metodelor supraincarcate putem utiliza writeEntry cu diferite tipuri de date ca al doilea parametru (int, bool, float, QString, QStringList, QFont etc.).

Acum am ajuns la finalul acestui tutorial, dar intii trebuie sa efectuam o mica schimbare la P8 astfel incit sa comunice cu P7. Aceasta are ca scop setarea paginii curente in momentul selectarii unei locatii din lista semnelor de carte.



Traducere de Bogdan Daniel Vatra. Adaptare de Claudiu Costin.