├── imagenes ├── login.png ├── tablas.png ├── botones.png ├── qgroupbox.png ├── qiodevice.png ├── ventana.png ├── progressbar.png ├── qtdesigner.png ├── dos_imagenes.png └── ejercicio_captcha.jpg ├── Clase18.rst ├── README.rst ├── Clase02.rst ├── Clase08.rst ├── Clase09.rst ├── Clase19.rst ├── Desafios.rst ├── Clase16.rst ├── Clase11.rst ├── Clase06.rst ├── Clase01.rst ├── Clase05.rst ├── Clase14.rst ├── Clase07.rst ├── Clase13.rst ├── Clase15.rst ├── Clase04.rst ├── Clase10.rst ├── Clase12.rst ├── Clase17.rst └── Clase03.rst /imagenes/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/login.png -------------------------------------------------------------------------------- /imagenes/tablas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/tablas.png -------------------------------------------------------------------------------- /imagenes/botones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/botones.png -------------------------------------------------------------------------------- /imagenes/qgroupbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/qgroupbox.png -------------------------------------------------------------------------------- /imagenes/qiodevice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/qiodevice.png -------------------------------------------------------------------------------- /imagenes/ventana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/ventana.png -------------------------------------------------------------------------------- /imagenes/progressbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/progressbar.png -------------------------------------------------------------------------------- /imagenes/qtdesigner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/qtdesigner.png -------------------------------------------------------------------------------- /imagenes/dos_imagenes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/dos_imagenes.png -------------------------------------------------------------------------------- /imagenes/ejercicio_captcha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosimani/Curso-POO-2024/HEAD/imagenes/ejercicio_captcha.jpg -------------------------------------------------------------------------------- /Clase18.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 18 - POO 2024 6 | =================== 7 | (Fecha: 27 de mayo) 8 | 9 | 10 | Ejercicio 16 (continuación): 11 | ============================ 12 | 13 | - Este ejercicio viene de la clase 5 y 7. 14 | - Luego de tener registrados los usuarios en MongoDB y funcionando el endpoint. 15 | - Acondicionar la clase Login para validar los usuarios contra el endpoint de FastAPI. 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Guía de estudio de la asignatura Programación Orientada a Objetos 2 | ================================================================= 3 | 4 | Destinado a estudiantes de la carrera Ing. Informática de la Universidad Blas Pascal. 5 | 6 | 7 | :Profesor: Dr. César Osimani 8 | :Correo: cesarosimani@gmail.com 9 | :Asignatura: Programación Orientada a Objetos 10 | :Fecha: Marzo a junio de 2024 11 | 12 | :Temas principales de la asignatura: 13 | - Espacio de nombres 14 | - inline y const 15 | - std, vector, string 16 | - Aritmética de punteros 17 | - Funciones genéricas 18 | - Herencia y herencia múltiple 19 | - Polimorfismo 20 | - Funciones virtuales 21 | - Clases abstractas 22 | - Modificador friend 23 | - Biblioteca Qt 24 | - Uso de documentación 25 | - slots y signals 26 | - QtNetwork 27 | - Interfaz gráfica de usuario (widgets, layouts, etc.) 28 | - QPainter y captura de eventos del teclado y del mouse 29 | - QTimer 30 | - QtDesigner 31 | - Base de datos (SELECT e INSERT). 32 | - Resolver los problemas consultando documentación técnica de distintas fuentes 33 | 34 | 35 | Parte de este material ha sido inspirado y/o adaptado de múltiples fuentes: 36 | 37 | * `Curso de C++ Zator Systems `_ 38 | * `Aplicativos para desarrollo con Qt/C++ `_ 39 | * `Instaladores offline de Qt `_ 40 | * También está disponible este instalador Offline: `https://download.qt.io/archive/qt/5.14/5.14.1 `_ 41 | * `Tutoriales y ejemplos con la biblioteca Qt `_ 42 | * `Foro de Qt en Español `_ 43 | * `Libro: El lenguaje de programación C++ de Bjarne Stroustrup (disponible en biblioteca de UBP) `_ 44 | * `Videos tutoriales de C `_ 45 | * `Videos tutoriales de C++ `_ 46 | * `Videos tutoriales de Qt `_ 47 | * `App SoloLearn `_ 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Clase02.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 02 - POO 2024 6 | =================== 7 | (Fecha: 13 de marzo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `std namespace vector list 2022 `_ 14 | 15 | `vector 2021 `_ 16 | 17 | 18 | Problema para las próximas semanas 19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 20 | 21 | :Una empresa que se dedica al desarrollo de software ofrece soluciones y utiliza las siguientes tecnologías y herramientas: 22 | - QtCreator como IDE 23 | - Biblioteca Qt con C++ para aplicaciones Desktop 24 | - MongoDB para base de datos 25 | - FastAPI en Python para la API 26 | 27 | Necesidad 28 | ^^^^^^^^^ 29 | 30 | - Se desea una aplicación desktop en Qt que tenga un login de usuarios 31 | - Cuando un usuario en la aplicación desktop ingrese un usuario válido obtendrá un access token desde la API desarrollada con FastAPI 32 | - Cuando se obtiene el access token, el usuario ya estará logueado, y podrá utilizar este token para próximas consultas a la API 33 | - Los usuarios se almacenarán en una colección de MongoDB 34 | - Se quiere montar todo esto en el localhost para tener un entorno de desarrollo y testing 35 | 36 | 37 | 38 | 39 | 40 | Utilidades de la biblioteca estándar de C++ 41 | =========================================== 42 | 43 | vector 44 | ^^^^^^ 45 | 46 | - Mantiene sus elementos en un área contigua de memoria. 47 | - El acceso aleatorio es eficiente. 48 | - La inserción en cualquier posición distinta a la última es ineficiente. 49 | - Se encuentra en #include en el namespace std 50 | 51 | .. code-block:: 52 | 53 | vector< int > v1; // vector vacío 54 | vector< int > v2( 15 ); // vector de 15 elementos 55 | vector< string > v3( 18, "cadena" ); // 18 elemento con valor inicial 56 | vector< string > v4( v3 ); // v4 es una copia v3 57 | 58 | **Algunas operaciones** 59 | 60 | .. code-block:: 61 | 62 | size() // Tamaño 63 | bool empty() // Está vacío? 64 | void clear() // Limpia el vector 65 | front() // Acceso al primero 66 | back() // Al último 67 | push_back( x ) // Inserción al último 68 | pop_back() // Elimina 69 | w = v // Asignación 70 | v == w v < w // Comparaciones 71 | v.at( i ) // Acceso con verificación de rango (lanza out_of_range) 72 | v[ i ] // Acceso sin verificación de rango 73 | 74 | -------------------------------------------------------------------------------- /Clase08.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 08 - POO 2024 6 | =================== 7 | (Fecha: 10 de abril) 8 | 9 | 10 | 11 | Registro en video de algunos temas de la clase de hoy 12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 | 14 | `POO 2023 - Array como parámetros - QTextEdit y aritmética de punteros 2023 `_ 15 | 16 | 17 | 18 | Array como parámetro en funciones 19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 20 | 21 | .. code-block:: 22 | 23 | #include 24 | using namespace std; 25 | 26 | void funcion( int miArray[] ); 27 | // Le estamos pasando un puntero al primer elemento del array. 28 | 29 | int main() { 30 | int miA[ 5 ] = { 0, 1, 2, 3, 4 }; 31 | 32 | funcion( miA ); 33 | 34 | cout << miA[ 0 ] << miA[ 1 ] << miA[ 2 ] << miA[ 3 ] << miA[ 4 ]; 35 | } 36 | 37 | void funcion( int miArray[] ) { 38 | miArray[ 0 ] = 5; // Las modificaciones quedarán. 39 | 40 | miArray[ 3 ] = 5; 41 | } 42 | 43 | 44 | 45 | Constructores con argumentos por defecto 46 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 47 | 48 | .. code-block:: 49 | 50 | class ClaseA { 51 | public: 52 | ClaseA( int a = 10, int b = 20 ) : a( a ), b( b ) { } 53 | 54 | void verDatos( int &a, int &b ) { 55 | a = this->a; 56 | b = this->b; 57 | } 58 | 59 | private: 60 | int a, b; 61 | }; 62 | 63 | int main( int argc, char ** argv ) { 64 | ClaseA * objA = new ClaseA; 65 | 66 | int a, b; 67 | objA->verDatos( a, b ); 68 | 69 | std::cout << "a = " << a << " b = " << b << std::endl; 70 | 71 | return 0; 72 | } 73 | 74 | // Probar con: 75 | 76 | ClaseA( int c, int a = 10, int b = 20 ) : a( a ), b( b ), c( 0 ) { } 77 | 78 | ClaseA( int a = 10, int b = 20, int c ) : a( a ), b( b ), c( 0 ) { } 79 | 80 | 81 | QTextEdit 82 | ========= 83 | 84 | - Un QWidget que muestra texto plano o enriquecido 85 | - Puede mostrar imágenes, listas y tablas 86 | - La barra de desplazamiento es automática 87 | - Interpreta tags HTML 88 | - Seteamos texto con setPlainText() 89 | 90 | 91 | Desafío 92 | ======= 93 | 94 | - Escribir la salida por consola de la siguiente aplicación: 95 | 96 | .. code-block:: 97 | 98 | #include 99 | #include 100 | 101 | int main( int argc, char** argv ) { 102 | QApplication app( argc, argv ); 103 | 104 | int a = 10, b = 100, c = 30, d = 1, e = 54; 105 | int m[ 10 ] = { 10, 9, 80, 7, 60, 5, 40, 3, 20, 1 }; 106 | int *p = &m[ 3 ], *q = &m[ 6 ]; 107 | 108 | ++q; 109 | qDebug() << a + m[ d / c ] + b-- / *q + 10 + e--; 110 | 111 | p = m; 112 | qDebug() << e + *p + m[ 9 ]++; 113 | 114 | return 0; 115 | } 116 | 117 | 118 | Ejercicio 14 (continuación): 119 | ============================ 120 | 121 | - Agregar la siguiente característica a Login: Si el usuario falla 3 veces la clave, bloquear por 5 minutos a ese usuario. 122 | 123 | 124 | Ejercicio 18 125 | ============ 126 | 127 | - Utilizar un proyecto con un login cualquiera que valide admin:1234 128 | - Cuando el usuario es válido, abrir una nueva ventana que tenga un QTextEdit que permita mostrar código HTML. 129 | - Esta ventana deberá tener un QLineEdit que permita ingresar una URL 130 | - Cuando se pulse Enter, se deberá buscar el html de la URL escrita y se deberá publicar en el QTextEdit. 131 | 132 | -------------------------------------------------------------------------------- /Clase09.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 09 - POO 2024 6 | =================== 7 | (Fecha: 15 de abril) 8 | 9 | 10 | Simulacro de examen parcial 11 | =========================== 12 | 13 | 14 | Ejercicio A 15 | ^^^^^^^^^^^ 16 | 17 | - Comenzar un proyecto vacío con QtCreator y diseñar un login de usuarios como el siguiente: 18 | 19 | .. figure:: imagenes/login.png 20 | 21 | - Tendrá un tamaño de 250x120 píxeles y llevará por título "Login". 22 | - Para el layout utilizar QGridLayout. 23 | - El único usuario válido es el DNI de estudiante y como clave sus últimos 3 números del DNI. 24 | - Ocultar con asteriscos la clave y detectar el Enter para validar al usuario. 25 | - Si el usuario y clave no es válido, sólo el campo de la clave se deberá limpiar. 26 | - Al fallar la clave 3 veces, la aplicación se cierra. 27 | - Si el usuario es válido, entonces se oculta el login y se visualiza un nuevo QWidget como el que sigue: 28 | 29 | .. figure:: imagenes/ventana.png 30 | 31 | - Utilizar una imagen del disco aproximadamente de 100x100 píxeles. 32 | - Esta imagen se mostrará en el QWidget exactamente centrada. 33 | - Dibujar además un cuadrado que envuelva la imagen (como muestra el ejemplo). 34 | 35 | 36 | Ejercicio B 37 | ^^^^^^^^^^^ 38 | 39 | - Crear una aplicación que inicie con un login validando el usuario admin:123 40 | - Luego de ingresar el usuario válido, mostrar un nuevo QWidget con las siguientes características: 41 | - Definida en la clase Editor 42 | - Contendrá un QTextEdit vacío, un QLineEdit, un QPushButton "Buscar" y un QLabel 43 | - El usuario podrá escribir cualquier texto en el QTextEdit. 44 | - EL usuario podrá escribir también en el QLineEdit un caracter, una cadena o una frase. 45 | - Al presionar "Buscar" se detectará automáticamente la cantidad de ocurrencias encontradas de los que se escribió en el QLineEdit. 46 | - El resultado de colocará en el QLabel, indicando, por ejemplo, "14 ocurrencias." 47 | - Luego de dejar funcionando lo anterior, agregar lo siguiente: 48 | - Un QLineEdit y un QPushButton "Guardar" 49 | - En este QLineEdit el usuario puede colocar el nombre de un archivo .txt 50 | - Al presionar Guardar se almacenará todo el texto del QTextEdit en este archivo .txt 51 | 52 | 53 | Ejercicio C 54 | ^^^^^^^^^^^ 55 | 56 | - Crear una clase Barra para dar funcionalidad a una barra de progreso 57 | - Que la barra tenga el siguiente aspecto: 58 | 59 | .. figure:: imagenes/progressbar.png 60 | 61 | - Debe tener métodos para setear su valor en porcentaje 62 | - Usar la señal de ``downloadProgress`` de ``QNetworkReply`` para controlar el porcentaje de descarga 63 | - Crear una interfaz que tenga un ``QLineEdit`` para una URL y un objeto Barra. 64 | - Probarlo con alguna URL que pertenezca a un archivo de tamaño superior a 50MB para que se note la demora en la descarga. 65 | 66 | 67 | Ejercicio D 68 | ^^^^^^^^^^^ 69 | 70 | - Diseñar una aplicación para una galería de fotos 71 | - En un archivo .txt almacenar en cada línea, una URL a una imagen 72 | - Un botón >> y otro botón << para avanzar o retroceder en la galería de fotos 73 | 74 | 75 | Ejercicio E 76 | ^^^^^^^^^^^ 77 | 78 | - Definir la clase Ventana que herede de QWidget 79 | - Usar desde el disco una imagen de una bola 8 con formato PNG (para usar transparencias). 80 | - Ventana tendrá un QGroupBox con los siguientes parámetros: 81 | - Diámetro de la bola (en píxeles) 82 | - Velocidad (segundos para ir de lado a lado) 83 | - QPushButton para actualizar estos parámetros en la bola 84 | - La bola irá golpeando de izquierda a derecha en la Ventana. -------------------------------------------------------------------------------- /Clase19.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 19 - POO 2024 6 | =================== 7 | (Fecha: 3 de junio) 8 | 9 | 10 | Simulacro de examen parcial 11 | =========================== 12 | 13 | 14 | Ejercicio A 15 | ^^^^^^^^^^^ 16 | 17 | - Definir una ventana vacía en la clase Principal, que herede de QWidget y diseñado con QtDesigner. 18 | - Agregar a este proyecto la clase AdminDB para permitir el uso de una base de datos. 19 | - Instanciar un único objeto de AdminDB en la aplicación. 20 | - Definir una clase Linea con las siguientes características: 21 | - En los archivos fuente linea.h y linea.cpp 22 | - Atributos privados: int x_inicial, y_inicial, x_final, y_final 23 | - Con sus getters y setters. 24 | - Utilizar en esta clase todos los const que son recomendables 25 | - Definir una tabla "lineas" en la base de datos con los siguientes campos: id, x_inicial, y_inicial, x_final, y_final 26 | - Cargar en la base de datos un único registro, es decir, los datos de una única línea. 27 | - Desde la clase Principal se podrá leer este único registro y crear un objeto Linea con esos datos. 28 | - Dibujar con paintEvent esta línea dentro de la ventana con las coordenadas leídas de la base. 29 | 30 | 31 | Ejercicio B 32 | ^^^^^^^^^^^ 33 | 34 | - Definir un formulario en la clase Formulario usando QtDesigner. 35 | - En Formulario se darán de alta instrumentos en un negocio de instrumentos musicales. 36 | - Los instrumentos que se pueden cargar serán: guitarras, vientos y teclados. 37 | - Definir las clases Instrumento, Guitarra, Viento y Teclado. 38 | - Cada clase en sus correspondientes archivos .h y .cpp 39 | - Instrumento será una clase abstracta con la función virtual pura ``void afinar()`` 40 | - Que esa función virtual pura simplemente publique un texto por consola, por ejemplo "Afinando guitarra". 41 | - El formulario tendrá un botón que agregará un instrumento nuevo a un ``QVector< Instrumento * >`` 42 | - El formulario tendrá un QComboBox en el cual tendrá el siguiente listado: Guitarra, Viento y Teclado. 43 | - El formulario también tendrá un botón "Ver stock" que publicará por consola todos los instrumentos cargados. 44 | - Los Instrumentos tendrán los siguientes atributos: marca, precio, cantidad_de_cuerdas, cantidad_de_teclas, metal_usado. 45 | - Cuando en el QComboBox se seleccione Guitarra, se deberá permitir ingresar sólo la marca, el precio y la cantidad de cuerdas. 46 | 47 | 48 | Ejercicio C 49 | ^^^^^^^^^^^ 50 | 51 | - Usar la clase Manager para gestionar todas las ventanas de una nueva aplicación. 52 | - Usar un login (clase Login) que valide usuarios contra la tabla usuarios usando AdminDB. 53 | - Para el campo clave usar MD5. 54 | - La base de datos debe estar en el archivo base.sqlite 55 | - Login y AdminDB que sean singleton. 56 | - Cada clase en sus correspondientes archivos .h y .cpp 57 | - Cuando un usuario ingrese correctamente, mostrar una ventana vacía. 58 | 59 | 60 | Ejercicio D 61 | ^^^^^^^^^^^ 62 | 63 | - Crear una clase Lienzo que herede de QWidget, creado con QtDesigner y que permita dibujar con paintEvent. 64 | - Cuando se presiona la tecla A (Activar) se comenzará a dibujar cada posición en donde se encuentra el mouse. No depende de que se presione algún bóton del mouse para comenzar a dibujar. 65 | - Cuando se presiona la tecla D (Desactivar) se dejará de dibujar. 66 | - La clase Lienzo recibe una enumeración que puede ser: TrazoFino, TrazoMediano, TrazoGrueso que determinará el grosor de lo que se dibuja. 67 | - Dentro de Lienzo y ubicado abajo a la derecha, se ubicará un objeto de MiLabel, que hereda de QLabel, con una señal propia para detectar el click del mouse. 68 | - Cuando se presione este MiLabel, se borrará todo lo dibujado. 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /Desafios.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | 6 | Desafíos Qt para examen final 7 | ============================= 8 | 9 | 10 | `Lista de Youtube donde se encuentran los desafíos `_ 11 | 12 | 13 | Desafío 1 - `Login de usuarios `_ - Código `aquí `_ 14 | 15 | Desafío 2 - `Clase Botón `_ - Código `aquí `_ 16 | 17 | Desafío 3 - `Interfaz con Botón `_ - Código `aquí `_ 18 | 19 | Desafío 4 - `Imagen de internet `_ - Código `aquí `_ 20 | 21 | Desafío 5 - `Clase Manager `_ - Código `aquí `_ 22 | 23 | Desafío 6 - `Clase Figura `_ - Código `aquí `_ 24 | 25 | Desafío 7 - `AdminDB `_ - Código `aquí `_ 26 | 27 | Desafío 8 - `Clases `_ - Código `aquí `_ 28 | 29 | 30 | 31 | Temas téoricos/prácticos/oral para examen final 32 | =============================================== 33 | 34 | Temas 1 - ``namespace, inline, const`` 35 | 36 | Temas 2 - ``std, vector, string`` 37 | 38 | Temas 3 - ``Aritmética de punteros y Funciones genéricas`` 39 | 40 | Temas 4 - ``Clase, herencia, herencia múltiple, Polimorfismo`` 41 | 42 | Temas 5 - ``Funciones virtuales, funciones virtuales puras y Clases abstractas`` 43 | 44 | Temas 6 - ``Interfaz gráfica de usuario con Qt (widgets, layouts, slots, signals, etc.)`` 45 | 46 | Temas 7 - ``QPainter y captura de eventos del teclado y del mouse`` 47 | 48 | Temas 8 - ``Uso de las clases del módulo QtNetwork`` 49 | 50 | Temas 9 - ``QTimer y modificador friend`` 51 | 52 | Temas 10 - ``Creación de interfaces con QtDesigner`` 53 | 54 | 55 | 56 | ========== 57 | 58 | 59 | `Aquí la fórmula para el cálculo de la nota final `_ 60 | 61 | 62 | ========== 63 | 64 | Modalidad de examen final 65 | ------------------------- 66 | 67 | - La totalidad del examen se divide en el 50% para la sección Desafíos y el 50% para la parte Teórica/Práctica/Oral. 68 | - **Desafíos:** Al momento de iniciado el examen en el campus, el docente elije uno de los desafíos para que el/la estudiante lo replique de manera exacta, tal cual lo hace el docente en el video, es decir, que la funcionalidad de la aplicación tenga las mismas características y funcionalidades, y que la resolución sea confeccionada con los mismos recursos de programación. En la descripción de cada video se encuentra la explicación relacionada al tiempo en que se debe realizar el desafío. 69 | - **Teórico/Práctico/Oral:** El docente elige uno de los temas teóricos/prácticos/oral y el/la estudiante explica el tema con los recursos que desee. Se puede utilizar código preconfeccionado, programarlo en el momento a medida que explica el tema, puede utilizar el pizarrón o puede presentar con el proyector. El docente podrá realizar pedidos extras si considera que faltan cuestiones por cubrir. Se puede solicitar en el momento que se desarrolle alguna aplicación con un enunciado espontáneo. 70 | 71 | Alternativa para la entrega de desafíos 72 | ---------------------------------------- 73 | 74 | - El/la estudiante puede presentar todos los desafíos en videos en una lista de Youtube. Deben ser entregados 48 horas antes del inicio del examen. Se deben entregar todos los desafíos y sin sobrepasar el tiempo que se indica en la descripción de los videos. Los videos se pueden grabar con OBS, con la cámara visualizada, compartiendo la pantalla completa y explicando en voz alta lo que se va haciendo. Esta explicación oral es muy importante para la evaluación. 75 | -------------------------------------------------------------------------------- /Clase16.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 16 - POO 2024 6 | =================== 7 | (Fecha: 20 de mayo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ===================================================== 12 | 13 | `const 2021 `_ 14 | 15 | `QFile 2021 `_ 16 | 17 | 18 | const 19 | ===== 20 | 21 | - Una variable definida como const no podrá ser modificada a lo largo del programa (se crea como sólo lectura) 22 | - Se puede aplicar a cualquier tipo: 23 | 24 | .. code-block:: c 25 | 26 | const float pi = 3.14; 27 | const peso = 67; // Si no se indica el tipo entonces es int 28 | // Aunque sólo en compiladores viejos 29 | 30 | 31 | 32 | const con punteros 33 | ^^^^^^^^^^^^^^^^^^ 34 | 35 | .. code-block:: c 36 | 37 | int x = 10; 38 | int * px = &x; // normal 39 | 40 | const int y = 10; 41 | int * py = &y; // El compilador dirá: "invalid conversion from const int* 42 | // to int*". La inversa sí se permite 43 | 44 | int y = 10; 45 | const int * py = &y; // permitido (pero el contenido es de sólo lectura) 46 | 47 | *py = 6; // No permitido. El contenido apuntado es de sólo lectura 48 | 49 | 50 | const en parámetros de funciones 51 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 52 | 53 | - Cuando los parámetros son punteros, decimos que no podrá modificar los objetos referenciados 54 | 55 | .. code-block:: c 56 | 57 | int funcion( const char * ch ) 58 | 59 | 60 | - Lo mismo sucede con referencias 61 | 62 | .. code-block:: c 63 | 64 | int funcion( const char& ch ) 65 | 66 | 67 | const en clases 68 | ^^^^^^^^^^^^^^^ 69 | 70 | .. code-block:: c 71 | 72 | class ClaseA { 73 | const int i; 74 | int x; 75 | 76 | public: 77 | int funcion( ClaseA cA, const ClaseA &c ) { 78 | cA.x = 1; 79 | cA.i = 2; // No compila. i es de sólo lectura. 80 | c.x = 3; // No compila. El objeto c es de sólo lectura. 81 | 82 | return cA.x; 83 | } 84 | }; 85 | 86 | 87 | .. code-block:: c 88 | 89 | // A la variable i sólo la puede inicializar el constructor y sólo con la forma: 90 | ClaseA() : i( 8 ) { } 91 | 92 | // Si en el cuerpo del constructor se hace: 93 | ClaseA() { 94 | i = 8; // Compila? i es de solo lectura o no 95 | } 96 | 97 | 98 | - Aplicado a métodos de una clase no permite modificar ninguna propiedad de la clase 99 | 100 | .. code-block:: c 101 | 102 | class ClaseB { 103 | int x; 104 | 105 | void funcion( int i ) const { 106 | x = x + i; // Compila? 107 | } 108 | }; 109 | 110 | 111 | Clase QFile 112 | ^^^^^^^^^^^ 113 | 114 | - Permite leer y escribir en archivos. 115 | - Puede ser utilizado además con ``QTextStream`` o ``QDataStream``. 116 | 117 | .. code-block:: c 118 | 119 | QFile( const QString & name ) 120 | viod setFile( const QString & name ) 121 | 122 | - Existe un archivo? y lo eliminamos. 123 | 124 | .. code-block:: c 125 | 126 | bool exists() const 127 | bool remove() 128 | 129 | - Lectura de un archivo línea por línea: 130 | 131 | .. code-block:: c 132 | 133 | QFile file( "c:/in.txt" ); 134 | if ( !file.open ( QIODevice::ReadOnly | QIODevice::Text ) ) 135 | return; 136 | 137 | while ( !file.atEnd() ) { 138 | QByteArray linea = file.readLine(); 139 | qDebug() << linea; 140 | } 141 | 142 | 143 | 144 | Clase QFileDialog 145 | ================= 146 | 147 | - Permite abrir un cuadro de diálogo para buscar un archivo en disco 148 | 149 | .. code-block:: c 150 | 151 | QString file = QFileDialog::getOpenFileName( this, "Abrir", "./", "Imagen (*.png *.jpg)" ); 152 | 153 | 154 | Ejercicio 24: 155 | ============= 156 | 157 | - Crear un **parser** que pueda analizar cualquier html en busca de todas las URLs que encuentre 158 | - Crear una GUI que permita al usuario ingresar un sitio web en un QLineEdit 159 | - Que descargue en archivos todos los recursos de dicho sitio web 160 | - Es decir, que busque en el html las imágenes, los css, los javascript y los descargue en archivos 161 | - Que le permita al usuario indicar en qué directorio descargar los archivos 162 | - También agregar un botón que upermita elegir un archivo de imagen del disco con ``QFileDialog`` y que la dibuje en pantalla con paintEvent. 163 | 164 | 165 | Tareas adicionales: 166 | =================== 167 | 168 | - Revisión de entornos virtuales en sus computadoras 169 | - Instalación y funcionamiento de FastAPI y MongoDB 170 | - Utilización de Postman para consultar APIs 171 | - Probar consultas a APIs con el envío de credenciales de usuario, access token o similar 172 | - Probar, por ejemplo, con MercadoLibre, Instagram, Spotify 173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /Clase11.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 11 - POO 2024 6 | =================== 7 | (Fecha: 29 de abril) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Polimorfismo función virtual 2021 `_ 14 | 15 | `Polimorfismo - QtDesigner y métodos virtuales de QWidget 2023 `_ 16 | 17 | 18 | Vista obligatoria 19 | ^^^^^^^^^^^^^^^^^ 20 | 21 | `Funciones virtuales 2023 `_ 22 | 23 | 24 | Polimorfismo 25 | ============ 26 | 27 | - Lo utilizamos con punteros. 28 | - Nos permite acceder a objetos de la clase derivada usando un puntero a la clase base. 29 | - Sin embargo, sólo podemos acceder a datos y funciones que existan en la clase base. 30 | - Los datos y funciones propias de la derivada quedan inaccesibles. 31 | 32 | .. code-block:: 33 | 34 | class Persona { 35 | public: 36 | Persona( QString nombre ) : nombre( nombre ) { } 37 | QString verNombre() { return "Nombre: " + nombre; } 38 | 39 | protected: // Para acceso desde las clases derivadas 40 | QString nombre; 41 | }; 42 | 43 | class Empleado : public Persona { 44 | public: 45 | Empleado( QString nombre ) : Persona( nombre ) { } 46 | QString verNombre() { return "Empleado: " + nombre; } 47 | void mostrarAlgo() { qDebug() << "Algo"; } 48 | }; 49 | 50 | class Estudiante : public Persona { 51 | public: 52 | Estudiante( QString nombre ) : Persona( nombre ) { } 53 | QString verNombre() { return "Estudiante: " + nombre; } 54 | }; 55 | 56 | 57 | #include 58 | #include "persona.h" 59 | #include 60 | 61 | int main( int argc, char** argv ) { 62 | QApplication a(argc, argv); 63 | 64 | { 65 | Persona * jose = new Estudiante( "Jose" ); 66 | Persona * carlos = new Empleado( "Carlos" ); 67 | 68 | qDebug() << carlos->verNombre(); 69 | qDebug() << jose->verNombre(); 70 | carlos->mostrarAlgo(); // Muestra algo? 71 | 72 | delete jose; 73 | delete carlos; 74 | } 75 | 76 | return a.exec(); 77 | } 78 | 79 | 80 | 81 | Funciones virtuales 82 | =================== 83 | 84 | - Puede ser interesante llamar a la función de la derivada (en polimorfismo). 85 | - Al declarar una función como virtual en la clase base, si se superpone en la derivada, al invocar usando el puntero a la clase base, se ejecuta la versión de la derivada. 86 | 87 | .. code-block:: 88 | 89 | class Persona { 90 | public: 91 | Persona( QString nombre ) : nombre( nombre ) { } 92 | virtual QString verNombre() { return "Persona: " + nombre; } // Y si no fuera virtual? 93 | 94 | protected: 95 | QString nombre; 96 | }; 97 | 98 | class Empleado : public Persona { 99 | public: 100 | Empleado( QString nombre ) : Persona( nombre ) { } 101 | QString verNombre() { return "Empleado: " + nombre; } 102 | }; 103 | 104 | 105 | #include 106 | #include "personal.h" 107 | #include 108 | 109 | int main( int argc, char** argv ) { 110 | QApplication a( argc, argv) ; 111 | 112 | { 113 | Persona *carlos = new Empleado( "Carlos" ); 114 | 115 | qDebug() << carlos->verNombre(); // Qué publica? 116 | 117 | delete carlos; 118 | } 119 | 120 | return a.exec(); 121 | } 122 | 123 | 124 | 125 | 126 | Uso de Qt Designer 127 | ================== 128 | 129 | - Nuevo proyecto -> Qt Widgets Application 130 | - Utilizar el puntero ``ui`` para acceder a los objetos del diseño 131 | 132 | 133 | **Ejemplo** 134 | 135 | .. code-block:: 136 | 137 | // ventana.h 138 | #ifndef VENTANA_H 139 | #define VENTANA_H 140 | 141 | #include 142 | 143 | namespace Ui { 144 | class Ventana; 145 | } 146 | 147 | class Ventana : public QWidget { 148 | Q_OBJECT 149 | 150 | public: 151 | explicit Ventana( QWidget * parent = 0 ); 152 | ~Ventana(); 153 | 154 | private: 155 | Ui::Ventana *ui; 156 | }; 157 | 158 | #endif // VENTANA_H 159 | 160 | .. code-block:: 161 | 162 | // ventana.cpp 163 | #include "ventana.h" 164 | #include "ui_ventana.h" 165 | 166 | Ventana::Ventana( QWidget * parent ) : QWidget( parent ), ui( new Ui::Ventana ) { 167 | ui->setupUi( this ); 168 | } 169 | 170 | Ventana::~Ventana() { 171 | delete ui; 172 | } 173 | 174 | 175 | Métodos virtuales de QWidget para capturar eventos 176 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 177 | 178 | - Estos métodos pueden ser reimplementados en una clase derivada para recibir los eventos. 179 | 180 | .. code-block:: 181 | 182 | virtual void mouseDoubleClickEvent( QMouseEvent * event ); 183 | virtual void mouseMoveEvent( QMouseEvent * event ); 184 | virtual void mousePressEvent( QMouseEvent * event ); 185 | virtual void mouseReleaseEvent( QMouseEvent * event ); 186 | virtual void keyPressEvent( QKeyEvent * event ); 187 | virtual void keyReleaseEvent( QKeyEvent * event ); 188 | virtual void resizeEvent( QResizeEvent * event ); 189 | virtual void moveEvent( QMoveEvent * event ); 190 | virtual void closeEvent( QCloseEvent * event ); 191 | virtual void hideEvent( QHideEvent * event ); 192 | virtual void showEvent( QShowEvent * event ); 193 | virtual void paintEvent( QPaintEvent * event ); 194 | 195 | 196 | 197 | Ejercicio 19 198 | ============ 199 | 200 | - Crear una clase Pintura que herede de QWidget y que permita dibujar a mano alzada con el mouse. 201 | - Con el scroll permitirá ampliar y disminuir el tamaño del trazo del pincel. 202 | - Con las teclas R, G y B se cambia el color del pincel. 203 | - Con Escape se borra todo lo que esté dibujado. 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /Clase06.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 06 - POO 2024 6 | =================== 7 | (Fecha: 3 de abril) 8 | 9 | 10 | 11 | Registro en video de algunos temas de la clase de hoy 12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 | 14 | `QGroupBox - QString number 2021 `_ 15 | 16 | `webservice network QIODevice QUrl 2021 `_ 17 | 18 | `QNetworkAccessManager imagen de internet 2021 `_ 19 | 20 | 21 | 22 | 23 | QGroupBox 24 | ^^^^^^^^^ 25 | 26 | .. figure:: imagenes/qgroupbox.png 27 | 28 | .. code-block:: 29 | 30 | QGroupBox * grupo = new QGroupBox( "Texto" ); 31 | QGridLayout * layout = new QGridLayout; 32 | 33 | layout->addWidget( label, 0, 0 ); 34 | layout->addWidget( usuario, 1, 0, 1, 2 ); 35 | layout->addWidget( clave, 2, 0, 1, 2 ); 36 | 37 | grupo->setLayout( layout ); 38 | 39 | 40 | 41 | 42 | Web Service 43 | ^^^^^^^^^^^ 44 | 45 | - Para intercambiar datos entre aplicaciones 46 | - Generalmente a través del protocolo HTTP 47 | - La info puede viajar en XML, JSON, etc. 48 | - Fomenta y facilita el uso y desarrollo de APIs Web 49 | - https://es.wikipedia.org/wiki/Servicio_web 50 | 51 | **Algunas APIs disponibles** 52 | 53 | - Twitter - https://dev.twitter.com 54 | - Facebook - https://developers.facebook.com 55 | - Amazon - https://developer.amazonservices.es 56 | - Spotify - https://developer.spotify.com/web-api 57 | - MercadoLibre - http://developers.mercadolibre.com 58 | - Google - https://developers.google.com 59 | - Youtube 60 | - Traductor 61 | - Google+ 62 | - Maps 63 | - Street View 64 | 65 | QUrl 66 | ^^^^ 67 | 68 | - Para manipular una url ingresada por el usuario 69 | 70 | .. code-block:: 71 | 72 | // URL ejemplo: http://www.yahoo.com.ar/documento/info.html 73 | 74 | // El método path() devuelve /documento/info.html 75 | // El método host() devuelve www.yahoo.com.ar 76 | 77 | QUrl url( "http://www.yahoo.com.ar/documento/info.html" ); 78 | qDebug() << url.host(); 79 | qDebug() << url.path(); 80 | 81 | 82 | 83 | 84 | QByteArray 85 | ^^^^^^^^^^ 86 | 87 | - Se podría decir que es administrador de un char* 88 | - Se puede usar el operador [] 89 | - Almacena \\000 al final de cada objeto QByteArray 90 | 91 | 92 | 93 | 94 | Clase QNetworkAccessManager 95 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 96 | 97 | - Permite enviar y recibir solicitudes a la red 98 | - Se obtiene un objeto ``QNetworkReply`` con toda la información recibida 99 | 100 | .. code-block:: 101 | 102 | QNetworkAccessManager * manager = new QNetworkAccessManager; 103 | 104 | connect( manager, SIGNAL( finished( QNetworkReply * ) ), this, SLOT( slot_respuesta( QNetworkReply * ) ) ); 105 | 106 | manager->get( QNetworkRequest( QUrl( http://mi.ubp.edu.ar" ) ) ); 107 | 108 | - Para poder utilizar las clases de network hay que agregar en el .pro 109 | 110 | .. code-block:: 111 | 112 | QT += network // Esto agrega al proyecto el módulo network 113 | 114 | - Por defecto, el módulo 'gui' y el módulo 'core' están incluidos. 115 | - Para utilizar HTTPS, Qt utiliza OpenSSL https://www.openssl.org/source 116 | - Se puede descargar desde https://slproweb.com/products/Win32OpenSSL.html 117 | - Por ejemplo, para 64 bits elegir `Win64 OpenSSL v1.1.1w `_ 118 | 119 | Clase QIODevice 120 | ^^^^^^^^^^^^^^^ 121 | 122 | .. figure:: imagenes/qiodevice.png 123 | 124 | - Clase base de los dispositivos de I/O 125 | - Algunos métodos: 126 | 127 | .. code-block:: 128 | 129 | QByteArray readAll() // Lee todos los datos disponibles. 130 | QByteArray read( qint64 max ) // Lee hasta max datos disponibles. 131 | QByteArray readLine() // Lee una linea. 132 | 133 | 134 | 135 | Clase QNetworkReply 136 | ^^^^^^^^^^^^^^^^^^^ 137 | 138 | - Contiene los datos y encabezado de una respuesta 139 | - Una vez leídos los datos, ya no quedarán disponibles. 140 | - Para controlar los bytes que se van descargando usar la señal: 141 | 142 | .. code-block:: 143 | 144 | void downloadProgress( qint64 bytesRecibidos, qint64 bytesTotal ) 145 | 146 | 147 | Clase QNetworkRequest 148 | ^^^^^^^^^^^^^^^^^^^^^ 149 | 150 | - Contiene la información que se envían en la petición 151 | - Seteamos algún campo de la cabecera con: 152 | 153 | .. code-block:: 154 | 155 | void setRawHeader( const QByteArray &nombre, const QByteArray & valor ) 156 | 157 | QNetworkRequest request; 158 | request.setUrl( QUrl( ui->le->text() ) ); 159 | request.setRawHeader( "User-Agent", "MiNavegador 1.0" ); 160 | 161 | 162 | 163 | Clase QNetworkProxyFactory 164 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ 165 | 166 | - Permite configurar un servidor proxy a nuestra aplicación Qt. 167 | - Lo siguiente utiliza la configuración del sistema (Chrome y Edge, no Firefox, ¿Opera?, ¿Brave?). 168 | 169 | .. code-block:: 170 | 171 | #include 172 | #include "principal.h" 173 | #include 174 | 175 | int main( int argc, char ** argv ) { 176 | QApplication a( argc, argv ); 177 | 178 | QNetworkProxyFactory::setUseSystemConfiguration( true ); 179 | 180 | Principal w; 181 | w.showMaximized(); 182 | 183 | return a.exec(); 184 | } 185 | 186 | 187 | 188 | Algunas particularidades de QNetworkReply y QNetworkRequest 189 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 190 | 191 | - Para controlar los bytes que se van descargando se puede usar la señal de ``QNetworkReply``: 192 | 193 | .. code-block:: c 194 | 195 | void downloadProgress( qint64 bytesRecibidos, qint64 bytesTotal ) 196 | 197 | - Los campos de la cabecera HTTP se pueden setear con el método de ``QNetworkRequest``: 198 | 199 | .. code-block:: c 200 | 201 | void setRawHeader( const QByteArray & nombre, const QByteArray & valor ) 202 | 203 | QNetworkRequest request; 204 | request.setUrl( QUrl( this->le->text() ) ); 205 | request.setRawHeader( "User-Agent", "MiNavegador 1.0" ); 206 | -------------------------------------------------------------------------------- /Clase01.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 01 - POO 2024 6 | =================== 7 | (Fecha: 11 de marzo) 8 | 9 | 10 | Metodología didáctica 11 | ===================== 12 | 13 | - A continuación se resume el conjunto de estrategias, procedimientos y acciones para facilitar el aprendizaje y el logro de nuestros objetivos. 14 | 15 | :Teoría: 16 | - En la primer parte de cada clase se expondrán los contenidos teóricos. 17 | - Este contenido también está disponible en grabaciones de años anteriores, cuyos links se colocarán a medida que se avance en las clases. 18 | 19 | :Práctica: 20 | - La segunda parte de cada clase estará destinado a la resolución de ejercicios e incorporación de esos contenidos. 21 | 22 | :Regularidad, promoción y examen final: 23 | - Primer y segundo parcial: Problema para resolver en 2 horas 24 | - La materia se promociona bajo la modalidad de la UBP. 25 | - El examen final sigue `esta modalidad `_ . 26 | 27 | 28 | Registro en video de algunos temas de la clase de hoy 29 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 30 | 31 | `Library, Librería, Biblioteca 2021 `_ 32 | 33 | `std C y std C++ 2021 `_ 34 | 35 | `Espacio de nombres 2021 `_ 36 | 37 | 38 | Instalación de herramientas 39 | =========================== 40 | 41 | :QtCreator: 42 | - Si hay instaladas versiones anteriores de Qt, desinstalarlas con C:\\Qt\\MaintenanceTool.exe y tildando Uninstall only 43 | - Se recomienda este instalador Offline: `https://download.qt.io/archive/qt/5.14/5.14.1 `_ 44 | - Importante la instalación de: 'Biblioteca Qt 5.14.1' 'Qt Creator' 'MinGW 7.3.0 64-bit' 45 | 46 | :OpenSSL: 47 | - Descargar instalador desde la `Página de descarga `_ 48 | - Seleccionar el instalador `Win64 OpenSSL v3.1.0 `_ 49 | 50 | 51 | Biblioteca estándar de C++ 52 | ========================== 53 | 54 | - Está en el espacio de nombres ``std`` 55 | - En la biblioteca estándar de C, los archivos de cabecera X.h se reemplazan por cX o X. Por ejemplo: 56 | 57 | .. code-block:: 58 | 59 | #include #include 60 | 61 | int atoi( const char * ) // Convierte a int un número expresado en cadena 62 | int abs( int ) // Devuleve el valor absoluto 63 | int rand() // Devuelve un número pseudo aleatorio entre 0 y 32767 64 | 65 | 66 | #include #include 67 | 68 | // Borra un archivo. Devuelve 0 o un código de error. 69 | int remove( const char * filename ) 70 | 71 | // Imprime por pantalla. Recibe un número indefinido de argumentos. 72 | int printf( const char * format, ... ) 73 | 74 | #include #include 75 | 76 | cout 77 | cin 78 | endl 79 | 80 | 81 | 82 | 83 | Espacio de nombres (namespace) 84 | ============================== 85 | 86 | - Permite agrupar declaraciones (de clases, funciones, etc.). 87 | - Permite declarar identificadores (nombre de variables) sin que se solapen. Es decir, identificadores iguales en distinto namespace. 88 | - Se pueden incluir las definiciones en un namespace pero mejor no. 89 | - Un espacio de nombre es un ámbito. 90 | 91 | Ejemplos con namespace 92 | ====================== 93 | 94 | **Ejemplo 1** 95 | 96 | .. code-block:: 97 | 98 | #include 99 | using namespace std; 100 | 101 | namespace enteros { 102 | int var1 = 5; 103 | int var2 = 7; 104 | } 105 | 106 | namespace con_decimales { 107 | float var1 = 5.14; 108 | float var2 = 7.13; 109 | } 110 | 111 | int main() { 112 | cout << enteros::var1 << endl; 113 | cout << con_decimales::var1 << endl; 114 | return 0; 115 | } 116 | 117 | - ¿Cuál es la salida por consola? 118 | 119 | .. .. 120 | 121 | 124 | 125 | **Ejemplo 2** 126 | 127 | .. code-block:: 128 | 129 | #include 130 | using namespace std; 131 | 132 | namespace enteros { 133 | int var1 = 5; 134 | int var2 = 7; 135 | } 136 | 137 | namespace con_decimales { 138 | float var1 = 5.14; 139 | float var2 = 7.13; 140 | } 141 | 142 | int main() { 143 | using enteros::var1; 144 | using con_decimales::var2; 145 | 146 | cout << var1 << endl; 147 | cout << var2 << endl; 148 | cout << enteros::var2 << endl; 149 | cout << con_decimales::var1 << endl; 150 | 151 | return 0; 152 | } 153 | 154 | .. .. 155 | 156 | 159 | 160 | **Ejemplo 3** 161 | 162 | .. code-block:: 163 | 164 | #include 165 | using namespace std; 166 | 167 | namespace enteros { 168 | int var1 = 5; 169 | int var2 = 7; 170 | } 171 | 172 | namespace con_decimales { 173 | float var1 = 5.14; 174 | float var2 = 7.13; 175 | } 176 | 177 | int main() { 178 | using namespace enteros; 179 | 180 | cout << var1 << endl; 181 | cout << var2 << endl; 182 | cout << con_decimales::var1 << endl; 183 | cout << con_decimales::var2 << endl; 184 | 185 | return 0; 186 | } 187 | 188 | .. .. 189 | 190 | 193 | 194 | **Ejemplo 4** 195 | 196 | .. code-block:: 197 | 198 | #include 199 | using namespace std; 200 | 201 | namespace enteros { 202 | int var1 = 5; 203 | int var2 = 7; 204 | } 205 | 206 | namespace con_decimales { 207 | float var1 = 5.14; 208 | float var2 = 7.13; 209 | } 210 | 211 | int main() { 212 | { 213 | using namespace enteros; 214 | cout << var1 << endl; 215 | } 216 | 217 | { 218 | using namespace con_decimales; 219 | cout << var1 << endl; 220 | } 221 | 222 | return 0; 223 | } 224 | 225 | .. .. 226 | 227 | 230 | -------------------------------------------------------------------------------- /Clase05.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 05 - POO 2024 6 | =================== 7 | (Fecha: 25 de marzo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Help signal slot QSlider QSpinBox 2021 `_ 14 | 15 | `QGridLayout - Q_OBJECT - Archivos del Qt Project 2021 `_ 16 | 17 | `Dibujar a mano - QByteArray - Preprocesador 2021 `_ 18 | 19 | 20 | Signals y slots 21 | =============== 22 | 23 | - signal y slot son funciones. 24 | - Las signals de una clase se comunican con los slots de otra. 25 | - Se deben conectar con la función connect de QObject. 26 | - Un evento puede generar una signal. 27 | - Los slots reciben estas signals. 28 | - SIGNAL() y SLOT() son macros (convierten a cadena). 29 | - emisor y receptor son punteros a QObject 30 | 31 | .. code-block:: 32 | 33 | QObject::connect( emisor, SIGNAL( signal ), receptor, SLOT( slot ) ); 34 | 35 | 36 | - Se puede remover la conexión: 37 | 38 | .. code-block:: 39 | 40 | QObject::disconnect( emisor, SIGNAL( signal ), receptor, SLOT( slot ) ); 41 | 42 | **Ejemplo:** QPushButton para cerrar la aplicación. 43 | 44 | .. code-block:: 45 | 46 | #include 47 | #include 48 | 49 | int main( int argc, char** argv ) { 50 | QApplication a( argc, argv ); 51 | QPushButton* boton = new QPushButton( "Salir" ); 52 | 53 | QObject::connect( boton, SIGNAL( pressed() ), &a, SLOT( quit() ) ); 54 | boton->setVisible( true ); 55 | 56 | return a.exec(); 57 | } 58 | 59 | Macro Q_OBJECT 60 | ^^^^^^^^^^^^^^ 61 | 62 | - Convierte a una clase cualquiera en una clase Qt. 63 | - Una clase Qt permitirá trabajar con signals y slots. 64 | - Incluir la macro Q_OBJECT en la primer línea de la definición de la clase. 65 | 66 | 67 | **Ejemplo:** Control de volumen 68 | 69 | .. code-block:: 70 | 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | 77 | int main( int argc, char** argv ) { 78 | QApplication a( argc, argv ); 79 | 80 | QWidget * ventana = new QWidget; // Es la ventana padre (principal) 81 | ventana->setWindowTitle( "Volumen" ); 82 | ventana->resize( 300, 50 ); 83 | 84 | QSpinBox * spinBox = new QSpinBox; 85 | QSlider * slider = new QSlider( Qt::Horizontal ); 86 | spinBox->setRange( 0, 100 ); 87 | slider->setRange( 0, 100 ); 88 | 89 | QObject::connect( spinBox, SIGNAL( valueChanged( int ) ), slider, SLOT( setValue( int ) ) ); 90 | QObject::connect( slider, SIGNAL( valueChanged( int ) ), spinBox, SLOT( setValue( int ) ) ); 91 | 92 | spinBox->setValue( 15 ); 93 | 94 | QHBoxLayout * layout = new QHBoxLayout; 95 | layout->addWidget( spinBox ); 96 | layout->addWidget( slider ); 97 | ventana->setLayout( layout ); 98 | ventana->setVisible( true ); 99 | 100 | return a.exec(); 101 | } 102 | 103 | 104 | 105 | QGridLayout 106 | ^^^^^^^^^^^ 107 | 108 | - Ubica los widgets en una grilla 109 | - Con setColumnMinimumWidth() podemos setear el ancho mínimo de columna 110 | - Separación entre widget con setVerticalSpacing( int ) 111 | - void addWidget( QWidget * widget, int fila, int columna, int spanFila, int spanCol ) 112 | 113 | 114 | 115 | QLineEdit 116 | ^^^^^^^^^ 117 | 118 | .. code-block:: 119 | 120 | QLineEdit * le = new QLineEdit; 121 | le->setEchoMode( QLineEdit::Password ); 122 | le->setEnabled( false ); 123 | 124 | // QLineEdit::Normal // Se visualizan al escribir 125 | // QLineEdit::NoEcho // No se visualiza nada 126 | // QLineEdit::Password // Se escribe como asteriscos 127 | // QLineEdit::PasswordEchoOnEdit // Se escribe normal y al dejar de editar se convierten en asteriscos 128 | 129 | **Señales** 130 | 131 | .. code-block:: 132 | 133 | // void returnPressed() // Detecta cuando el usuario presiona Enter. 134 | 135 | // void editingFinished() // Cuando pierde foco. 136 | 137 | // void textChanged( const QString & text ) // Texto modificado por código o por usuario desde la gui. 138 | 139 | // void textEdited( const QString & text ) // Sólo por el usuario. 140 | 141 | 142 | 143 | Dibujar a mano sobre un QWidget 144 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 145 | 146 | .. code-block:: 147 | 148 | // mapa.h 149 | #include 150 | 151 | class Mapa : public QWidget { 152 | Q_OBJECT 153 | 154 | public: 155 | Mapa() { } 156 | 157 | protected: 158 | void paintEvent( QPaintEvent * ); 159 | 160 | }; 161 | 162 | // mapa.cpp 163 | #include "mapa.h" 164 | #include 165 | 166 | void Mapa::paintEvent( QPaintEvent * ) { 167 | QPainter painter( this ); 168 | painter.drawLine( 0, 0, this->width(), this->height() ); 169 | } 170 | 171 | **Clase QPainter** 172 | 173 | - Pinta a bajo nivel sobre widgets. 174 | - Debe ser utilizado dentro del método ``paintEvent( QPaintEvent * )``. 175 | 176 | .. code-block:: 177 | 178 | void drawEllipse( int x, int y, int ancho, int alto ); 179 | void drawImage( int x, int y, QImage & image ); 180 | void drawLine( int x1, int y1, int x2, int y2 ); 181 | void drawText( int x, int y, QString & text ); 182 | void fillRect( int x, int y, int ancho, int alto ); 183 | 184 | 185 | 186 | Ejercicio 13 187 | ============ 188 | 189 | - Punto de partida: Usar el código del ejemplo del control de volumen 190 | - Cuando el valor del QSlider se modifique, colocar como título de la ventana el mismo valor que tiene el QSlider. 191 | 192 | 193 | Ejercicio 14 194 | ============ 195 | 196 | - Diseñar un login con QGridLayout. 197 | - Usar asteriscos para la clave. 198 | - Detectar enter para simular la pulsación del botón. 199 | - Definir la clase Formulario que será un QWidget 200 | - Formulario tendrá QLabels y QLineEdits para Legajo, Nombre y Apellido, y un QPushButton 201 | - Si la clave ingresada es admin:1111, se cierra Login y se muestra Formulario 202 | - Si se ingresa otra clave se borrará el texto del QLineEdit de la clave. 203 | 204 | 205 | Ejercicio 15 206 | ============ 207 | 208 | .. figure:: imagenes/ejercicio_captcha.jpg 209 | 210 | 211 | Ejercicio 16 212 | ============ 213 | 214 | - Registrar en MongoDB algunos usuarios (nombre, apellido, usuario, clave) 215 | - Tener disponible un endpoint con FastAPI para validar usuarios. 216 | 217 | 218 | 219 | 220 | 221 | -------------------------------------------------------------------------------- /Clase14.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 14 - POO 2024 6 | =================== 7 | (Fecha: 13 de mayo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ===================================================== 12 | 13 | `Incorporación de enum a Login 2024 `_ 14 | 15 | `Enum - Manager - QtDesigner con clase propia - signals propias 2023 `_ 16 | 17 | `Enumeraciones - https://youtu.be/pD5sbMKiGSM `_ 18 | 19 | `QTimer - https://youtu.be/3flYMoF0mNU `_ 20 | 21 | `logs y QTimer 2021 `_ 22 | 23 | `Manager 2022 - https://youtu.be/smkrsoyeB68 `_ 24 | 25 | 26 | 27 | Enumeraciones 28 | ============= 29 | 30 | - Es un tipo especial de variable 31 | - Sus valores son constantes enteras 32 | - Estos valores pueden ser autogenerados (0, 1, 2, 3, ...) 33 | 34 | .. code-block:: c 35 | 36 | enum los_dias { DOM, LUN, MAR, MIE, JUE, VIE, SAB } dia; 37 | 38 | enum los_dias { DOM = 7, LUN = 1, MAR, MIE, JUE = 0, VIE, SAB }; 39 | 40 | - Las variables de este tipo pueden adoptar sólo valores DOM, LUN, ... 41 | - Es decir, la variable "dia" puede tomar DOM o LUN o MAR ... 42 | - Las enumeraciones declaradas dentro de una clase tiene la visibilidad de la clase 43 | 44 | .. code-block:: c 45 | 46 | class Dia { 47 | public: 48 | enum los_dias { LUN, MAR, MIE, JUE, VIE }; 49 | int un_dia; 50 | }; 51 | 52 | int main( int argc, char ** argv ) { 53 | Dia d1; 54 | d1.un_dia = Dia::LUN; 55 | } 56 | 57 | 58 | **Ejemplo** 59 | 60 | .. code-block:: c 61 | 62 | // figura.h 63 | class Figura : public QWidget { 64 | Q_OBJECT 65 | 66 | public: 67 | enum Forma { CIRCULO, CUADRADO }; 68 | 69 | Figura( QWidget * parent = 0 ); 70 | 71 | void dibujar( Forma forma ); 72 | 73 | protected: 74 | void paintEvent( QPaintEvent * ); 75 | 76 | private: 77 | Forma forma; 78 | }; 79 | 80 | 81 | // figura.cpp 82 | Figura::Figura( QWidget * parent ) : QWidget( parent ), forma( CIRCULO ) { } 83 | 84 | void Figura::dibujar( Forma forma ) { 85 | this->forma = forma; 86 | this->repaint(); 87 | } 88 | 89 | void Figura::paintEvent( QPaintEvent * ) { 90 | QPainter pincel( this ); 91 | 92 | switch( forma ) { 93 | case CIRCULO: 94 | // dibujar circulo 95 | break; 96 | 97 | case CUADRADO: 98 | // dibujar cuadrado 99 | break; 100 | 101 | default:; 102 | } 103 | } 104 | 105 | // main.cpp 106 | int main( int argc, char ** argv ) { 107 | QApplication a( argc, argv ); 108 | 109 | Figura figura; 110 | figura.dibujar( Figura::CUADRADO ); 111 | figura.show(); 112 | 113 | return a.exec(); 114 | } 115 | 116 | 117 | 118 | 119 | Clase QTimer 120 | ^^^^^^^^^^^^ 121 | 122 | - Permite programar tareas de una sola ejecución o tareas repetitivas. 123 | - Conectamos la señal ``timeout()`` con algún slot. 124 | - Con ``start()`` comenzamos y la señal ``timeout()`` se emitirá al terminar. 125 | 126 | 127 | **Ejemplo (repetitivo):** Temporizador que cada 1000 mseg llamará a ``slot_update()`` 128 | 129 | 130 | .. code-block:: c 131 | 132 | QTimer * timer = new QTimer( this ); 133 | connect( timer, SIGNAL( timeout() ), this, SLOT( slot_update() ) ); 134 | timer->start( 1000 ); 135 | 136 | 137 | **Para una sola ejecución** 138 | 139 | - Para temporizador de una sola ejecución usar ``setSingleShot(true)`` 140 | - El método estático ``QTimer::singleShot()`` nos permite la ejecución. 141 | 142 | 143 | **Ejemplo:** Luego de 200 mseg se llamará a ``slot_update()``: 144 | 145 | 146 | .. code-block:: c 147 | 148 | QTimer::singleShot( 200, this, SLOT( slot_update() ) ); 149 | // donde this es el objeto que tiene definido el slot_update(). 150 | 151 | 152 | Uso de una clase propia con QtDesigner 153 | ====================================== 154 | 155 | - Deben heredar de algún QWidget 156 | - Colocamos el widget (clase base) con QtDesigner 157 | - Clic derecho "Promote to" 158 | 159 | .. figure:: imagenes/qtdesigner.png 160 | 161 | - Base class name: QLabel 162 | - Promoted class name: MiLabel 163 | - Header file: miLabel.h 164 | - Add (y con esto queda disponible para promover) 165 | - La clase MiLabel deberá heredar de QLabel 166 | - El constructor debe tener como parámetro: 167 | 168 | 169 | .. code-block:: 170 | 171 | MiLabel( QWidget * parent = 0 ); // Esto en miLabel.h 172 | 173 | MiLabel::MiLabel( QWidget * parent ) : QLabel( parent ) { // Esto en miLabel.cpp 174 | 175 | } 176 | 177 | 178 | 179 | Clase Manager 180 | ============= 181 | 182 | - Encargada de administrar las conexiones principales y la visualización de todas las ventanas de la aplicación 183 | 184 | 185 | Ejercicio 20: 186 | ============= 187 | 188 | - Crear un proyecto Qt Widget Application con un QWidget que sea la clase Ventana 189 | - Crear una clase Boton que hereda de QWidget 190 | - Redefinir paintEvent en Boton y usar fillRect para dibujarlo de algún color 191 | - Definir el siguiente método en Boton: 192 | 193 | .. code-block:: c 194 | 195 | Boton * boton = new Boton; 196 | boton->colorear( Boton::Azul ); 197 | 198 | // Este método recibe como parámetro una enumeración que puede ser: 199 | // Boton::Azul Boton::Verde Boton::Magenta 200 | 201 | - Usar QtDesigner para Ventana y Boton. Es decir, Designer Form Class 202 | - Definir la enumeración en Boton 203 | - Abrir el designer de Ventana y agregar 5 botones (objetos de la clase Boton). Promocionarlos 204 | - Que esta Ventana con botones quede lo más parecido a la siguiente imagen: 205 | 206 | .. figure:: imagenes/botones.png 207 | 208 | - Usar para Ventana grid layout, usar espaciadores y usar todos los recursos posibles del QtDesigner 209 | - Dibujar un fondo agradable con paintEvent y drawImage 210 | - Que Boton tenga la señal signal_clic() 211 | 212 | 213 | 214 | Ejercicio 21: 215 | ============= 216 | 217 | - Definir dos QWidgets (una clase Login y una clase Ventana). 218 | - El Login validará al usuario contra una base SQLite 219 | - La Ventana sólo mostrará un QPushButton para "Volver" al login. 220 | - Crear solamente un objeto de Ventana y uno solo de Login. 221 | - Si sucede un problema en la compilación, analizar los motivos (respetar el enunciado). 222 | - Solucionar ese problema y ver la alternativa de hacerlo con Manager. 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | -------------------------------------------------------------------------------- /Clase07.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 07 - POO 2024 6 | =================== 7 | (Fecha: 8 de abril) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Sutileza con punteros - octal - arrays como parámetros 2021 `_ 14 | 15 | `QNetworkAccessManager y colocar imagen en login 2023 `_ 16 | 17 | `Login con imagen generando código con el chat 2024 `_ 18 | 19 | 20 | 21 | 22 | 23 | 24 | Sutilezas con punteros 25 | ^^^^^^^^^^^^^^^^^^^^^^ 26 | 27 | .. code-block:: 28 | 29 | char cadena[ 10 ] = "hola"; 30 | // Funciona? sí. Qué hace con el sobrante? 31 | // Los completa a todos con \000 32 | 33 | char cadena[ 4 ] = "hola"; // Por qué no compila? 34 | 35 | char cadena[ 5 ] = "hola"; // Y por qué esto sí compila? 36 | 37 | // Porque la última posición se usa para el carácter nulo que el 38 | // compilador lo agrega (si tiene lugar). 39 | 40 | // \000 (octal) 41 | // \x0 (hexadecimal) 42 | 43 | Usando puntero para cadenas 44 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 45 | 46 | .. code-block:: 47 | 48 | char * cadena = "hola"; // el compilador agrega \000 49 | char * cadena = "ho\000la"; // Imprime ho 50 | 51 | - Asignamos memoria dinámicamente. 52 | - No necesitamos especificar la longitud máxima. 53 | 54 | Notación octal y hexadecimal 55 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 56 | 57 | .. code-block:: 58 | 59 | cout << 3 + 4 + 11; // Imprime 18 60 | cout << 3 + 4 + 011; // ? 61 | 62 | // octal hexadecimal decimal 63 | // 0121 0x51 81 64 | // 011 0x9 9 65 | // '\000' '\x0' nulo 66 | // '\063' '\x33' carácter 3 67 | 68 | 69 | 70 | Punteros a punteros 71 | ^^^^^^^^^^^^^^^^^^^ 72 | 73 | .. code-block:: 74 | 75 | char cadena[ 2 ][ 3 ]; 76 | cadena[ 0 ][ 0 ] = 'f'; 77 | cadena[ 0 ][ 1 ] = 'u'; 78 | cadena[ 0 ][ 2 ] = 'e'; 79 | cadena[ 1 ][ 0 ] = 'f'; 80 | cadena[ 1 ][ 1 ] = 'u'; 81 | cadena[ 1 ][ 2 ] = 'i'; 82 | 83 | // Mejor así 84 | 85 | char cadena[ 2 ][ 3 ]; 86 | cadena[ 0 ][ 0 ] = 's'; 87 | cadena[ 0 ][ 1 ] = 'i'; 88 | cadena[ 0 ][ 2 ] = '\000'; 89 | cadena[ 1 ][ 0 ] = 'n'; 90 | cadena[ 1 ][ 1 ] = 'o'; 91 | cadena[ 1 ][ 2 ] = '\000'; 92 | 93 | Array ≡ puntero 94 | ^^^^^^^^^^^^^^^ 95 | 96 | - Cuando declaramos un array 97 | - Estamos declarando un puntero al primer elemento. 98 | 99 | .. code-block:: 100 | 101 | char arreglo[ 5 ]; 102 | char * puntero; 103 | puntero = arreglo; // Equivale a puntero = &arreglo[ 0 ]; 104 | 105 | Volviendo a puntero a puntero 106 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 107 | 108 | .. code-block:: 109 | 110 | char cadena[ 2 ][ 3 ] = { { 's', 'i', '\000' }, { 'n', 'o', '\000' } }; 111 | // Y si fuera char cadena[ 2 ][ 3 ] = { { 's', 'i', '-' }, { 'n', 'o', '\000' } }; 112 | char * p1; 113 | char * p2; 114 | 115 | p1 = cadena[ 0 ]; // p1 = &cadena[ 0 ][ 0 ]; 116 | p2 = cadena[ 1 ]; // p2 = &cadena[ 1 ][ 0 ]; 117 | 118 | cout << p1; // si 119 | cout << p2; // no 120 | 121 | cout << *p1; // ? 122 | cout << *p2; // ? 123 | 124 | // Es decir: 125 | // El identificador de un arreglo unidimensional 126 | // es considerado un puntero a su primer elemento. 127 | 128 | **Ejemplo** 129 | 130 | .. code-block:: 131 | 132 | char p1[] = { 'a', 'b', 'c', 'd', 'e' }; 133 | cout << "Letra " << *p1; // Letra a 134 | cout << "Letra " << p1[ 0 ]; // Letra a 135 | 136 | char m2[][ 5 ] = { { 'a', 'b', 'c', 'd', 'e' }, { 'A', 'B', 'C', 'D', 'E' } }; 137 | cout << "Letra " << **m2; // Letra a 138 | cout << "Letra " << m2[ 0 ][ 0 ]; // Letra a 139 | cout << "Letra " << m2[ 1 ][ 3 ]; // Letra D 140 | cout << "Letra " << *( *( m2 + 1 ) + 3 ); // Letra D 141 | 142 | **Extendiendo a arreglos de cualquier dimensión** 143 | 144 | .. code-block:: 145 | 146 | m[ a ] == *( m + a ) 147 | m[ a ][ b ] == *( *( m + a ) + b ) 148 | m[ a ][ b ][ c ] == *( *( *( m + a ) + b ) + c ) 149 | 150 | // Si nos referimos al primer elemento 151 | 152 | m[ 0 ] == *m 153 | m[ 0 ][ 0 ] == **m 154 | m[ 0 ][ 0 ][ 0 ] == ***m 155 | 156 | 157 | 158 | Parámetros desde la línea de comandos 159 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 160 | 161 | - Escribir el siguiente programa y ejecutarlo desde la línea de comandos para ver el uso de estos parámetros: 162 | 163 | .. code-block:: 164 | 165 | #include 166 | 167 | int main( int argc, char ** argv ) { 168 | std::cout << "Hay " << argc << " argumentos:" << std::endl; 169 | for ( int i = 0 ; i < argc ; ++i ) { 170 | std::cout << argv[ i ] << std::endl; 171 | } 172 | } 173 | 174 | 175 | 176 | Obtener una imagen desde internet 177 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 178 | 179 | .. code-block:: 180 | 181 | void Principal::slot_descargaFinalizada( QNetworkReply * reply ) { 182 | QImage image = QImage::fromData( reply->readAll() ); 183 | } 184 | 185 | 186 | 187 | Ejercicio 14 (continuación): 188 | ============================ 189 | 190 | - Publicar en la ventana de Login, la temperatura actual en la Ciudad de Córdoba. Usar alguna API disponible. 191 | - Agregar un método en Login que permita mostrar u ocultar la información de la temperatura. 192 | - Además que la ventana de Login tenga como background una imagen descargada de interner, centrada y adaptada en tamaño, sin deformar su aspecto y que permita al usuario que modifique el tamaño del Login y que se siga viendo correctamente la imagen. 193 | - Agregar un método en Login que permita indicar la URL de la imagen que se mostrará en el background. En caso que nunca se invoque a este método, ninguna imagen se mostrará. 194 | 195 | 196 | Ejercicio 16 (continuación): 197 | ============================ 198 | 199 | - Que el endpoint para validar a los usuarios sea con un POST y que devuelva "denegado" o que devuelva el nombre y el apellido del usuario en el siguiente formato: "Juan Carlos::Ponce" 200 | - Probar el funcionamiento de este endpoint mediante la web de prueba de FastAPI. 201 | 202 | 203 | 204 | Ejercicio 17 205 | ============ 206 | 207 | - Diseñar un login que cargue como fondo, una imagen descargada de internet 208 | - Cuando un usuario sea válido, que se abra en full screen otra ventana (definida en la clase Ventana) y que tenga otra imagen descargada de internet en su interior, abarcando toda la ventana. 209 | - Esta ventana no deberá abrirse hasta tanto se haya descargado la imagen. 210 | - La imagen no se debe deformar al visualizarse. 211 | 212 | 213 | Aclaraciones 214 | ============ 215 | 216 | - Acondicionar la publicación de los ejercicios en el GitHub de manera que puedan ser explorados fácilmente. 217 | - Colocar el enunciado de cada ejercicio para una cómoda exploración. 218 | -------------------------------------------------------------------------------- /Clase13.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 13 - POO 2024 6 | =================== 7 | (Fecha: 8 de mayo) 8 | 9 | 10 | 11 | Registro en video de algunos temas de la clase de hoy 12 | ===================================================== 13 | 14 | 15 | `MD5 - AdminDB mostrarTabla - signals propias 2023 `_ 16 | 17 | `MD5 e independizar del SO 2021 `_ 18 | 19 | `Práctica con MD5 y base de datos 2021 `_ 20 | 21 | `Señales propias 2022 `_ 22 | 23 | 24 | 25 | Clase QCryptographicHash 26 | ^^^^^^^^^^^^^^^^^^^^^^^^ 27 | 28 | - Provee la generación de la clave hash 29 | - Soporta MD5, MD4 y SHA-1 30 | 31 | .. code-block:: c 32 | 33 | enum Algorithm { Md4, Md5, Sha1 } 34 | 35 | QCryptographicHash(Algorithm metodo) 36 | 37 | void addData(const QByteArray & data) 38 | 39 | void reset() 40 | 41 | QByteArray result() const 42 | 43 | 44 | **Método estático** 45 | 46 | .. code-block:: c 47 | 48 | QByteArray hash( const QByteArray & data, Algorithm metodo ) 49 | 50 | 51 | **Otros métodos útiles** 52 | 53 | .. code-block:: c 54 | 55 | QByteArray QByteArray::toHex() 56 | // Devuelve en hexadecimal 57 | // Útil para enviar por url una clave hash MD5 58 | // Hexadecimal tiene sólo caracteres válidos para URL 59 | 60 | **Ejemplo**: Obtener MD5 de la clave ingresada en un QlineEdit: 61 | 62 | .. code-block:: c 63 | 64 | QcryptographicHash::hash( leClave->text().toUtf8(), QCryptographicHash::Md5 ).toHex() 65 | 66 | 67 | 68 | **Calculadora MD5 online** 69 | 70 | http://www.md5.cz/ 71 | 72 | 73 | 74 | **Para independizar del SO** 75 | 76 | .. code-block:: c 77 | 78 | AdminDB adminDB; 79 | QString nombreSqlite; 80 | 81 | #ifdef __APPLE__ 82 | nombreSqlite = "/home/cosimani/db/test"; 83 | #elif __WIN32__ 84 | nombreSqlite = "C:/Qt/db/test"; 85 | #elif __linux__ 86 | nombreSqlite = "/home/cosimani/db/test"; 87 | #else 88 | nombreSqlite = "/home/cosimani/db/test"; 89 | #endif 90 | 91 | if ( adminDB.conectar( nombreSqlite ) ) 92 | qDebug() << "Conexion exitosa"; 93 | 94 | 95 | **Algunas explicaciones sobre base de datos** 96 | 97 | 98 | - `Crear base de datos `_ 99 | 100 | - `Crear tabla `_ 101 | 102 | - `Insertar registro `_ 103 | 104 | - `Consultar datos `_ 105 | 106 | 107 | **Ejemplo de método mostrarTabla para la clase AdminDB** 108 | 109 | .. code-block:: c 110 | 111 | #ifndef ADMINDB_H 112 | #define ADMINDB_H 113 | 114 | #include 115 | #include 116 | 117 | class AdminDB : public QObject 118 | { 119 | Q_OBJECT 120 | public: 121 | explicit AdminDB( QObject * parent = 0 ); 122 | ~AdminDB(); 123 | 124 | bool conectar( QString archivoSqlite ); 125 | QSqlDatabase getDB(); 126 | bool isConnected(); 127 | void mostrarTabla( QString tabla ); 128 | 129 | private: 130 | QSqlDatabase db; 131 | }; 132 | 133 | #endif // ADMINDB_H 134 | 135 | 136 | .. code-block:: c 137 | 138 | #include "admindb.h" 139 | #include 140 | #include 141 | #include 142 | 143 | AdminDB::AdminDB( QObject * parent ) : QObject( parent ) { 144 | qDebug() << "Drivers disponibles:" << QSqlDatabase::drivers(); 145 | 146 | db = QSqlDatabase::addDatabase( "QSQLITE" ); 147 | } 148 | 149 | AdminDB::~AdminDB() { 150 | if ( db.isOpen() ) 151 | db.close(); 152 | } 153 | 154 | bool AdminDB::conectar( QString archivoSqlite ) { 155 | db.setDatabaseName( archivoSqlite ); 156 | 157 | return db.open(); 158 | } 159 | 160 | QSqlDatabase AdminDB::getDB() { 161 | return db; 162 | } 163 | 164 | bool AdminDB::isConnected() { 165 | return db.isOpen(); 166 | } 167 | 168 | void AdminDB::mostrarTabla( QString tabla ) { 169 | if ( this->isConnected() ) { 170 | QSqlQuery query = db.exec( "SELECT * FROM " + tabla ); 171 | 172 | if ( query.size() == 0 || query.size() == -1 ) 173 | qDebug() << "La consulta no trajo registros"; 174 | 175 | while( query.next() ) { 176 | QSqlRecord registro = query.record(); // Devuelve un objeto que maneja un registro (linea, row) 177 | int campos = registro.count(); // Devuleve la cantidad de campos de este registro 178 | 179 | QString informacion; // En este QString se va armando la cadena para mostrar cada registro 180 | for ( int i = 0 ; i < campos ; i++ ) { 181 | informacion += registro.fieldName( i ) + ":"; // Devuelve el nombre del campo 182 | informacion += registro.value( i ).toString() + " - "; 183 | } 184 | qDebug() << informacion; 185 | } 186 | } 187 | else 188 | qDebug() << "No se encuentra conectado a la base"; 189 | } 190 | 191 | 192 | 193 | 194 | Señales propias 195 | ^^^^^^^^^^^^^^^ 196 | 197 | - Si necesitamos enviar una señal se utiliza la palabra reservada ``emit``. 198 | 199 | .. code-block:: c 200 | 201 | int i = 5; 202 | emit signal_enviarEntero( i ); 203 | 204 | 205 | - La función ``signal_enviarEntero( int a )`` debe estar declarada con el modificador de acceso ``signals`` 206 | 207 | .. code-block:: c 208 | 209 | signals: 210 | void signal_enviarEntero( int ); 211 | 212 | 213 | - No olvidarse de la macro ``Q_OBJECT`` para permitir a esta clase usar signals y slots. 214 | - Las signals deben ser compatibles en sus parámetros con los slots a los cuales se conecten. 215 | - Solamente se declara esta función (Qt se encarga de definirla). 216 | 217 | 218 | Ejercicio 14 (continuación): 219 | ============================ 220 | 221 | - Este ejercicio viene de la clase 5, 7, 8 y 12. 222 | - Implementar en AdminDB el uso de MD5 para las claves de los usuarios. 223 | - Acondicionar para que el método utilizado sea el siguiente: 224 | 225 | .. code-block:: c 226 | 227 | /** 228 | * Si el usuario y clave son crrectas, este metodo devuelve el nombre y 229 | * apellido en un QStringList. 230 | */ 231 | QStringList AdminDB::validarUsuario( QString tabla, QString usuario, QString clave ) { 232 | 233 | QStringList datosPersonales; 234 | 235 | if ( ! db.isOpen() ) 236 | return datosPersonales; 237 | 238 | QSqlQuery * query = new QSqlQuery( db ); 239 | QString claveMd5 = QCryptographicHash::hash( clave.toUtf8(), 240 | QCryptographicHash::Md5 ).toHex(); 241 | 242 | query->exec( "SELECT nombre, apellido FROM " + 243 | tabla + " WHERE usuario = '" + usuario + 244 | "' AND clave = '" + claveMd5 + "'" ); 245 | 246 | while( query->next() ) { 247 | QSqlRecord registro = query->record(); 248 | 249 | datosPersonales << query->value( registro.indexOf( "nombre" ) ).toString(); 250 | datosPersonales << query->value( registro.indexOf( "apellido" ) ).toString(); 251 | } 252 | 253 | return datosPersonales; 254 | } 255 | 256 | - Además, definir un método en AdminDB para ejecutar un select a la base. El prototipo es el siguiente: 257 | 258 | .. code-block:: c 259 | 260 | /** 261 | * @brief Método que ejecuta una consulta SQL a la base de datos que ya se encuentra conectado. 262 | Utiliza QSqlQuery para ejecutar la consulta, con el método next() se van extrayendo 263 | los registros que pueden ser analizados con QSqlRecord para conocer la cantidad de 264 | campos por registro. 265 | * @param comando es una consulta como la siguiente: SELECT nombre, apellido, id FROM usuarios 266 | * @return Devuelve un QVector donde cada elemento es un registro, donde cada uno de estos registros 267 | están almacenados en un QStringList que contiene cada campo de cada registro. 268 | */ 269 | QVector< QStringList > select( QString comando ); 270 | 271 | - Definir en Login una signal que se emita cada vez que un usuario se loguee exitosamente. La signal debe emitir el nombre de usuario. 272 | 273 | .. code-block:: c 274 | 275 | void signal_usuarioValidado( QString usuario ); 276 | 277 | 278 | 279 | 280 | 281 | -------------------------------------------------------------------------------- /Clase15.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 15 - POO 2024 6 | =================== 7 | (Fecha: 15 de mayo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ===================================================== 12 | 13 | `Herencia múltiple 2022 `_ 14 | 15 | `Herencia múltiple 2021 `_ 16 | 17 | `inline 2021 `_ 18 | 19 | `friend 2021 `_ 20 | 21 | 22 | 23 | Herencia múltiple 24 | ^^^^^^^^^^^^^^^^^ 25 | 26 | - La clase derivada hereda todos los datos y funciones de todas las clases base 27 | - Puede suceder que en la clases base existan funciones con igual nombre 28 | - Los casos de ambigüedad se solucionan con el nombre completo 29 | - Otra solución sería redefinir en la derivada la función ambigua. 30 | 31 | .. code-block:: c 32 | 33 | #include 34 | #include 35 | 36 | class ClaseA { 37 | public: 38 | ClaseA( int a ) : valorA( a ) { } 39 | int verValor() { return valorA; } 40 | 41 | protected: 42 | int valorA; 43 | }; 44 | 45 | .. code-block:: c 46 | 47 | class ClaseB { 48 | public: 49 | ClaseB() : valorB( 20 ) { } 50 | int verValor() { return valorB; } 51 | 52 | protected: 53 | int valorB; 54 | }; 55 | 56 | .. code-block:: c 57 | 58 | class ClaseC : public ClaseA, public ClaseB { 59 | public: 60 | ClaseC( int c ) : ClaseA( c ), ClaseB() { } 61 | int verValor() { return ClaseA::verValor(); } 62 | }; 63 | 64 | .. code-block:: c 65 | 66 | int main( int argc, char ** argv ) { 67 | QApplication a( argc, argv ); 68 | 69 | ClaseC c( 10 ); 70 | qDebug() << c.verValor(); 71 | qDebug() << c.ClaseB::verValor(); 72 | 73 | return 0; 74 | } 75 | 76 | 77 | **Ejemplo** 78 | 79 | .. code-block:: c 80 | 81 | class Persona { 82 | private: 83 | int edad; 84 | int x, y; 85 | 86 | public: 87 | Persona( int edad = 0 ) : edad( edad ), x( 0 ), y( 0 ) { } 88 | 89 | void move( int x, int y ) { 90 | this->x = x; 91 | this->y = y; 92 | } 93 | }; 94 | 95 | class Jugador : public Persona, public QWidget { 96 | private: 97 | int id; 98 | 99 | public: 100 | Jugador() : Persona( 18 ), QWidget(), id( 0 ) { } 101 | 102 | void mudarse( int x, int y ) { 103 | this->id++; 104 | this->Persona::move( x, y ); // Se requiere especificar de esta manera 105 | } 106 | }; 107 | 108 | 109 | 110 | Funciones inline 111 | ================ 112 | 113 | - Cuando decimos que llamamos a una función es porque salta, ejecuta y retorna. 114 | - Una función inline inserta su código. 115 | - Ventaja de ejecutarse más rápidamente. 116 | - Como desventaja tenemos un programa generado más extenso. 117 | 118 | .. code-block:: c 119 | 120 | #include 121 | #include 122 | 123 | inline int calculo( int a, int b ) { 124 | return a/2+b; 125 | } 126 | 127 | int main( int argc, char ** argv ) { 128 | QApplication a( argc, argv ); 129 | 130 | int x=2, y=3, z=0; 131 | z = calculo( x, y ); 132 | 133 | return 0; 134 | } 135 | 136 | **Funciones miembro inline dentro de clases** 137 | 138 | - Un método se declara dentro del cuerpo de la clase y se puede definir dentro o fuera 139 | - Si se declara y define dentro, se denomina función inline. En este caso, no hace falta indicar con inline (está implícito). 140 | - Si se define fuera, deberá indicar inline. De lo contrario será offline. 141 | - Se recomienda usar funciones inline para funciones pequeñas y de uso frecuente. 142 | 143 | .. code-block:: c 144 | 145 | #include 146 | #include 147 | 148 | class ClaseA { 149 | private: 150 | int x; 151 | int y; 152 | 153 | public: 154 | ClaseA() : x( 10 ), y( 20 ) { } 155 | int getX() { return x; } // inline implícito 156 | int getY(); 157 | }; 158 | 159 | inline int ClaseA::getY() { 160 | return y; 161 | } 162 | 163 | int main( int argc, char ** argv ) { 164 | QApplication a( argc, argv ); 165 | 166 | ClaseA cA; 167 | qDebug() << cA.getX(); 168 | qDebug() << cA.getY(); 169 | 170 | return 0; 171 | } 172 | 173 | 174 | Declaraciones friend 175 | ==================== 176 | 177 | - Miembros privados no son accesibles para funciones y clases externas 178 | - Podemos usar friend en caso de necesitar acceder 179 | - Se pueden aplicar a clases o métodos 180 | - Inhabilitan el sistema de protección (protected o private) 181 | - La amistad no es transferible 182 | 183 | .. code-block:: c 184 | 185 | A es amigo de B B amigo de C No por eso A es amigo de C 186 | 187 | - No se hereda 188 | 189 | .. code-block:: c 190 | 191 | A amigo de B C derivada de B No por eso A es amigo de C 192 | 193 | - No simétrica 194 | 195 | .. code-block:: c 196 | 197 | A amigo de B No por eso B es amigo de A 198 | 199 | **Funciones amigas** 200 | 201 | .. code-block:: c 202 | 203 | #include 204 | using namespace std; 205 | 206 | class ClaseA { 207 | public: 208 | ClaseA( int i ) : a( i ) { } 209 | void verA() { cout << a << endl; } 210 | 211 | protected: 212 | int a; 213 | friend void mostrarA( ClaseA ); // mostrarA es amiga de ClaseA 214 | }; 215 | 216 | void mostrarA( ClaseA cA ) { // Esta función no pertenece a ClaseA 217 | cout << cA.a << endl; // Pero al ser amiga puede acceder a 'a' 218 | } 219 | 220 | int main( int argc, char ** argv ) { 221 | ClaseA objetoA( 10 ); 222 | mostrarA( objetoA ); 223 | objetoA.verA(); 224 | 225 | return 0; 226 | } 227 | 228 | **Función amiga en otra clase** 229 | 230 | .. code-block:: c 231 | 232 | #include 233 | using namespace std; 234 | 235 | class ClaseA; // Declaración 236 | 237 | class ClaseB { 238 | public: 239 | ClaseB( int i ) : b( i ) { } 240 | 241 | void ver() { cout << b << endl; } 242 | 243 | bool esMayor( ClaseA cA ) { // Compara 244 | return b > cA.a; 245 | } 246 | 247 | private: 248 | int b; 249 | }; 250 | 251 | class ClaseA { 252 | public: 253 | ClaseA( int i ) : a( i ) { } 254 | void ver() { cout << a << endl; } 255 | 256 | private: 257 | friend bool ClaseB::esMayor( ClaseA ); 258 | int a; 259 | }; 260 | 261 | int main( int argc, char ** argv ) { 262 | ClaseA objetoA( 10 ); 263 | ClaseB objetoB( 2 ); 264 | 265 | objetoA.ver(); 266 | objetoB.ver(); 267 | 268 | if ( objetoB.esMayor( objetoA ) ) 269 | cout << "objetoB > objetoA" << endl; 270 | else 271 | cout << "objetoB < objetoA" << endl; 272 | 273 | return 0; 274 | } 275 | 276 | 277 | 278 | Ejercicio 22: 279 | ============= 280 | 281 | - Crear una clase base llamada Instrumento y las clases derivadas Guitarra, Bateria y Teclado. 282 | - La clase base tiene una función virtual pura llamada ``sonar()``. 283 | - Defina una función virtual ``verlo()`` que publique la marca del instrumento. Por defecto todos los instrumentos son de la marca Yamaha. 284 | - Utilice en la función ``main()`` un ``std::vector`` para almacenar punteros a objetos del tipo Instrumento. Instancie 5 objetos y agréguelos al ``std::vector``. 285 | - Publique la marca de cada instrumento recorriendo el vector. 286 | - En las clases derivadas agregue los datos miembro "``int cuerdas``", "``int teclas``" e "``int tambores``" según corresponda. Por defecto, guitarra con 6 cuerdas, teclado con 61 teclas y batería con 5 tambores. 287 | - Haga que la clase ``Teclado`` tenga herencia múltiple, heredando además de una nueva clase ``Electrico``. Todos los equipos del tipo "``Electrico``" tienen por defecto un voltaje de 220 volts. Esta clase deberá tener un destructor que al destruirse publique la leyenda "Desenchufado". 288 | - Al llamar a la función ``sonar()``, se deberá publicar "Guitarra suena...", "Teclado suena..." o "Batería suena..." según corresponda. 289 | - Incluya los métodos ``get`` y ``set`` que crea convenientes. 290 | 291 | 292 | Ejercicio 23: 293 | ============= 294 | 295 | - Reutilizar el código fuente de cualquier otro ejericio y utilizar herencia múltiple, inline y friend. 296 | - Implementar herencia múltiple, inline y friend cuando sea beneficioso hacerlo. 297 | 298 | Aclaraciones: 299 | ============= 300 | 301 | - Volver a leer las aclaraciones de la clase 3, 4 y 7 respecto a GitHub 302 | -------------------------------------------------------------------------------- /Clase04.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 04 - POO 2024 6 | =================== 7 | (Fecha: 20 de marzo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Función genérica 2021 `_ 14 | 15 | `Función genérica - arrays - string - punteros 2022 `_ 16 | 17 | `getDatos de Poste - Convenciones 2021 `_ 18 | 19 | `Introducción a Qt 2021 `_ 20 | 21 | `Primer aplicación en Qt 2021 `_ 22 | 23 | 24 | 25 | 26 | Función Genérica 27 | ================ 28 | 29 | - Supongamos que debemos implementar una función que imprima en la salida los valores de un array de enteros: 30 | 31 | .. code-block:: 32 | 33 | void imprimir ( int v[], int cantidad ) { 34 | for ( int i = 0 ; i < cantidad ; i++ ) 35 | std::cout << v[ i ] << " "; 36 | std::cout << std::endl; 37 | } 38 | 39 | int main( int, char ** ) { 40 | int v1[ 5 ] = { 5, 2, 4, 1, 6 }; 41 | imprimir( v1, 3 ); 42 | 43 | return 0; 44 | } 45 | 46 | - Ahora necesitamos la impresión de un array de float 47 | 48 | .. code-block:: 49 | 50 | void imprimir( float v[], int cantidad ); 51 | 52 | - Vemos que las versiones se diferencian por el tipo de datos del array. Entonces podemos utilizar lo siguiente: 53 | 54 | .. code-block:: 55 | 56 | template < class T > void imprimir ( T v[], int cantidad ) { 57 | for ( int i=0 ; i < cantidad ; i++ ) 58 | std::cout << v[ i ] << " "; 59 | std::cout << std::endl; 60 | } 61 | 62 | int main( int, char ** ) { 63 | int v1[ 5 ] = { 5, 2, 4, 1, 6 }; 64 | float v2[ 4 ] = { 2.3, 5.1, 0, 2 }; 65 | 66 | imprimir( v1, 5 ); // qué pasa si pongo cantidad 10 -> Publica basura 67 | imprimir( v2, 2 ); 68 | 69 | return 0; 70 | } 71 | 72 | - El compilador utiliza el código de la función genérica como plantilla para crear automáticamente dos funciones sustituyendo T por el tipo de dato concreto. 73 | 74 | .. code-block:: 75 | 76 | Con T = int utiliza --> void imprimir( int v[], int cantidad ) 77 | 78 | Con T = float utiliza --> void imprimir( float v[], int cantidad ) 79 | 80 | - Aquí, la única operación que realizamos sobre los valores de tipo T es: 81 | 82 | .. code-block:: 83 | 84 | std::cout << v[ i ] 85 | 86 | - Esto pone una restricción, ya que sólo se admitirá los tipos de datos para los que se puedan imprimir en pantalla con: 87 | 88 | .. code-block:: 89 | 90 | std::cout << 91 | 92 | 93 | 94 | Revisión de la clase Poste 95 | ========================== 96 | 97 | **¿ Cómo funciona el método getDatos() ?** 98 | 99 | 100 | .. code-block:: 101 | 102 | class Poste { 103 | private: 104 | int altura; 105 | int seccion; 106 | 107 | public: 108 | Poste( int altura, int seccion ); 109 | 110 | void getDatos( int & altura, int & seccion ); 111 | void setDatos( int altura, int seccion ); 112 | }; 113 | 114 | Poste::Poste( int altura, int seccion ) : altura( altura ), seccion( seccion ) { 115 | 116 | } 117 | 118 | void Poste::getDatos( int & altura, int & seccion ) { 119 | altura = this->altura; 120 | seccion = this->seccion; 121 | } 122 | 123 | void Poste::setDatos( int altura, int seccion ) { 124 | this->altura = altura; 125 | this->seccion = seccion; 126 | } 127 | 128 | 129 | 130 | Convenciones para escribir nuestro código 131 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 132 | 133 | - Los nombres de las clases, structs y enum comienzan con mayúsculas (usando ``UpperCamelCase``). 134 | - Nombres de variables, funciones y métodos comienzan con minúsculas (usando ``lowerCamelCase`` y con palabras separadas con guión bajo). 135 | 136 | - Ejemplos para nombres de clases: ``Persona`` - ``PrimeraClase`` - ``Ventana`` 137 | - Ejemplos para nombres de variables y funciones: ``velocidad`` - ``sumarNumeros`` - ``alto_imagen`` - ``anchoImagen`` 138 | 139 | **CamelCase**: Es escribir con la forma de jorobas de camello con las mayúsculas y minúsculas. 140 | 141 | UpperCamelCase: La primera letra de cada palabra es mayúscula. Ejemplo: ``EjemploDeUpperCamelCase``. 142 | lowerCamelCase: Igual a UpperCamelCase con excepción de la primer palabra. Ejemplo: ``ejemploDeLowerCamelCase`` 143 | 144 | 145 | Primer aplicación en Qt con interfaz gráfica 146 | ============================================ 147 | 148 | - Qt(Quasar Toolkit) 149 | - Biblioteca para desarrollo de software de Quasar Technologies 150 | - Se llamó también Trolltech 151 | - Biblioteca multiplataforma 152 | - En el 2008 lo compró Nokia 153 | - Aplicaciones escritas con C++ (Qt) 154 | - KDE 155 | - VLC Media Player 156 | - Skype 157 | - VirtualBox 158 | - Google Earth 159 | - Spotify para Linux 160 | - En 2012, Digia compra Qt y comercializa las licencias 161 | - Digia desarrolló herramientas para usar Qt en iOS y Android. 162 | 163 | 164 | **Ejemplo** 165 | 166 | - Creación de una aplicación Qt 167 | 168 | .. code-block:: 169 | 170 | #include 171 | // - Administra los controles de la interfaz 172 | // - Procesa los eventos 173 | // - Existe una única instancia 174 | // - Analiza los argumentos de la línea de comandos 175 | 176 | int main( int argc, char** argv ) { 177 | // app es la instancia y se le pasa los parámetros de la línea 178 | // de comandos para que los procese. 179 | QApplication app( argc, argv ); 180 | 181 | QLabel hola( "

Hola

" ); 182 | hola.resize( 200, 100 ); 183 | hola.setVisible( true ); 184 | 185 | app.exec(); // Se le pasa el control a Qt 186 | return 0; 187 | } 188 | 189 | 190 | 191 | Ejercicio 8: 192 | ============ 193 | 194 | - En un Empty qmake Project 195 | - Crear una función genérica que imprima por consola una descripción de cualquier objeto. 196 | - El mensaje puede ser algo así: "Persona con nombre Lucrecia", "Poste con altura de 8 metros y 15 cm de diámetro". 197 | - Probar esta función en main utilizando dos objetos de la clase Persona y dos objetos de la clase Poste. 198 | - Incluir todo el código fuente en el archivo main.cpp. 199 | - Pedirle al chat el código, interpretarlo y hacerlo funcionar. 200 | 201 | 202 | Ejercicio 9: 203 | ============ 204 | 205 | - En un Empty qmake Project 206 | - Crear una función genérica que imprima por consola sus valores ordenados 207 | - Es decir, se le pasa un array con sus valores en cualquier orden, y la función genérica los imprime ordenados 208 | - Que el prototipo sea: ``template < class T > void imprimir( T * v, int cantidad, bool mayor_a_menor );`` 209 | - Utilizar el método de ordenamiento por inserción 210 | - Probar esta función en main utilizando dos arrays (int y float) y ordenar de mayor a menor y el otro al revés. 211 | 212 | Ejercicio 10: 213 | ============= 214 | 215 | - En un Empty qmake Project 216 | - Crear una clase Jugador con atributos ``int velocidad``, ``int fuerza`` y ``std::string nombre`` 217 | - Usar constructor inicializando de la manera recomendada la velocidad en 0, fuerza en 0 y nombre "sin nombre" 218 | - Crear los métodos setter y getter para setear y obtener los valores de los atributos 219 | - Incluir el destructor 220 | - En la función main crear un ``std::vector< Jugador >`` e insertar 10 jugadores distintos 221 | - Por último, publicar los datos de cada uno de los jugadores con ``std::cout`` 222 | 223 | 224 | Ejercicio 11: 225 | ============= 226 | 227 | - En un Empty qmake Project 228 | - En la función main crear un objeto de la clase QLabel, uno de QWidget, uno de QPushButton y uno de QLineEdit 229 | - Invocar al método show() de cada uno de estos 4 objetos 230 | - Notar que cada objeto se muestra independiente 231 | 232 | Ejercicio 12: 233 | ============= 234 | 235 | - En un Empty qmake Project 236 | - En la función main crear un objeto de la clase QLabel y pegarle en el mismo objeto QLabel una imagen de alta resolución. 237 | - Que la imagen se obtenga desde un archivo JPG del disco duro 238 | - Mostrar el QLabel de forma maximizada y que la imagen no se deforme. 239 | - Al cabo de 3 segundos, el QLabel y la aplicación se deberá cerrar 240 | 241 | Aclaraciones: 242 | ============= 243 | 244 | - Todos los ejercicios tienen que ser actualizados en un repositorio en GitHub en carpetas ejercicio01, ejercicio02, ... 245 | - Contener todo lo necesario para poder compilarlo y ejecutarlo. 246 | - Excluir los archivos y carpetas que no sean necesarios, como se el archivo con extensión .pro.user y la carpeta build- 247 | - Enviar un mail a cesarosimani@gmail.com con la URL del repositorio. 248 | 249 | -------------------------------------------------------------------------------- /Clase10.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 10 - POO 2024 6 | =================== 7 | (Fecha: 22 de abril) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Dibujar a mano - QByteArray - Preprocesador 2021 `_ 14 | 15 | `Preprocesador y guardían de inclusión múltiple 2023 `_ 16 | 17 | 18 | `Derivadas - Constructor explícito 2021 `_ 19 | 20 | `Clases derivadas, constructor, destructor, constructor explícito 2023 `_ 21 | 22 | 23 | 24 | 25 | 26 | El preprocesador 27 | ^^^^^^^^^^^^^^^^ 28 | 29 | - Analiza el archivo fuente antes de la compilación real 30 | - Realiza las sustituciones de macros 31 | - Una macro es un patrón de sustitución formado por expresiones textuales 32 | - Procesa las directivas (``#include``, ``#define``, ``#ifndef``, ...) 33 | - Elimina los comentarios. 34 | 35 | **Directivas #ifdef #endif #ifndef** 36 | 37 | - Con ``#ifdef`` si la macro está definida, entonces hace lo siguiente hasta encontrar un ``#endif`` 38 | - ``#ifndef`` pregunta si no está definida 39 | 40 | **Directiva #include** 41 | 42 | - Inserta archivos 43 | - Influye sobre el ámbito y los identificadores 44 | 45 | .. code-block:: 46 | 47 | #include 48 | #include "nombre de fichero de cabecera" 49 | 50 | **Directiva #define** 51 | 52 | - Define macros para sustituir cada vez que se encuentre el identificador. 53 | 54 | .. code-block:: 55 | 56 | #define identificador 57 | 58 | - Si 'secuencia' no existe, el identificador será eliminado cada vez que aparezca 59 | - No es necesario añadir un punto y coma al final 60 | - Termina en el primer retorno de línea encontrado 61 | 62 | 63 | 64 | Guardián de inclusión múltiple 65 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 66 | 67 | - Este problema se soluciona con el uso del **Guardián de inclusión múltiple**: 68 | 69 | .. code-block:: 70 | 71 | #ifndef PRINCIPAL_H 72 | #define PRINCIPAL_H 73 | 74 | // . . . 75 | 76 | #endif // PRINCIPAL_H 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Clases derivadas 86 | ================ 87 | 88 | .. code-block:: 89 | 90 | // personal.h 91 | #include 92 | 93 | class Personal { 94 | public: 95 | QString verEdad() { return "Edad: " + QString::number( edad ); } 96 | QString verSalario() { return "Salario: " + QString::number( salario ); } 97 | 98 | protected: // Para acceso desde las clases derivadas 99 | int edad; 100 | int salario; 101 | }; 102 | 103 | // Modificadores de acceso para Herencia: 104 | // public -> Mantiene los modificadores de acceso de la clase base 105 | // private -> Pasa todo a privado 106 | class Desarrollador : public Personal { 107 | public: 108 | Desarrollador( int edad ) { 109 | salario = 2000; 110 | this->edad = edad; 111 | } 112 | 113 | // Se podrá usar? 114 | Desarrollador( int edad ) : salario( 2000 ), edad( edad ) { } 115 | // No. Sólo para miembros de la propia clase (no para heredados). 116 | }; 117 | 118 | class Administrador : public Personal { 119 | public: 120 | Administrador() { 121 | salario = 2000; 122 | edad = 30; 123 | } 124 | }; 125 | 126 | #include 127 | #include "personal.h" 128 | #include 129 | 130 | int main( int argc, char ** argv ) { 131 | QApplication a( argc, argv ); 132 | 133 | Desarrollador juan( 20 ); 134 | Administrador marcos; 135 | 136 | qDebug() << juan.verEdad(); 137 | qDebug() << juan.verSalario(); 138 | 139 | qDebug() << marcos.verEdad(); 140 | qDebug() << marcos.verSalario(); 141 | 142 | return a.exec(); 143 | } 144 | 145 | Constructor de la clase derivada 146 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 147 | 148 | .. code-block:: 149 | 150 | class Persona { 151 | public: 152 | Persona( int edad ) : edad( edad ) { } 153 | QString verEdad() { return "Edad: " + QString::number( edad ); } 154 | void setEdad( int edad ) { this->edad = edad; } 155 | 156 | protected: 157 | int edad; 158 | }; 159 | 160 | class Empleado : public Persona { 161 | public: 162 | // Siempre primero se llama al constructor de la clase base 163 | Empleado( int edad, int salario ) : Persona( edad ), salario( salario ) { } 164 | QString verSalario() { return "Salario: " + QString::number( salario ); } 165 | 166 | protected: 167 | int salario; 168 | }; 169 | 170 | #include 171 | #include "personal.h" 172 | #include 173 | 174 | int main( int argc, char ** argv ) { 175 | QApplication a( argc, argv ); 176 | 177 | Persona carlos( 24 ); 178 | Empleado ale( 20, 2500 ); 179 | 180 | qDebug() << carlos.verEdad(); 181 | // qDebug() << carlos.verSalario(); // No compila. No está en la clase base. 182 | 183 | qDebug() << ale.verEdad(); 184 | qDebug() << ale.verSalario(); 185 | 186 | return a.exec(); 187 | } 188 | 189 | 190 | 191 | Destructor de la clase derivada 192 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 193 | 194 | .. code-block:: 195 | 196 | class ClaseA { 197 | public: 198 | ClaseA() : datoA(10) { qDebug() << "Constructor A"; } 199 | ~ClaseA() { qDebug() << "Destructor A"; } 200 | int verA() { return datoA; } 201 | 202 | protected: 203 | int datoA; 204 | }; 205 | 206 | class ClaseB : public ClaseA { 207 | public: 208 | ClaseB() : datoB( 20 ) { qDebug() << "Constructor B"; } 209 | ~ClaseB() { qDebug() << "Destructor B"; } 210 | int verB() { return datoB; } 211 | 212 | protected: 213 | int datoB; 214 | }; 215 | 216 | #include 217 | #include "personal.h" 218 | #include 219 | 220 | int main( int argc, char ** argv ) { 221 | QApplication a( argc, argv ); 222 | 223 | { 224 | ClaseB objeto; 225 | qDebug() << "a=" << objeto.verA() << ", b=" << objeto.verB(); 226 | } 227 | 228 | return a.exec(); 229 | } 230 | 231 | // Publica 232 | Constructor A 233 | Constructor B 234 | a=10, b=20 235 | Destructor B 236 | Destructor A 237 | 238 | 239 | 240 | Constructor explícito 241 | ^^^^^^^^^^^^^^^^^^^^^ 242 | 243 | - En el siguiente ejemplo tenemos una clase con un constructor no explícito: 244 | 245 | .. code-block:: 246 | 247 | class Persona { 248 | private: 249 | int edad; 250 | 251 | public: 252 | Persona( int edad = 0 ) : edad( edad ) { } 253 | 254 | int getEdad() { return edad; } 255 | void setEdad( int edad ) { this->edad = edad; } 256 | }; 257 | 258 | - Lo que permite instanciar objetos de todas las siguientes maneras: 259 | 260 | .. code-block:: 261 | 262 | Persona carlos; 263 | Persona miguel( 25 ); 264 | Persona * roman = new Persona; 265 | Persona * juan = new Persona( 18 ); 266 | 267 | Persona roberto = 23; 268 | 269 | - Llama la atención la última de las maneras. 270 | - En ese caso, el compilador permite la conversión, ya que se entiende que el programador quiere usar el constructor que recibe un int como parámetro. 271 | 272 | - Si deseamos bloquear esta posibilidad, debemos indicar que el constructor sea explícito, de la siguiente manera: 273 | 274 | .. code-block:: 275 | 276 | class Persona { 277 | private: 278 | int edad; 279 | 280 | public: 281 | explicit Persona( int edad = 0 ) : edad( edad ) { } 282 | 283 | int getEdad() { return edad; } 284 | void setEdad( int edad ) { this->edad = edad; } 285 | }; 286 | 287 | - Cuando un constructor no explícito recibe dos variables: 288 | 289 | .. code-block:: 290 | 291 | class Persona { 292 | private: 293 | int edad; 294 | int dni; 295 | 296 | public: 297 | Persona( int edad = 0, int dni = 0 ) : edad( edad ), dni( dni ) { } 298 | 299 | int getEdad() { return edad; } 300 | void setEdad( int edad ) { this->edad = edad; } 301 | int getDni() { return dni; } 302 | void setDni( int dni ) { this->dni = dni; } 303 | }; 304 | 305 | - Se puede hacer lo siguiente: 306 | 307 | .. code-block:: 308 | 309 | Persona roberto = { 23, 35876543 }; 310 | 311 | - Y tener en cuenta que también es posible lo siguiente: 312 | 313 | .. code-block:: 314 | 315 | // Cuando el constructor recibe 3 parámetros y de distintos tipos 316 | Persona( int edad = 0, int dni = 0, QString nombre = "" ) : edad( edad ), 317 | dni( dni ), 318 | nombre( nombre ) { 319 | } 320 | 321 | // Se puede instanciar un objeto así: 322 | Persona roberto = { 23, 35876543, "Roberto" }; 323 | 324 | - A continuación un ejemplo por Carlos Duarte para `Constructor explícito `_ 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | -------------------------------------------------------------------------------- /Clase12.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 12 - POO 2024 6 | =================== 7 | (Fecha: 6 de mayo) 8 | 9 | 10 | 11 | Registro en video de algunos temas de la clase de hoy 12 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 13 | 14 | 15 | 16 | `AdminDB y su implementación en Login 2024 `_ 17 | 18 | `SQLite, AdminDB y función virtual pura 2023 `_ 19 | 20 | `AdminDB 2022 `_ 21 | 22 | `Base de datos 2021 `_ 23 | 24 | 25 | 26 | 27 | Vista obligatoria 28 | ^^^^^^^^^^^^^^^^^ 29 | 30 | `Función virtual pura clase abstracta 2021 `_ 31 | 32 | 33 | 34 | 35 | Función virtual pura y clase abstracta 36 | ====================================== 37 | 38 | - No necesita ser definida, sólo se declara. 39 | - Será definida en las clases derivadas 40 | 41 | .. code-block:: c 42 | 43 | virtual void verValor( int a ) = 0; 44 | 45 | - Una clase con al menos una función virtual pura la convierte en clase abstracta. 46 | - Una clase abstracta no puede ser instanciada. 47 | - Si en la clase derivada no se define la función virtual pura, significa que esta clase derivada también es abstracta. 48 | 49 | 50 | 51 | Conexión a base de datos 52 | ^^^^^^^^^^^^^^^^^^^^^^^^ 53 | 54 | **Ejemplo de la estructura de las tablas en la base de datos** 55 | 56 | .. figure:: imagenes/tablas.png 57 | 58 | - Con Qt se pueden utilizar los siguientes motores de base de datos: 59 | - **ODBC (Open DataBase Connectivity)**: 60 | - Estándar de acceso a base de datos 61 | - Usado con Microsoft Access en Windows 62 | - Está disponible en Windows: Panel de control -> Herramientas administrativas -> ODBC Data sources 63 | 64 | - **SQLite** 65 | - Es un sistema de gestión de bases de datos relacional. 66 | - En C y libre 67 | - Los datos se almacenan en un archivo 68 | - No es cliente-servidor. La librería (dll) tiene funciones para trabajar 69 | - No requiere instalación, directamente con un ejecutable 70 | - Para Linux, Windows, Mac OS, Android, iOS, BlackBerry OS, Windows Phone, ... 71 | 72 | - **MySQL** 73 | - Quizás el motor de base de datos más utilizado 74 | - Requiere una instalación más avanzada para usar con Qt dependiendo el SO que se utilice. 75 | 76 | Usando SQLite 77 | ^^^^^^^^^^^^^ 78 | 79 | **Creación de una base de datos SQLite** 80 | 81 | - Descargar de http://www.sqlite.org/download.html 82 | - Precompiled Binaries for Windows–Linux–MAC (The command-line shell program) 83 | - En Linux se puede hacer: ``sudo apt-get install sqlite3`` 84 | - Al descomprimir tenemos el ejecutable sqlite3 85 | - Creamos una carpeta C:/Qt/db (o /home/db) y copiamos ahí el ejecutable 86 | - En consola creamos una base de datos, por ejemplo, llamada ``test`` con una tabla ``usuarios`` 87 | 88 | :: 89 | 90 | sqlite3 test 91 | 92 | create table usuarios ( 93 | id integer primary key, (es autoincrementable) 94 | usuario varchar(30), 95 | clave varchar(30), 96 | nombre varchar(50), 97 | apellido varchar(50), 98 | mail varchar(50) 99 | ); 100 | 101 | // Podemos insertar un registro 102 | 103 | insert into usuarios (usuario, clave, nombre, apellido, mail) 104 | values ("cgomez", "1234", "Carlos", "Gomez", "cgomez@gmail.com"); 105 | 106 | // Podemos ver el contenido de la tabla "usuario": 107 | 108 | select * from usuarios; 109 | 110 | // Para salir de la base: 111 | 112 | .exit 113 | 114 | En Qt 115 | ^^^^^ 116 | 117 | - Requiere QT += sql 118 | - Para averiguar los controladores disponibles, usamos el método estático: 119 | 120 | .. code-block:: c 121 | 122 | qDebug() << QSqlDatabase::drivers(); // Devuelve un QStringList 123 | 124 | - Un objeto QSqlDatabase representa la conexión a la base 125 | - Elegimos el controlador y conectamos: 126 | 127 | .. code-block:: c 128 | 129 | QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" ); 130 | 131 | db.setDatabaseName( "C:/Qt/db/test" ); 132 | if ( db.open() ) 133 | qDebug() << "Conexión exitosa"; 134 | else 135 | qDebug() << "No se pudo abrir la base"; 136 | 137 | - En Windows, para usar el archivo Access ``C:/db/base.mdb`` se hace lo siguiente: 138 | 139 | .. code-block:: c 140 | 141 | QSqlDatabase db = QSqlDatabase::addDatabase( "QODBC" ); 142 | 143 | db.setDatabaseName( "DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};" 144 | "DBQ=C:/db/base.mdb" ); 145 | if ( db.open() ) 146 | qDebug() << "Conexión exitosa"; 147 | 148 | 149 | 150 | **Preparando la clase AdminDB** 151 | 152 | - Definir una clase AdminDB para administrar la base de datos 153 | - Crear el siguiente método: 154 | 155 | .. code-block:: c 156 | 157 | bool conectar(QString archivoSqlite); 158 | 159 | - En un proyecto nuevo y desde la función main() intentar la conexión. 160 | 161 | .. code-block:: c 162 | 163 | // --- adminDB.h --------------- 164 | #include 165 | #include 166 | #include 167 | 168 | class AdminDB : public QObject { 169 | Q_OBJECT 170 | 171 | public: 172 | AdminDB(); 173 | bool conectar( QString archivoSqlite ); 174 | QSqlDatabase getDB(); 175 | 176 | private: 177 | QSqlDatabase db; 178 | }; 179 | 180 | // --- adminDB.cpp ------------ 181 | #include "adminDB.h" 182 | 183 | AdminDB::AdminDB() { 184 | db = QSqlDatabase::addDatabase( "QSQLITE" ); 185 | } 186 | 187 | bool AdminDB::conectar( QString archivoSqlite ) { 188 | db.setDatabaseName( archivoSqlite ); 189 | 190 | if( db.open() ) 191 | return true; 192 | 193 | return false; 194 | } 195 | 196 | QSqlDatabase AdminDB::getDB() { 197 | return db; 198 | } 199 | 200 | // --- main.cpp ---------------- 201 | #include 202 | #include "adminDB.h" 203 | 204 | int main( int argc, char** argv ) { 205 | QApplication a( argc, argv ); 206 | 207 | qDebug() << QDir::currentPath(); 208 | 209 | AdminDB adminDB; 210 | if (adminDB.conectar( "C:/Qt/db/test" ) ) 211 | qDebug() << "Conexion exitosa"; 212 | else 213 | qDebug() << "Conexion NO exitosa"; 214 | 215 | return 0; 216 | } 217 | 218 | 219 | 220 | 221 | 222 | Consulta a la base de datos 223 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 224 | 225 | .. code-block:: c 226 | 227 | QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE" ); 228 | 229 | db.setDatabaseName( "C:/Qt/db/test" ); 230 | 231 | if ( db.open() ) { 232 | QSqlQuery query = db.exec( "SELECT nombre, apellido FROM usuarios" ); 233 | 234 | while( query.next() ) { 235 | qDebug() << query.value( 0 ).toString() << " " << query.value( 1 ).toString(); 236 | } 237 | } 238 | 239 | 240 | 241 | 242 | **Ejemplo**: slot de la clase Login para que valide usuarios contra la base 243 | 244 | .. code-block:: c 245 | 246 | void Login::slot_validar() { 247 | bool usuarioValido = false; 248 | 249 | if ( adminDB->getDB().isOpen() ) { 250 | QSqlQuery * query = new QSqlQuery( adminDB->getDB() ); 251 | 252 | query->exec( "SELECT nombre, apellido FROM usuarios WHERE usuario='" + 253 | leUsuario->text() + "' AND clave='" + leClave->text() + "'" ); 254 | 255 | // Si los datos son consistentes, devolverá un único registro. 256 | while ( query->next() ) { 257 | 258 | QSqlRecord record = query->record(); 259 | 260 | // Obtenemos el número de la columna de los datos que necesitamos. 261 | int columnaNombre = record.indexOf( "nombre" ); 262 | int columnaApellido = record.indexOf( "apellido" ); 263 | 264 | // Obtenemos los valores de las columnas. 265 | qDebug() << "Nombre=" << query->value( columnaNombre ).toString(); 266 | qDebug() << "Apellido=" << query->value( columnaApellido ).toString(); 267 | 268 | usuarioValido = true; 269 | } 270 | 271 | if ( usuarioValido ) { 272 | QMessageBox::information( this, "Conexión exitosa", "Válido" ); 273 | } 274 | else { 275 | QMessageBox::critical( this, "Sin permisos", "Usuario inválido" ); 276 | } 277 | } 278 | } 279 | 280 | 281 | 282 | Registrar eventos (logs) 283 | ^^^^^^^^^^^^^^^^^^^^^^^^ 284 | 285 | .. code-block:: c 286 | 287 | bool AdminDB::registrar( QString evento ) { 288 | QSqlQuery query( db ); 289 | 290 | bool exito = query.exec( "INSERT INTO registos (evento) VALUES ('" + evento + "')" ); 291 | 292 | qDebug() << query.lastQuery(); 293 | qDebug() << query.lastError(); // Devuelve un objeto de QSqlError 294 | 295 | return exito; 296 | } 297 | 298 | 299 | 300 | 301 | 302 | Ejercicio 14 (continuación): 303 | ============================ 304 | 305 | - Este ejercicio viene de la clase 5, 7 y 8. 306 | - Incorporar la validación de usuarios con QSLite. 307 | - Todo lo que se haga con la base de datos, que se encuentre en la clase AdminDB 308 | - Pueden utilizar SQLiteStudio (`https://sqlitestudio.pl `_) o similar. 309 | -------------------------------------------------------------------------------- /Clase17.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 17 - POO 2024 6 | =================== 7 | (Fecha: 22 de mayo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Sobrecarga de operadores 2021 `_ 14 | 15 | `Singleton 2021 `_ 16 | 17 | 18 | Sobrecarga de operadores 19 | ======================== 20 | 21 | - Supongamos los siguientes objetos de la clase Poste: 22 | 23 | .. code-block:: c 24 | 25 | Poste p1; // Su único miembro dato es un float para la altura del Poste 26 | Poste p2; 27 | 28 | - Necesitamos unir estos Postes para obtener un único Poste con sus alturas sumadas. 29 | - ¿Podemos hacer lo siguiente? 30 | 31 | .. code-block:: c 32 | 33 | Poste unidos = p1 + p2; 34 | 35 | **Otro ejemplo** 36 | 37 | .. code-block:: c 38 | 39 | class Cliente { 40 | private: 41 | int saldo; 42 | 43 | public: 44 | Cliente() : saldo( 0 ) { 45 | } 46 | 47 | void operator+( int sumando ) { 48 | this->saldo += sumando; 49 | } 50 | 51 | void operator-( int sustraendo ) { 52 | this->saldo -= sustraendo; 53 | } 54 | 55 | bool operator<( Cliente otroCliente ) { 56 | if ( this->saldo < otroCliente.saldo ) 57 | return true; 58 | return false; 59 | } 60 | }; 61 | 62 | int main( int argc, char ** argv ) { 63 | Cliente juan; 64 | 65 | Cliente carlos; 66 | 67 | juan + 50; // Suma 50 a su cuenta 68 | 69 | carlos + 100; // Quita 100 a carlos 70 | 71 | if ( juan < carlos ) { 72 | qDebug() << "juan tiene menos"; 73 | } 74 | 75 | return 0; 76 | } 77 | 78 | 79 | 80 | 81 | static 82 | ====== 83 | 84 | **Variables estáticas** 85 | 86 | - Al salir de su ámbito no pierde su valor 87 | - Sólo son conocidas dentro de su ámbito (pero igual "recuerdan su valor") 88 | - Se inicializan sólo la primera vez 89 | 90 | .. code-block:: c 91 | 92 | #include 93 | #include 94 | 95 | int funcion( int a = 2 ) { 96 | static int suma = 0; 97 | return ( suma += a ); 98 | } 99 | 100 | int main( int argc, char ** argv ) { 101 | QApplication a( argc, argv ); 102 | 103 | qDebug() << funcion(); 104 | qDebug() << funcion( 10 ); 105 | qDebug() << funcion(); 106 | 107 | return 0; 108 | } 109 | 110 | **Miembros estáticos** 111 | 112 | - Para cada instancia de una clase existe una copia de los miembros no-estáticos. 113 | - Pero hay una única copia de los estáticos para todas las instancias. 114 | - Pueden ser accedidas sin referencia a ninguna instancia concreta de la clase. 115 | - Los miembros estáticos no dependen de ninguna instancia para su existencia. 116 | - Existen incluso antes que la primera instancia de una clase. 117 | 118 | **¿Qué problema tiene este código?** 119 | 120 | .. code-block:: c 121 | 122 | #include 123 | #include 124 | 125 | class A { 126 | public: 127 | static int x; 128 | }; 129 | 130 | int main( int argc, char ** argv ) { 131 | QApplication a( argc, argv ); 132 | 133 | A a1; 134 | qDebug() << a1.x; // No reconoce x 135 | 136 | return 0; 137 | } 138 | 139 | **¿Qué se publica?** 140 | 141 | .. code-block:: c 142 | 143 | #include 144 | #include 145 | 146 | class A { 147 | public: 148 | static int x; 149 | }; 150 | 151 | int A::x = 5; 152 | 153 | int main( int argc, char ** argv ) { 154 | QApplication a( argc, argv ); 155 | 156 | A a1, a2; 157 | qDebug() << a1.x; 158 | qDebug() << a2.x; 159 | 160 | a1.x = 9; 161 | qDebug() << a1.x; 162 | qDebug() << a2.x; 163 | 164 | return 0; 165 | } 166 | 167 | - La modificación del valor ``x`` en el objeto a1 cambia dicha propiedad ``x`` en ``a2``. 168 | - La definición ``int A::x = 5;`` solo son permitidas para miembros estáticos. 169 | 170 | **¿Qué error tiene el siguiente código?** 171 | 172 | .. code-block:: c 173 | 174 | class B { 175 | static const char * p1; // privado por defecto 176 | 177 | public: 178 | static const char * p2; // declaración 179 | const char* p3; 180 | }; 181 | 182 | const char * B::p1 = "Adios"; // Ok. Definición 183 | const char * B::p2 = "mundo"; // Ok 184 | const char * B::p3 = "cruel"; // Error. No es estática. No se puede definir así. 185 | 186 | 187 | - No significa que las propiedades estáticas (privadas o protegidas) puedan ser accedidas directamente desde el exterior. Depende del modificador de acceso: 188 | 189 | .. code-block:: c 190 | 191 | int main( int argc, char ** argv ) { 192 | QApplication a( argc, argv ); 193 | 194 | qDebug() << B::p1; // Error: no accesible! 195 | qDebug() << B::p2; // Ok: -> "mundo" 196 | 197 | return 0; 198 | } 199 | 200 | **Definición de miembros estáticos** 201 | 202 | - Si los miembros estáticos existen antes de cualquier instancia, entonces hay que definirlos. 203 | - Los métodos estáticos sólo pueden acceder a miembros estáticos. 204 | 205 | **¿Qué problema tiene el siguiente código?** 206 | 207 | .. code-block:: c 208 | 209 | class C { 210 | static int y; 211 | 212 | public: 213 | int x; 214 | static int * p; 215 | static const char * c; 216 | static int getY() { return y; } 217 | static int getX() { return x; } // No compila. x no es estático. 218 | }; 219 | 220 | int C::y = 1; // no se debe poner static 221 | int * C::p = &C::y; 222 | const char * C::c = "ABC"; 223 | 224 | **El constructor y miembros estáticos** 225 | 226 | - La inclusión de un constructor no evita tener que definir los miembros estáticos. 227 | - Recordar que el constructor es invocado cuando se instancia. 228 | - El constructor puede modificar los valores de los miembros estáticos pero no inicializarlos. 229 | 230 | **¿El siguiente código compila?** 231 | 232 | .. code-block:: c 233 | 234 | class D { 235 | static int y; 236 | 237 | public: 238 | int x; 239 | 240 | // El constructor no puede modificar así los miembros estáticos 241 | D() : y( 10 ), x( 20 ) { } 242 | }; 243 | 244 | int D::y = 1; 245 | 246 | - Se debería usar un constructor como el que sigue: 247 | 248 | .. code-block:: c 249 | 250 | D() : x( 20 ) { 251 | y = 10; 252 | } 253 | 254 | **Particularidades de la notación** 255 | 256 | - Los miembros estáticos pueden ser accedidos con :: con la notación C::miembro. 257 | - No es necesario utilizar ninguna instancia concreta de la clase. 258 | 259 | **¿Qué publicaría el siguiente código?** 260 | 261 | .. code-block:: c 262 | 263 | #include 264 | #include 265 | 266 | class E { 267 | public: 268 | static int x; // miembro estático 269 | E( int i = 12 ) { x = i; } 270 | 271 | }; 272 | 273 | int E::x = 13; // definicion de miembro 274 | 275 | int main( int argc, char ** argv ) { 276 | QApplication( argc, argv ); 277 | 278 | qDebug() << E::x; 279 | E e1; 280 | qDebug() << E::x; 281 | 282 | return 0; 283 | } 284 | 285 | 286 | 287 | Singleton 288 | ========= 289 | 290 | - Un singleton es un patrón de diseño que restringe la creación de instancias de una clase a una única instancia. 291 | 292 | 293 | Ejemplo de AdminDB como singleton 294 | ================================= 295 | 296 | .. code-block:: c 297 | 298 | #ifndef ADMINDB_H 299 | #define ADMINDB_H 300 | 301 | class AdminDB { 302 | 303 | private: 304 | static AdminDB * instancia; 305 | AdminDB(); 306 | 307 | public: 308 | static AdminDB * getInstancia(); 309 | 310 | void conectar(); 311 | }; 312 | 313 | #endif // ADMINDB_H 314 | 315 | 316 | .. code-block:: c 317 | 318 | #include "admindb.h" 319 | #include 320 | 321 | AdminDB * AdminDB::instancia = nullptr; 322 | 323 | AdminDB::AdminDB() { 324 | } 325 | 326 | AdminDB * AdminDB::getInstancia() { 327 | if( instancia == nullptr ) { 328 | instancia = new AdminDB; 329 | } 330 | return instancia; 331 | } 332 | 333 | void AdminDB::conectar() { 334 | qDebug() << "La base se encuentra conectada..."; 335 | } 336 | 337 | 338 | .. code-block:: c 339 | 340 | #include "admindb.h" 341 | 342 | int main( int, char ** ) { 343 | 344 | AdminDB::getInstancia()->conectar(); 345 | 346 | return 0; 347 | } 348 | 349 | 350 | 351 | 352 | Ejercicio 25: 353 | ============= 354 | 355 | - Construir un nuevo proyecto que tenga un Login independiente, es decir, que no dependa de otra clase GUI. 356 | - El Login tenga un QLabel que funciona como botón que sea para registrar un nuevo usuario. 357 | - Cuando se presiona el QLabel que funciona como botón, se abrirá una ventana para dar de alta un usuario. 358 | - Usar SQLite con AdminDB como singleton. 359 | - Cuando un usuario válido ingresa correctamente se mostrará otra ventana que visualizará todos los usuarios cargados en la base. 360 | - Para la visualización de los usuarios se puede usar QTreeWidget. Agregar la funcionalidad para que en esta misma ventana se puedan editar los campos como si fuera una planilla tipo excel. 361 | - Seguir las recomendaciones que se comentaron durante el dictado de clases para construir las clases. 362 | -------------------------------------------------------------------------------- /Clase03.rst: -------------------------------------------------------------------------------- 1 | .. -*- coding: utf-8 -*- 2 | 3 | .. _rcs_subversion: 4 | 5 | Clase 03 - POO 2024 6 | =================== 7 | (Fecha: 18 de marzo) 8 | 9 | 10 | Registro en video de algunos temas de la clase de hoy 11 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 12 | 13 | `Clases 2021 `_ 14 | 15 | 16 | Cadena de caracteres 17 | ^^^^^^^^^^^^^^^^^^^^ 18 | 19 | - Al estilo C 20 | 21 | .. code-block:: 22 | 23 | #include 24 | 25 | char cadena1[ 30 ], cadena2[ 30 ]; 26 | strcpy( cadena1, "Hola" ); 27 | cin >> cadena2; 28 | 29 | - Con C++ usamos 30 | 31 | .. code-block:: 32 | 33 | #include 34 | 35 | Asignación s1 = s2 s1 = "Hola" 36 | Concatenación s1 = s2 + s3 37 | Comparación if ( s1 == s2 ) 38 | Subcadenas s1.substr( 3, 5 ) 39 | Longitud s1.length() s2.size() // Son lo mismo 40 | Acceso a char s1[ 2 ] s2.at( 2 ) // Lanza out_of_range 41 | Limpiar s1.clear() 42 | Busca cadena s1.find( "cadena" ); s1.find( s2 ); 43 | Puntero a char const char *c = s1.c_str() 44 | 45 | 46 | 47 | Punteros 48 | ======== 49 | 50 | **Declaración** 51 | 52 | .. code-block:: 53 | 54 | int * entero; // entero es un puntero a int 55 | char * caracter; // puntero a char 56 | 57 | entero es el puntero 58 | *entero es el contenido 59 | 60 | 61 | **Punteros a variables** 62 | 63 | .. code-block:: 64 | 65 | int entero; // entero es una variable int 66 | int * pEntero; // pEntero es un puntero a int 67 | pEntero = &entero; // &entero es la dirección de memoria donde se almacena entero 68 | 69 | **Arrays y punteros** 70 | 71 | .. code-block:: 72 | 73 | int miArray[ 10 ]; // miArray es como un puntero al primer elemento 74 | int* puntero; 75 | 76 | puntero = miArray; // similar a: puntero = &miArray[0]; 77 | ( *puntero )++; // equivale a miArray[0]++; // incrementa 78 | puntero++; // equivale a &miArray[1]; // se mueve una posición 79 | 80 | puntero = puntero + 3; // se desplaza 3 posiciones int 81 | 82 | 83 | 84 | 85 | 86 | 87 | Clases 88 | ====== 89 | 90 | .. code-block:: 91 | 92 | class Poste { 93 | // Lista de miembros (generalmente funciones y datos) 94 | // Los datos no pueden ser inicializados fuera del constructor 95 | // Si las funciones se definen fuera, se usa el operador :: 96 | // :: es el operador de acceso a ámbito 97 | }; 98 | 99 | 100 | .. code-block:: 101 | 102 | class Poste; // Esto es la declaración de una clase. 103 | 104 | .. code-block:: c 105 | 106 | class Poste { // Esto es la declaración y definición de una clase. 107 | 108 | }; 109 | 110 | 111 | 112 | 113 | **Ejemplo:** 114 | 115 | .. code-block:: 116 | 117 | #include 118 | 119 | class Poste { 120 | private: 121 | // Datos miembro de la clase Poste. También llamados atributos. 122 | int altura; 123 | int seccion; 124 | 125 | public: 126 | // Funciones miembro de la clase Poste. Llamados también métodos. 127 | void getDatos( int & a, int & s ); 128 | void setDatos( int a, int s ) { 129 | altura = a; 130 | seccion = s; 131 | } 132 | }; 133 | 134 | void Poste::getDatos( int & a, int & s ) { 135 | a = altura; 136 | s = seccion; 137 | } 138 | 139 | int main() { 140 | Poste poste; 141 | int x, y; // Variables donde se copiarán los valores de poste 142 | 143 | poste.setDatos( 12, 32 ); 144 | poste.getDatos( x, y ); 145 | 146 | cout << "(" << x << “, ” << y << “)” << endl; 147 | } 148 | 149 | // La función "setDatos()" se definió en el interior de la clase (lo haremos sólo cuando 150 | // la definición sea muy simple, ya que dificulta la lectura y comprensión del programa). 151 | 152 | **Constructor** 153 | 154 | .. code-block:: 155 | 156 | class Poste { 157 | private: 158 | int altura; 159 | int seccion; 160 | 161 | public: 162 | Poste( int a, int s ); 163 | 164 | void getDatos( int & a, int & s ); 165 | void setDatos( int a, int s ); 166 | }; 167 | 168 | Poste::Poste( int a, int s ) { 169 | altura = a; 170 | seccion = s; 171 | } 172 | 173 | void Poste::getDatos( int & a, int & s ) { 174 | a = altura; 175 | s = seccion; 176 | } 177 | 178 | void Poste::setDatos( int a, int s ) { 179 | altura = a; 180 | seccion = s; 181 | } 182 | 183 | **Cuestiones sobre declaraciones** 184 | 185 | .. code-block:: 186 | 187 | Poste poste; // Llama al constructor sin parámetros. En esta última versión 188 | // de Poste, esto no serviría, ya que no hay constructor sin parámetros. 189 | // Si no se especifica un constructor, el compilador crea uno. 190 | // Por lo tanto, esta declaración sirve para una clase Poste 191 | // donde el programador no escriba constructor, o escriba uno sin recibir parámetros. 192 | 193 | Poste poste(); // Se entiende como el prototipo de una función sin parámetros que 194 | // devuelve un objeto Poste. Es decir, no sirve para instanciar un 195 | // objeto con el contructor sin parámetros de Poste. 196 | 197 | Poste poste1( 12, 43 ); // Válido 198 | Poste poste2( 45, 34 ); // Válido 199 | 200 | 201 | **Inicialización de objetos** 202 | 203 | .. code-block:: 204 | 205 | // Lo siguiente se permite y funciona casi siempre, (salvo cuando usemos const, que 206 | // veremos más adelante). Hay que tener presente que aquí, primero se reserva lugar 207 | // en memoria para altura y seccion conteniendo basura y luego se le asignan los 208 | // valores que vienen en los parámetros del constructor. 209 | Poste( int a, int s ) { 210 | altura = a; 211 | seccion = s; 212 | } 213 | 214 | // La siguiente sería la manera más correcta de inicializar los atributos de un 215 | // objeto. En este caso, altura y seccion nunca contienen basura, sino que 216 | // directamente se crean en memoria con el valor que vienen en los parámetros del constructor. 217 | Poste::Poste( int a, int s ) : altura( a ), seccion( s ) { } 218 | 219 | Poste::Poste() : a( 0 ), b( 0 ) { } 220 | 221 | **El puntero this** 222 | 223 | - Es un puntero que ya se exite dentro del ámbito de una clase y apunta al propio objeto instanciado. 224 | - Se utiliza para acceder a los atributos y métodos. 225 | 226 | .. code-block:: 227 | 228 | class Poste { 229 | private: 230 | int altura; 231 | int seccion; 232 | 233 | public: 234 | Poste( int altura, int seccion ); 235 | 236 | void getDatos( int & altura, int & seccion ); 237 | void setDatos( int altura, int seccion ); 238 | }; 239 | 240 | Poste::Poste( int altura, int seccion ) : altura( altura ), seccion( seccion ) { 241 | } 242 | 243 | void Poste::getDatos( int & altura, int & seccion ) { 244 | altura = this->altura; 245 | seccion = this->seccion; 246 | } 247 | 248 | void Poste::setDatos( int altura, int seccion ) { 249 | this->altura = altura; 250 | this->seccion = seccion; 251 | } 252 | 253 | 254 | **Destructor** 255 | 256 | .. code-block:: 257 | 258 | Poste::~Poste() { 259 | altura = 0; 260 | seccion = 0; 261 | } 262 | 263 | 264 | 265 | 266 | 267 | 268 | Ejercicio 1: 269 | ============ 270 | 271 | - Instalar Qt. Lo cual incluye las herramientas de compilación C++, la biblioteca Qt y Qt Creator. 272 | - Crear un primer programa que muestre por la consola de QtCreator 10 números aleatorios en el intervalo [ 2, 20 ] 273 | - Cada vez que se ejecute el programa, los números deberán ser aleatorios y distintos en cada ejecución. 274 | 275 | 276 | Ejercicio 2: 277 | ============ 278 | 279 | Objetivo: Familiarización con librerías, archivos DLL y variable de entorno PATH. Tener presente la distinción entre biblioteca, librería y library. 280 | 281 | Descripción: Crear un programa simple en C++ que utilice una librería externa (en forma de archivo DLL o similar en otros sistemas operativos) y que haga uso de la variable de entorno PATH para ubicar dicha librería. 282 | 283 | Pasos a seguir: 284 | 285 | a. Crear una librería en C++ y compilarla como un archivo DLL 8o similar en otros sistemas operativos). Programar en la librería una función que imprima un mensaje simple, como "Hola, desde la biblioteca". 286 | 287 | b. Crear un programa principal en C++ que utilice esta librería. Hacer referencia (o linkear) a la librería de manera dinámica. 288 | 289 | c. Incluir la ruta al archivo DLL en la variable de entorno PATH. 290 | 291 | d. En el programa principal, cargar la librería, invocar a la función y mostrar el mensaje. 292 | 293 | 294 | Ejercicio 3: 295 | ============ 296 | 297 | - Elija un nombre para su propio espacio de nombres para todo lo que se haga en este asignatura 298 | - Luego de elegido el nombre para su namespace, defina una función dentro de ese namespace para devolver el número de versión junto con la fecha de la última actualización de la biblioteca 299 | 300 | .. code-block:: 301 | 302 | QString getVersion(); // Devuelve un texto como "v0.0.1 - 20240318" 303 | 304 | 305 | Ejercicio 4: 306 | ============ 307 | 308 | - Crear un std::vector para contener int 309 | - Cargar 30 valores pseudo aleatorios entre 1 y 15 310 | - Publicar la moda 311 | 312 | 313 | Ejercicio 5: 314 | ============ 315 | 316 | - Crear un std::vector para contener objetos de la clase std::string 317 | - Cargar 5 expresiones idiomáticas, como por ejemplo: pan comido 318 | - Publicar por consola ordenado alfabéticamente 319 | 320 | 321 | Ejercicio 6: 322 | ============ 323 | 324 | - En un Empty qmake Project 325 | - Crear una nueva clase (que no sea Persona, ni Cliente, ni Poste). Invente una clase. 326 | - Agregar uno o más constructores, agregar sus métodos y sus atributos 327 | - Crear algunos objetos de esta clase en la función main 328 | 329 | Ejercicio 7: 330 | ============ 331 | 332 | - Empty qmake Project 333 | - Utilizar la clase creada en el ejercicio anterior para crear objetos y almacenarlos en un ``std::vector`` 334 | - ¿Se pueden ordenar? Qué estrategia utilizaría para ordenarlos de menor a mayor 335 | 336 | 337 | 338 | Aclaraciones: 339 | ============= 340 | 341 | - Todos los ejercicios serán actualizados en un repositorio en GitHub 342 | - Escribir el README con contenido para poder ejecutar los ejercicios 343 | - Cada ejercicio tendrá su propia carpeta ejercicio01, ejercicio02, ... 344 | - Que cada ejercicio debe contener todo lo necesario para poder compilarlo y ejecutarlo. 345 | - Excluir los archivos y carpetas que no sean necesarios, como se el archivo con extensión .pro.user y la carpeta build- 346 | 347 | --------------------------------------------------------------------------------