[Kde-devel-es] Tutorial: p3

Antonio Larrosa Jiménez kde-devel-es@mail.kde.org
Tue, 1 Oct 2002 13:12:10 +0200


--Boundary-00=_KMYm9C6abutJx2c
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hola,

Con un poco de retraso, aqu=ED llega la tercera parte del tutorial. En este=
=20
punto ya vamos a a=F1adir una barra de men=FA y un widget de texto rico o=20
texto con formato (rich text).

Pero bueno, lo mejor es leerlo.

Si teneis alguna duda, s=F3lo teneis que contestar al mensaje.

Saludos,

=2D-
Antonio Larrosa Jimenez
KDE core developer - larrosa@kde.org
http://devel-home.kde.org/~larrosa/
With a rubber duck,one's never alone --The Hitchhiker's Guide to the Galaxy

--Boundary-00=_KMYm9C6abutJx2c
Content-Type: text/html;
  charset="us-ascii";
  name="p3.html"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="p3.html"

<HTML>
<HEAD>
<TITLE>
Tutorial de KDE- p3
</TITLE>
</HEAD>
<BODY BGCOLOR=3Dwhite COLOR=3Dblack>
<H2><CENTER>p3</CENTER></H2> =20
<P ALIGN=3D"RIGHT">
<A HREF=3D"p4.html">Siguiente</A>
<A HREF=3D"p2.html">Anterior</A>
<A HREF=3D"index.html">Tabla de Contenidos</A></P>
Ya hemos creado una aplicaci&oacute;n simple de KDE en p2, pero en la mayor=
&iacute;a de
los casos habr=E1 que usar un interfaz mas complicado que un simple bot&oac=
ute;n :-),
asi que veamos como a&ntilde;adir un widget principal standard con una barr=
a de men=FA.
<P>
<HR>
<BLOCKQUOTE><PRE>
#include &lt;kapp.h&gt;
#include "p3.h"
=20
int main( int argc, char **argv )
{
    KApplication a( argc, argv, "p3");
=20
    MainWindow *window=3Dnew MainWindow( "Tutorial - p3" );
    window-&gt;resize( 400, 300 );
=20
    a.setMainWidget( window );
    window-&gt;show();
=20
    return a.exec();
}=20
</PRE></BLOCKQUOTE>
<HR>
<DIV ALIGN=3DRIGHT>main.cpp</DIV>
<P>
<HR>
<BLOCKQUOTE><PRE>
#include &lt;kmainwindow.h&gt;
=20
class MainWindow : public KMainWindow
{
   Q_OBJECT
  public:
=20
    MainWindow ( const char * name );
=20
  public slots:
    void fileOpen();
    void fileSave();
};
</PRE></BLOCKQUOTE>
<HR>
<DIV ALIGN=3DRIGHT>p3.h</DIV>
<P>
<HR>
<BLOCKQUOTE><PRE>
#include "p3.h"
#include &lt;kfiledialog.h&gt;
#include &lt;kapp.h&gt;
#include &lt;kmenubar.h&gt;
#include &lt;klocale.h&gt;
#include &lt;kmessagebox.h&gt;
#include &lt;kpopupmenu.h&gt;
#include &lt;qtextview.h&gt;
=20
MainWindow::MainWindow ( const char * name ) : KMainWindow ( 0L, name )
{
    setCaption("KDE Tutorial - p3");

    QPopupMenu *filemenu =3D new QPopupMenu;
    filemenu-&gt;insertItem( i18n( "&amp;Open" ), this, SLOT(fileOpen()) );
    filemenu-&gt;insertItem( i18n( "&amp;Save" ), this, SLOT(fileSave()) );
    filemenu-&gt;insertItem( i18n( "&amp;Quit" ), kapp, SLOT(quit()) );
    QString about =3D
            i18n("p3 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 redistribut=
e it\n"
                 "under certain conditions\n");
=20
    QPopupMenu *helpmenu =3D helpMenu( about );
    KMenuBar *menu =3D menuBar();
    menu-&gt;insertItem( i18n( "&amp;File" ), filemenu );
    menu-&gt;insertSeparator();
    menu-&gt;insertItem( i18n( "&amp;Help" ), helpmenu );
=20
    QTextView *hello=3Dnew QTextView(
       i18n("&lt;H2&gt;Hello World !&lt;/H2&gt;&lt;BR&gt;This is a simple"
	" window with &lt;I&gt;&lt;font size=3D5&gt;&lt;B&gt;R&lt;font color=3Dred"
	" size=3D5&gt;ich &lt;/font&gt;&lt;font color=3Dblue size=3D5&gt;Text"
	"&lt;/font&gt;&lt;/B&gt;&lt;/I&gt; capabilities&lt;BR&gt;Try to resize"
	" this window, all this is automatic !"), "", this );
    setCentralWidget( hello );
=20
=20
}=20
=20
void MainWindow::fileOpen()
{
    KURL filename =3D KFileDialog::getOpenURL( QString::null, "*", this );
    QString msg =3D QString( i18n("Now this app should open the url %1 .") =
).arg(filename.url());
    KMessageBox::information( 0, msg, i18n( "Information" ),=20
		"fileOpenInformationDialog" );
}
=20
void MainWindow::fileSave()
{
    KURL filename=3DKFileDialog::getSaveURL( QString::null, "*", this );
}
</PRE></BLOCKQUOTE>
<HR>
<DIV ALIGN=3DRIGHT>p3.cpp</DIV>
<P>
Este c&oacute;digo parece mucho mas complejo, pero no lo es, echemos un vis=
tazo.
<P>
El c&oacute;digo en main.cpp no ha cambiado mucho desde p1 o p2. La &uacute=
;nica=20
diferencia es que ahora creamos un objeto MainWindow en vez de un QPushButt=
on, y que
ahora no especificamos un puntero NULL en el widget padre, ya que se toma p=
or defecto.
<P>
Adem&aacute;s, no conectamos ninguna se&ntilde;al aqu&iacute;, ya que
MainWindow no tiene ninguna se&ntilde;al como <CODE>clicked()</CODE> (ni
tendr&iacute; mucho sentido que la tuviera).=20
<P>
<PRE>
class MainWindow : public KMainWindow
{
   Q_OBJECT
</PRE>
<P>
En p3.h definimos la clase MainWindow, que hereda de KMainWindow, que es=20
incluida en las kdelibs e incluye todos los m&eacute;todos necesarios para=
=20
crear una aplicaci&oacute;n normal de KDE con un men&uacute;, barra de herr=
amientas (toolbar),
barra de estado (status bar), etc. Observe que en versiones anteriores del =
tutorial,
hered=E1bamos de KTMainWindow, pero esta clase se considera obsoleta.
<P>
=46ij&eacute;monos que hemos escrito <CODE>Q_OBJECT</CODE> en la declaraci&=
oacute;n de=20
nuestra clase. Q_OBJECT es una macro que declara las variables especiales y=
 los
miembros virtuales que necesita el meta-objeto para implementar el mecanism=
o de
se&ntilde;al/slot y otras cosas, y adem&aacute;s le dice a moc que este es =
un QObject y que
puede tener se&ntilde;ales y/o slots.
<PRE>=20
  public slots:
    void fileOpen();
    void fileSave();
</PRE>=20
<P>
Como aprendimos en p1, los slots son m&eacute;todos normales, as&iacute; qu=
e pueden ser
p&uacute;blicos, protegidos o privados (<CODE>public:</CODE>, <CODE>protect=
ed:</CODE>
o <CODE>private:</CODE>) como cualquier otro. La &uacute;nica diferencia se=
ra que debemos=20
especificar <CODE>public slots:</CODE>,<CODE>protected slots:</CODE> o
<CODE>private slots:</CODE>, para que moc sepa que son slots.
<P>
El preprocesador tendr&aacute; cuidado de quitar o substituir todas esas ma=
rcas especiales=20
para que no molesten al compilador.
<P>
Veamos ahora el fichero p3.cpp:
<P>
<PRE>
    QPopupMenu *filemenu =3D new QPopupMenu;
    filemenu-&gt;insertItem( i18n( "&amp;Open" ), this, SLOT(fileOpen()) );
    filemenu-&gt;insertItem( i18n( "&amp;Save" ), this, SLOT(fileSave()) );
    filemenu-&gt;insertItem( i18n( "&amp;Quit" ), kapp, SLOT(quit()) );
<P>
</PRE>=20
<P>
filemenu es un QPopupmenu, esto es, un men&uacute; que contiene "items" (el=
ementos) que el usuario
pulsar&aacute; para realizar una acci&oacute;n dada.
<P>
Insertamos esos items llamando a <CODE>insertItem</CODE>. El primer par&aac=
ute;metro es el
texto que deber&aacute; de estar en el men&uacute;, con un caracter &amp; j=
usto delante de la
letra que queramos usar como acceso r&aacute;pido. Usando i18n nos aseguram=
os que el
texto aparecer&aacute; en el lenguaje en el que el usuario tenga configurad=
o su escritorio.
<P>
Cuando el usuario selecciona un elemento, el men&uacute; emite una se&ntild=
e;al que puede
(=A1 y debe !) ser conectada a una funci&oacute;n para hacer algo. Por conv=
eniencia,
en vez de usar <CODE>connect</CODE>, podemos conectar esta se&ntilde;al dir=
ectamente=20
cuando definimos la entrada del men&uacute;. &Eacute;sto es lo que hacemos =
en el segundo
y tercer par&aacute;metros. Conectamos el elemento de men&uacute; <CODE>Ope=
n</CODE> al
slot <CODE>fileOpen()</CODE> en este (<CODE>this</CODE>) objeto, la entrada=
 <CODE>Save</CODE>
al slot <CODE>fileSave()</CODE> en este (<CODE>this</CODE>) objeto, y la=20
entrada <CODE>Quit</CODE> al slot <CODE>quit()</CODE> de la aplicaci&oacute=
;n
(<CODE>kapp</CODE>), tal como hicimos en p1 y p2.
<P>
=46ij&eacute;monos en que kapp es una funci&oacute;n de conveniencia que pu=
ede ser usada para
acceder a la instancia actual de KApplication.
<P>
<PRE>
    QString about =3D
            i18n("p3 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 redistribut=
e it\n"
                 "under certain conditions\n");
=20
    QPopupMenu *helpmenu =3D helpMenu( about );
</PRE>=20
<P>
Primero ponemos esa cadena dentro del objeto QString. QString es una
clase de cadena de texto de prop&oacute;sito general que se usa para manipu=
lar texto de muy
diversas formas. Uno de los principales beneficios de QString es el poder u=
sar
Unicode en la aplicaci&oacute;n de forma autom&aacute;tica, sin tener que p=
reocuparse de ello.
Ademas prov&eacute;e un mecanismo impl&iacute;cito de compartici&oacute;n d=
e las cadenas que incrementa
su eficiencia, ya que cuando se crea una copia de un QString no se copia re=
almente=20
su contenido hasta que uno de ellos cambia.
<P>
Despu&eacute;s creamos otro men&uacute; popup, pero usando el miembro helpM=
enu de KMainWindow.
Haciendo eso conseguimos un men&uacute; estandard de ayuda, con las entrada=
s para=20
documentaci&oacute;n, un di&aacute;logo sobre el programa (about), etc. Ade=
m&aacute;s, el
di&aacute;logo sobre el programa incluye todo el texto que hemos escrito en=
 la
cadena <CODE>about</CODE>.
<P>
<PRE>
    KMenuBar *menu =3D menuBar();
    menu-&gt;insertItem( i18n( "&amp;File" ), filemenu );
    menu-&gt;insertSeparator();
    menu-&gt;insertItem( i18n( "&amp;Help" ), helpmenu );
</PRE>=20
<P>
Ya estamos preparados para terminar la creaci&oacute;n de nuestro men&uacut=
e;. Primero,
obtenemos la barra de men&uacute; usada por nuestra ventana principal usand=
o <CODE>menuBar()</CODE>.
Como no hay barra de men&uacute; todav=EDa, este m&eacute;todo la crear&aac=
ute; para nosotros
y nos devolver&aacute; un objeto KMenuBar vac&iacute;o que podemos rellenar.
KMenuBar prov&eacute;e un men&uacute; estandard de KDE, con una apariencia
com&uacute;n en todas las aplicaciones
<P>
Entonces insertamos los dos QPopupMenus que ya tenemos, con un separador en=
medio,
y ya hemos terminado de crear el men&uacute;.
<P>
<PRE>
    QTextView *hello=3Dnew QTextView(
       i18n("&lt;H2&gt;Hello World !&lt;/H2&gt;&lt;BR&gt;This is a simple"
	" window with &lt;I&gt;&lt;font size=3D5&gt;&lt;B&gt;R&lt;font color=3Dred"
	" size=3D5&gt;ich &lt;/font&gt;&lt;font color=3Dblue size=3D5&gt;Text"
	"&lt;/font&gt;&lt;/B&gt;&lt;/I&gt; capabilities&lt;BR&gt;Try to resize"
	" this window, all this is automatic !"), "", this );
    setCentralWidget( hello );
</PRE>=20
<P>
Quer&iacute;a que esta aplicaci&oacute;n hiciera algo bonito y simple, asi =
que le vamos
a a&ntilde;adir un widget QTextView. Este widget es un visor bastante &uacu=
te;til de texto
enriquecido (Rich Text), donde podemos especificar el tipo de fuente y colo=
r entre
otras cosas. Despues de crearlo con el texto anterior lo ponemos como el wi=
dget central
( <CODE>centralWidget</CODE> ) de esta ventana.
<P>
Pero, =BFqu&eacute; es un widget central?. Un widget central es el widget q=
ue el=20
usuario puede ver bajo el men&uacute; (o la barra de herramientas si existe=
). Es decir, el=20
widget que muestra el documento que el usuario tiene abierto, o cualquier c=
osa que no es
parte estandar de KMainWindow (esto es, el men&uacute;, la barra de herrami=
entas y la de estado).
<P>
<PRE>
    KURL filename =3D KFileDialog::getOpenURL( QString::null, "*", this );
</PRE>=20
<P>
Ahora miramos a la implementaci&oacute;n del slot de fileOpen. Este c&oacut=
e;digo abre
un di&aacute;logo de abrir fichero que permite al usuario abrir un fichero =
existente.
<P>
Los tres par&aacute;metros indican el directorio en el que se comienza a bu=
scar (no nos
importa en cual comienza, asi que dejamos el actual por defecto), los filtr=
os
(para ver solo los archivos que cumplen una determinada expresi&oacute;n re=
gular) y el
objeto padre.
<P>
Ahora tenemos el url que el usuario quiere abrir almacenado en <CODE>filena=
me</CODE>.
<P>
Observa que se recomienda encarecidamente el permitir al usuario abrir cual=
quier URL,
no s=F3lo archivos locales. Para esto, hemos utilizado el m=E9todo getOpenU=
RL, que permite
al usuario seleccionar cualquier URL. Mire abajo un ejemplo sobre como usar=
 la librer=EDa
KIO.
<P>
<PRE>
    QString msg=3DQString( i18n("Now this app should open the url %1 .") ).=
arg(filename.url());
</PRE>=20
<P>
Podemos manipular cadenas con la clase QString, en realidad estamos usando =
esto
para componer el mensaje que vamos a mostrar a continuaci&oacute;n (ya que =
abrir un fichero
no se encuentra dentro de los objetivos de este tutorial). El formato es si=
milar al
que se usa con sprintf, pero sin necesidad de preocuparse sobre los tipos d=
e los=20
datos, ya que s&oacute;lo habr&aacute; que usar %1, %2, etc. y despues .arg=
(var1).arg(var2).arg(var3),
etc. Otra cosa buena sobre QString es que no habr&aacute; problemas cuando =
la cadena destino
no tenga espacio para la cadena resultante, ya que se reservar&aacute; mas =
espacio=20
automaticamente.
<P>
Por cierto, filename.url() es un QString que contiene la URL guardada en el=
 objeto KURL, o sea,
protocolo+nombre del host+camino+query+todolodem=E1s :-).
<P>
<PRE>
    KMessageBox::information( 0, msg, i18n( "Information" ), "fileOpenInfor=
mationDialog" );
</PRE>=20
<P>
Con la clase KMessageBox y sus miembros est&aacute;ticos, podemos crear una=
 variedad
de cajas de mensajes. En este ejemplo, usamos una caja de informaci&oacute;=
n para=20
mostrar qu&eacute; fichero se deber&iacute;a de haber abierto. El tercer pa=
r&aacute;metro es el mensaje
que aparecer&aacute; como t&iacute;tulo de la caja, y el cuarto es un ident=
ificador, que se usa
para almacenar en un fichero de configuraci&oacute;n (usualmente ~/.kde/sha=
re/config/p3rc)
si el usuario quiere que no se le muestre mas este di&aacute;logo, cosa que=
 se decide
usando un checkbox que aparece en el di&aacute;logo.
<P>
=A1 Fij&eacute;monos en que no hemos escrito ninguna forma de volver a most=
rar ese=20
di&aacute;logo de nuevo !. Esto se consigue llamando a <CODE>KMessageBox::e=
nableAllMessages();</CODE>,
pero me parece que ser&iacute;a un buen ejercicio para el lector de este tu=
torial el
a&ntilde;adir un men&uacute; que haga esta llamada en p3 :-) .
<P>
<PRE>
    KURL filename=3DKFileDialog::getSaveURL( QString::null, "*", this );
</PRE>=20
<P>
=46inalmente, en fileSave llamamos a una funci&oacute;n an&aacute;loga a ge=
tOpenURL, getSaveURL.
<P>
=46ij&eacute;monos en que si usamos getOpenURL deber&iacute;amos de usar la=
 librer&iacute;a KIO para=20
obtener un fichero remoto si eso es lo que quiere el usuario, esto se puede=
 hacer de forma
trivial con el siguiente c&oacute;digo:
<P>
<PRE>
    QString tmpFile;
    if( KIO::NetAccess::download( "ftp://ftp.kde.org/myfile.tgz", tmpFile )=
 )
    {
    /* Aqu=ED hacemos lo que queramos con el fichero _local_ guardado en tm=
pFile */

    KIO::NetAccess::removeTempFile( tmpFile );
    }
</PRE>=20
<P>
Pero esto est&aacute; fuera del &aacute;mbito de este tutorial, aunque pued=
e que lo incremente
en el futuro con un ejemplo de la libreria KIO, libkio.
<P>
Bueno, espero que no fuera demasiado dif&iacute;cil.
<P ALIGN=3D"RIGHT">
<A HREF=3D"p4.html">Siguiente</A>
<A HREF=3D"p2.html">Anterior</A>
<A HREF=3D"index.html">Tabla de Contenidos</A></P>
<HR>
<CENTER>&copy; 1999-2002 <A HREF=3D"mailto:larrosa@kde.org">Antonio Larrosa=
</A></CENTER>
<CENTER>Traducido por <A HREF=3D"mailto:rafael@picasso.scai.uma.es">Rafael =
Larrosa</A> y <A HREF=3D"mailto:larrosa@kde.org">Antonio Larrosa</A></CENTE=
R>
</BODY>
</HTML>

--Boundary-00=_KMYm9C6abutJx2c--