Programación Linux en el Guille


Programación en Linux con KDevelop 1.0

Solución a los ejercicios planteados en la página:
Crear diálogos personalizados (formularios) y gestionar eventos.

 

Autor: Guillermo 'guille' Som
Actualizado: 17/Jun/2003


Pues mira tú por dónde... no puse la solución al ejercicio que planteé en la página en la que se explica cómo crear formularios y acceder a los eventos (slots) de los controles (widgets), así que... aunque sea con cuatro años de retraso (supongo que lo habrás resuelto bien), aquí tienes el código con la solución.

¿No te acuerdas de cual era el ejercicio a resolver?
Pues era lo siguiente: (en esta página tienes más información)

...sería interesante que nuestra aplicación tuviese un botón que nos permita borrar los elementos seleccionados de la lista.
Otra mejora podría ser sustituir el elemento seleccionado por el contenido de la caja de texto.
Y para terminar con los ejercicios (o proposiciones no indecentes), sería que se nos permitiera usar por defecto un nombre de fichero, de esa forma, cada vez que esa opción esté marcada y pulsemos en abrir o guardar, se use ese fichero en lugar de tener que preguntarnos el nombre...

Este es el código a usar, el diseño del formulario o ventana tendrás que hacerlo por tu cuenta.

En el fichero .h tendrás que añadir estas declaraciones bajo private slots:

// Conectar la pulsación de los botones Añadir y Eliminar a las funciones
void cmdDel_click();
void cmdReplace_click();

En la sección private: vamos a crear una enumeración para la acción a tomar en la función testFile (que se encargará de comprobar si se usa o no el fichero por defecto):

// Enumeración para la acción a tomar en la función testFile
enum eAccion {Leer_Fichero, Guardar_Fichero};
// Función para comprobar si se usa o no el fichero por defecto
QString testFile( eAccion accion );


En el fichero .cpp tendrás que añadir lo siguiente:
En el constructor de la clase habrá que conectar los nuevos controles (widgets) con sus respectivos eventos (slots):

// ------------------------------------------------------------------------
// Solución de los ejercicios
// ------------------------------------------------------------------------
// Conectar la pulsación de los botones Añadir y Eliminar a las funciones
connect( cmdDel, SIGNAL(clicked()), SLOT(cmdDel_click()) );
connect( cmdReplace, SIGNAL(clicked()), SLOT(cmdReplace_click()) );

Este será el código del botón eliminar:

void KPrueba02::cmdDel_click(){
    // Cuando pulsamos en el botón Eliminar
    lblStatus->setText("Eliminando...");

    // Borramos todos los elementos seleccionados
    uint i;
    // número de elementos antes de borrar
    uint t = lstNames->count();

    // Sólo si hay elementos en la lista...
    if(t<1)
        lblStatus->setText("No hay nada que borrar...");
    else{
        // Es curioso, pero de esta otra forma no funciona:
        // for( i = t - 1 ; i >= 0; i-- )
        for( i = t; i > 0; i-- )
            if( lstNames->isSelected(i-1) )
                // eliminamos el elemento seleccionado
                lstNames->removeItem(i-1);
        
        // Si el número de elementos actual es diferente de lo que había
        if( t != lstNames->count() )
            // es que se ha modificado la lista...
            modificado = true;
        
        QString s;
        // Convertimos el número en una cadena
        s.setNum( lstNames->count() );
        // mostramos el número de elementos en la lista
        lblStatus->setText( "Nombres en la lista: " + s );
    }
}

Este otro, es el código del botón Reemplazar:

void KPrueba02::cmdReplace_click(){
    // Al pulsar en Reemplazar

    // Asignamos el contenido del textbox al elemento seleccionado de la lista
    QString s = txtName->text();

    // currentItem nos da el número de elemento actualmente seleccionado
    // en caso de que haya más de un elemento seleccionado,
    // devolverá el último que se seleccionó
    int i = lstNames->currentItem();
    // si vale -1 es que no hay seleccionado
    if( i != -1){
        // en caso contrario, cambiamos el contenido del elemento seleccionado
        lstNames->changeItem(s, i);
        // marcamos el flag de que se ha modificado la lista
        modificado = true;
    }
}

Esta es la función testFile:

// Cuando se pulsa en Guardar o Abrir se comprobará si se quiere usar el fichero por defecto
// en caso de que sea así, no se mostrará el cuadro de diálogo,
// salvo que el fichero en cuestión no exista.
// Esta función se encargará de mostrar el cuadro de diálogo si procede.
// Devolverá una cadena (QString) con el nombre del fichero a usar.
QString KPrueba02::testFile( eAccion accion ){
    
    // El checkbox estará seleccionado,
    // si queremos usar el fichero por defecto
    if( chkFile->isChecked() ){
        QString s;    // esta variable sólo es visible dentro del bloque if
        // Asignar el nombre del fichero
        s = lblFile->text();
        // Si es una cadena vacía, es que no hay nombre asignado
        if( !s.isEmpty() ){
            // Si la accion es leer, devolver el nombre del fichero sólo si existe
            if( accion == Leer_Fichero ){
                QFile f(s);
                if( f.exists() )
                    return s;
            }else
                return s;
        }
    }
    // Si llegamos aquí, es que tenemos que mostrar el diálogo
    QString sFile;

    // Comprobar si es el de abrir o guardar
    if( accion == Leer_Fichero )
        // Seleccionar el fichero para abrir
        sFile = QFileDialog::getOpenFileName("./", "*.txt", this);
    else
        // Seleccionar el fichero para guardar
        sFile = QFileDialog::getSaveFileName("./", "*.txt", this);
    
    // Devolver el nombre del fichero seleccionado
    // en caso de que se haya cancelado, la cadena estará vacia,
    // pero ese caso se tiene en cuenta en las funciones correspondientes
    return sFile;
}

Por último, veamos el código de los botones Guardar y Abrir con los cambios para usar testFile:

void KPrueba02::cmdSave_click(){
    // Cuando se pulsa en Guardar

    // Sólo si hay elementos en la lista
    if( lstNames->count() ){
        // Preguntar el nombre del fichero
        //QString sFile = QFileDialog::getSaveFileName("./","*.txt",this);
        
        // Usamos la función que comprueba si se debe usar el fichero por defecto
        QString sFile = testFile( Guardar_Fichero);
        
    // Si se ha seleccionado un nombre
        // (cuando se pulsa en cancelar se devuelve una cadena vacia)
        if( !sFile.isEmpty() ){
            // Asignar el fichero seleccionado
            QFile f(sFile);
             // Abrirlo para escribir en él
            f.open(IO_WriteOnly);
             // Guardar cada elemento de la lista
            uint i;
            for( i=0;i<lstNames->count();i++ ){
                // Añadir un retorno de carro y cambio de línea... al estilo MS-DOS
                QString c = lstNames->text(i) + QString("\n\r");
                // writeBlock espera una cadena y el número de caracteres
                f.writeBlock( c, c.length() );
                lblStatus->setText("guardando... "+c);
            }
             // cerrar el fichero
            f.close();
            modificado = false;
            lblStatus->setText("Datos guardados en: " + sFile);
            
            // Asignar el nombre del fichero que se puede usar por defecto
            lblFile->setText( sFile );
        }else
            lblStatus->setText("No has seleccionado un nombre");

    }else
        lblStatus->setText("No hay elementos que guardar!");
}

void KPrueba02::cmdOpen_click(){
    // Cuando se pulsa en Abrir

    // Si se ha modificado la lista, preguntar si se guarda...
    if( modificado ){
        if( QMessageBox::warning(this,"Abrir - Prueba de Diálogos",
                                      "¡ATENCION! La lista se ha modificado y no está guardada\n\n¿Quieres guardarla?",
                                      " Si ", " No ",0,0)==0 )
            cmdSave_click();
    }
    // Borrar el contenido de la lista
    lstNames->clear();

    // Preguntar el nombre del fichero a abrir
    //QString sFile = QFileDialog::getOpenFileName("./","*.txt",this);
    
    // Usamos la función que comprueba si se debe usar el fichero por defecto
    QString sFile = testFile( Leer_Fichero);
    
  // Si se ha seleccionado un nombre
    // (cuando se pulsa en cancelar se devuelve una cadena vacia)
    if( !sFile.isEmpty() ){
        // Asignar el fichero seleccionado
        QFile f(sFile);
         // Abrirlo para lectura
        f.open(IO_ReadOnly);
        
         // Leer del fichero y asignarlo al listbox
        QString s;
        // Asignamos el fichero a un TextStream para poder "navegar" por el contenido
        QTextStream t(&f);
        
        while( !t.eof() ) {
            // Leemos la siguiente línea
            s = t.readLine();
            // Quitamos los espacios del principio y final
            s = s.stripWhiteSpace();
            // Si no es una cadena vacia...
            if( !s.isEmpty() )
                // Lo añadimos a la lista
                lstNames->insertItem(s);
        }
         // cerrar el fichero
        f.close();
        modificado = false;
        s.setNum( lstNames->count() );
        lblStatus->setText("Nombres en la lista: " + s );
        
        // Asignar el nombre del fichero que se puede usar por defecto
        lblFile->setText( sFile );
    }else
        lblStatus->setText("No has seleccionado un nombre");
}

Bueno, esto es todo... menos mal que siempre habrá gente que lea esto "mucho" después de que fuera originalmente publicado (me refiero sobre todo al ejercicio), así no habrá problemas con este "desfase" de tiempo...

Nos vemos.
Guillermo

Nerja, 17 de Junio de 2003


Volver al índice de KDevelop

Volver a la sección de Linux

índice de el Guille