p3

Siguiente Anterior Tabla de Contenidos

Ya hemos creado una aplicación simple de KDE en p2, pero en la mayoría de los casos habrá que usar un interfaz mas complicado que un simple botón :-), asi que veamos como añadir un widget principal standard con una barra de menú.


#include <kapp.h>
#include "p3.h"
 
int main( int argc, char **argv )
{
    KApplication a( argc, argv, "p3");
 
    MainWindow *window=new MainWindow( "Tutorial - p3" );
    window->resize( 400, 300 );
 
    a.setMainWidget( window );
    window->show();
 
    return a.exec();
} 

main.cpp


#include <kmainwindow.h>
 
class MainWindow : public KMainWindow
{
   Q_OBJECT
  public:
 
    MainWindow ( const char * name );
 
  public slots:
    void fileOpen();
    void fileSave();
};

p3.h


#include "p3.h"
#include <kfiledialog.h>
#include <kapp.h>
#include <kmenubar.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kpopupmenu.h>
#include <qtextview.h>
 
MainWindow::MainWindow ( const char * name ) : KMainWindow ( 0L, name )
{
    setCaption("KDE Tutorial - p3");

    QPopupMenu *filemenu = new QPopupMenu;
    filemenu->insertItem( i18n( "&Open" ), this, SLOT(fileOpen()) );
    filemenu->insertItem( i18n( "&Save" ), this, SLOT(fileSave()) );
    filemenu->insertItem( i18n( "&Quit" ), kapp, SLOT(quit()) );
    QString about =
            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 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 );
 
    QTextView *hello=new QTextView(
       i18n("<H2>Hello World !</H2><BR>This is a simple"
	" window with <I><font size=5><B>R<font color=red"
	" size=5>ich </font><font color=blue size=5>Text"
	"</font></B></I> capabilities<BR>Try to resize"
	" this window, all this is automatic !"), "", this );
    setCentralWidget( hello );
 
 
} 
 
void MainWindow::fileOpen()
{
    KURL filename = KFileDialog::getOpenURL( QString::null, "*", this );
    QString msg = QString( i18n("Now this app should open the url %1 .") ).arg(filename.url());
    KMessageBox::information( 0, msg, i18n( "Information" ), 
		"fileOpenInformationDialog" );
}
 
void MainWindow::fileSave()
{
    KURL filename=KFileDialog::getSaveURL( QString::null, "*", this );
}

p3.cpp

Este código parece mucho mas complejo, pero no lo es, echemos un vistazo.

El código en main.cpp no ha cambiado mucho desde p1 o p2. La única diferencia es que ahora creamos un objeto MainWindow en vez de un QPushButton, y que ahora no especificamos un puntero NULL en el widget padre, ya que se toma por defecto.

Además, no conectamos ninguna señal aquí, ya que MainWindow no tiene ninguna señal como clicked() (ni tendrí mucho sentido que la tuviera).

class MainWindow : public KMainWindow
{
   Q_OBJECT

En p3.h definimos la clase MainWindow, que hereda de KMainWindow, que es incluida en las kdelibs e incluye todos los métodos necesarios para crear una aplicación normal de KDE con un menú, barra de herramientas (toolbar), barra de estado (status bar), etc. Observe que en versiones anteriores del tutorial, heredábamos de KTMainWindow, pero esta clase se considera obsoleta.

Fijémonos que hemos escrito Q_OBJECT en la declaración de nuestra clase. Q_OBJECT es una macro que declara las variables especiales y los miembros virtuales que necesita el meta-objeto para implementar el mecanismo de señal/slot y otras cosas, y además le dice a moc que este es un QObject y que puede tener señales y/o slots.

 
  public slots:
    void fileOpen();
    void fileSave();

Como aprendimos en p1, los slots son métodos normales, así que pueden ser públicos, protegidos o privados (public:, protected: o private:) como cualquier otro. La única diferencia sera que debemos especificar public slots:,protected slots: o private slots:, para que moc sepa que son slots.

El preprocesador tendrá cuidado de quitar o substituir todas esas marcas especiales para que no molesten al compilador.

Veamos ahora el fichero p3.cpp:

    QPopupMenu *filemenu = new QPopupMenu;
    filemenu->insertItem( i18n( "&Open" ), this, SLOT(fileOpen()) );
    filemenu->insertItem( i18n( "&Save" ), this, SLOT(fileSave()) );
    filemenu->insertItem( i18n( "&Quit" ), kapp, SLOT(quit()) );

filemenu es un QPopupmenu, esto es, un menú que contiene "items" (elementos) que el usuario pulsará para realizar una acción dada.

Insertamos esos items llamando a insertItem. El primer parámetro es el texto que deberá de estar en el menú, con un caracter & justo delante de la letra que queramos usar como acceso rápido. Usando i18n nos aseguramos que el texto aparecerá en el lenguaje en el que el usuario tenga configurado su escritorio.

Cuando el usuario selecciona un elemento, el menú emite una señal que puede (¡ y debe !) ser conectada a una función para hacer algo. Por conveniencia, en vez de usar connect, podemos conectar esta señal directamente cuando definimos la entrada del menú. Ésto es lo que hacemos en el segundo y tercer parámetros. Conectamos el elemento de menú Open al slot fileOpen() en este (this) objeto, la entrada Save al slot fileSave() en este (this) objeto, y la entrada Quit al slot quit() de la aplicación (kapp), tal como hicimos en p1 y p2.

Fijémonos en que kapp es una función de conveniencia que puede ser usada para acceder a la instancia actual de KApplication.

    QString about =
            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 redistribute it\n"
                 "under certain conditions\n");
 
    QPopupMenu *helpmenu = helpMenu( about );

Primero ponemos esa cadena dentro del objeto QString. QString es una clase de cadena de texto de propósito general que se usa para manipular texto de muy diversas formas. Uno de los principales beneficios de QString es el poder usar Unicode en la aplicación de forma automática, sin tener que preocuparse de ello. Ademas provée un mecanismo implícito de compartición de las cadenas que incrementa su eficiencia, ya que cuando se crea una copia de un QString no se copia realmente su contenido hasta que uno de ellos cambia.

Después creamos otro menú popup, pero usando el miembro helpMenu de KMainWindow. Haciendo eso conseguimos un menú estandard de ayuda, con las entradas para documentación, un diálogo sobre el programa (about), etc. Además, el diálogo sobre el programa incluye todo el texto que hemos escrito en la cadena about.

    KMenuBar *menu = menuBar();
    menu->insertItem( i18n( "&File" ), filemenu );
    menu->insertSeparator();
    menu->insertItem( i18n( "&Help" ), helpmenu );

Ya estamos preparados para terminar la creación de nuestro menú. Primero, obtenemos la barra de menú usada por nuestra ventana principal usando menuBar(). Como no hay barra de menú todavía, este método la creará para nosotros y nos devolverá un objeto KMenuBar vacío que podemos rellenar. KMenuBar provée un menú estandard de KDE, con una apariencia común en todas las aplicaciones

Entonces insertamos los dos QPopupMenus que ya tenemos, con un separador enmedio, y ya hemos terminado de crear el menú.

    QTextView *hello=new QTextView(
       i18n("<H2>Hello World !</H2><BR>This is a simple"
	" window with <I><font size=5><B>R<font color=red"
	" size=5>ich </font><font color=blue size=5>Text"
	"</font></B></I> capabilities<BR>Try to resize"
	" this window, all this is automatic !"), "", this );
    setCentralWidget( hello );

Quería que esta aplicación hiciera algo bonito y simple, asi que le vamos a añadir un widget QTextView. Este widget es un visor bastante útil de texto enriquecido (Rich Text), donde podemos especificar el tipo de fuente y color entre otras cosas. Despues de crearlo con el texto anterior lo ponemos como el widget central ( centralWidget ) de esta ventana.

Pero, ¿qué es un widget central?. Un widget central es el widget que el usuario puede ver bajo el menú (o la barra de herramientas si existe). Es decir, el widget que muestra el documento que el usuario tiene abierto, o cualquier cosa que no es parte estandar de KMainWindow (esto es, el menú, la barra de herramientas y la de estado).

    KURL filename = KFileDialog::getOpenURL( QString::null, "*", this );

Ahora miramos a la implementación del slot de fileOpen. Este código abre un diálogo de abrir fichero que permite al usuario abrir un fichero existente.

Los tres parámetros indican el directorio en el que se comienza a buscar (no nos importa en cual comienza, asi que dejamos el actual por defecto), los filtros (para ver solo los archivos que cumplen una determinada expresión regular) y el objeto padre.

Ahora tenemos el url que el usuario quiere abrir almacenado en filename.

Observa que se recomienda encarecidamente el permitir al usuario abrir cualquier URL, no sólo archivos locales. Para esto, hemos utilizado el método getOpenURL, que permite al usuario seleccionar cualquier URL. Mire abajo un ejemplo sobre como usar la librería KIO.

    QString msg=QString( i18n("Now this app should open the url %1 .") ).arg(filename.url());

Podemos manipular cadenas con la clase QString, en realidad estamos usando esto para componer el mensaje que vamos a mostrar a continuación (ya que abrir un fichero no se encuentra dentro de los objetivos de este tutorial). El formato es similar al que se usa con sprintf, pero sin necesidad de preocuparse sobre los tipos de los datos, ya que sólo habrá que usar %1, %2, etc. y despues .arg(var1).arg(var2).arg(var3), etc. Otra cosa buena sobre QString es que no habrá problemas cuando la cadena destino no tenga espacio para la cadena resultante, ya que se reservará mas espacio automaticamente.

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ás :-).

    KMessageBox::information( 0, msg, i18n( "Information" ), "fileOpenInformationDialog" );

Con la clase KMessageBox y sus miembros estáticos, podemos crear una variedad de cajas de mensajes. En este ejemplo, usamos una caja de información para mostrar qué fichero se debería de haber abierto. El tercer parámetro es el mensaje que aparecerá como título de la caja, y el cuarto es un identificador, que se usa para almacenar en un fichero de configuración (usualmente ~/.kde/share/config/p3rc) si el usuario quiere que no se le muestre mas este diálogo, cosa que se decide usando un checkbox que aparece en el diálogo.

¡ Fijémonos en que no hemos escrito ninguna forma de volver a mostrar ese diálogo de nuevo !. Esto se consigue llamando a KMessageBox::enableAllMessages();, pero me parece que sería un buen ejercicio para el lector de este tutorial el añadir un menú que haga esta llamada en p3 :-) .

    KURL filename=KFileDialog::getSaveURL( QString::null, "*", this );

Finalmente, en fileSave llamamos a una función análoga a getOpenURL, getSaveURL.

Fijémonos en que si usamos getOpenURL deberíamos de usar la librería KIO para obtener un fichero remoto si eso es lo que quiere el usuario, esto se puede hacer de forma trivial con el siguiente código:

    QString tmpFile;
    if( KIO::NetAccess::download( "ftp://ftp.kde.org/myfile.tgz", tmpFile ) )
    {
    /* Aquí hacemos lo que queramos con el fichero _local_ guardado en tmpFile */

    KIO::NetAccess::removeTempFile( tmpFile );
    }

Pero esto está fuera del ámbito de este tutorial, aunque puede que lo incremente en el futuro con un ejemplo de la libreria KIO, libkio.

Bueno, espero que no fuera demasiado difícil.

Siguiente Anterior Tabla de Contenidos


© 1999-2002 Antonio Larrosa
Traducido por Rafael Larrosa y Antonio Larrosa