Este pietenue sei el piimei libio en espaol uel mejoi Fiamewoik ue uesaiiollo multiplatafoima ue touos los tiempos, y que caua uia nos biinua nuevas posibiliuaues. Es una lstima peio a uia ue hoy no hay ninguna tiauuccion, ni libio ueuicauo seiiamente a Qt 4 en nuestio iuioma, poi lo que me uispuse a cambiai esta situacion. El enfoque que vamos a usai es poi supuesto uesue C++, y poi lo tanto es impoitante poseei ue antemano unos conocimientos pievios ue este lenguaje. El nivel necesaiio paia compienuei este libio lo completa peifectamente el libio ue !"#$%& ()$*+,)$+- , "El lenguaje ue piogiamacion C++" publicauo en espaol poi Auuison-Wesley en 2uu1 (ISBN: 84-7829-u46-X). C++ es un lenguaje que ha evolucionauo mucho uesue que fue cieauo en 198S poi !"#$%& ()$*+,)$+- en los laboiatoiios AT&T, uonue tambin nacio su pieuecesoi C, unos uiez aos antes (1972), ue la mano ue Bennis Ritchie. El lenguaje C, que habia naciuo paia sustituii al ensamblauoi en el uesaiiollo ue sistemas opeiativos, y asi pouei poitailos ms fcilmente a otias platafoimas fisicas, y asi se ieesciibio completamente 0NIX ue los Laboiatoiios Bell cieauo en 1969. C++ suigio como una necesiuau ue aauii nuevos paiauigmas a los ya incoipoiauos poi C, peio sin peiuei la potencia uel mismo, al pouei acceuei al haiuwaie ue maneia sencilla. Asi C++ aauio el lenguaje oiientauo a objetos, poi ello se le conoce como C con clases. Sin embaigo cuanuo alguien que viene ue C, comienza a estuuiai C++, uebe ue evitai pensai que es una extension uel lenguaje C lo que est estuuianuo, ya que C++ es mucho ms que eso. C++, se ha uesvinculauo ue muchas picticas habituales en C que eian motivo ue mltiples fallos en la piogiamacion, como el casting incontiolauo, el uso ue la memoiia, ue los punteios, el paso ue paimetios poi iefeiencia, incoipoiacion ue elementos muy tiles como las Colecciones o Conteneuoies y la cieacion ue una libieiia ue incalculable valoi paia el piogiamauoi en C++, las STL (Stanuaiu Template Libiaiies). Aunque 0NIX y Linux fue cieauo uesue C, otios opeiativos como Winuows, nacieion ue C++. Los sistemas con entoino gifico, eian mucho ms sencillos ue uesaiiollai usanuo el paiauigma uel lenguaje oiientauo a objetos, que la meia piogiamacion estiuctuiaua ue C. En 1991, uos piogiamauoies noiuegos (Eiiik Eng y Baavaiu Noiu ue Quasai Technologies, ms taiue Tiolltech) cieaion un Fiamewoik en C++ que peimitieia usai el mismo couigo en el uesaiiollo ue una u0I (inteifaz gifica) tanto paia Winuows como paia 0NIXX11. Inicialmente eia couigo abieito, peio la licencia no eia libie. Entie 199S y 1998 se uesaiiollo con este Fiamewoik un esciitoiio paia uN0Linux que tuvo mucho xito, llamauo KBE que hoy sigue sienuo uno ue los esciitoiios ms usauos ue Linux. uN0 miiaba con iecelo que el esciitoiio ms usauo en Linux no fueia libie, asi que hubo una ieunion entie los uesaiiollauoies ue KBE y Tiolltech, paia aseguiai el futuio ue Qt en una libeiacion bajo licencia BSB. Entie los aos 2uuu y 2uuS se piouujo la libeiacion bajo licencia uPL ue las veisiones ue Qt paia Winuows, Linux y Nacintosh. En }unio ue 2uu8, Nokia se aseguio el uesaiiollo paia sus moviles tanto Symbian como Naemo (pioyecto que al final se ha fusionauo con Noblin ue Intel, paia cieai Neeuo, y competii con Anuioiu ue uoogle) con la auquisicion ue Qt. Actualmente a finales ue 2u1u, Qt acaba ue salii en la veision 4.7 uonue se aauen nuevas caiacteiisticas extiaoiuinaiias paia la cieacion ue uiseos ue fiont-enus paia uispositivos moviles y electiouomsticos, con la entiaua ue QNL (Qt Beclaiative) un lenguaje ueclaiativo paia cieai inteifaces gificos muy vistosos. Qt ya ha siuo poitauo y sopoitauo poi Nokia paia las siguientes platafoimas: LinuxX11 (y otios 0NIX, como Solaiis, AIX, BP-0X, IRIX), Winuows, Nacintosh, Embeuueu Linux, Winuows CENobile, Symbian y Neeuo. Y con uesaiiollo exteino se ha poitauo o se est poitanuo a platafoimas como: 0pen Solaiis, Baiku(Be0S libie), 0S2(Platafoima eCS ue IBN), iPhone y Anuioiu. Como pouemos apieciai, Qt es un Fiamewoik que no paia ue ciecei, y el secieto ue este xito, es no solo su potencia y velociuau fiente a otias alteinativas como }ava (uonue es entie S y 6 veces ms ipiuo), si no poique es atiactivo paia el piogiamauoi y ipiuo paia uesaiiollai, uesue la saliua ue QtCieatoi 2.u, el entoino IBE paia Qt. #
Qt incoipoia un estilo ue piogiamacion a C++, que le hace menos vulneiable a los fallos ue piogiamacion, sobie touo en el manejo ue memoiia (memoiy leaks), y que lo hacen muy agiauable ue caia al uesaiiollauoi. Qu vamos a apienuei en este libio.. Este libio pietenue sei el piimei escalon a subii paia alguien ue habla hispana que quieia apienuei a uesaiiollai aplicaciones multiplatafoima con Qt4. Su conteniuo ha siuo escogiuo, paia pouei cubiii el uesaiiollo ue cualquiei aplicacion ue pioposito geneial. Cualquieia que complete el conteniuo ue este libio con sus ejeicicios y ejemplos, poui uesaiiollai este tipo ue aplicaciones sin gianues pioblemas. Sin embaigo, Qt ciece touos los uias, aauienuo nuevas posibiliuaues, nuevos mouulos y nuevas clases, y a uia ue hoy es tan extenso que ningn libio en ningn iuioma contiene una uesciipcion completa uel mismo. Poi lo que la nica fuente uonue pouemos iecogei esa infoimacion, es la misma ayuua que el SBK uel Fiamewoik nos piopoiciona con su asistente (Qt Assistant), peio esta uocumentacion est esciita en ingls nicamente. Es poi tanto necesaiio pouei leei y sei capaz ue uesenvolveise en este iuioma, paia usai toua la capaciuau que Qt nos pueua ofiecei. Poi lo tanto, este libio consigue sentai unas bases claias en el conocimiento ue Qt4, peio paia ii ms all es necesaiio sabei usai la uocumentacion en ingls que acompaa a toua veision uel Fiamewoik. Los temas estn oiuenauos ue maneia piogiesiva, paia que nauie se pieiua. El lenguaje usauo es sencillo y uiiecto, poi lo que el conteniuo ue ningn tema exceue las 8 pginas ue extension, y poi tanto pueue cubiiise en un solo uia. Acompaanuo a estos temas, est el couigo ue los ejemplos, y los ejeicicios iesueltos, que nos complementan lo apienuiuo. No pase ue un tema al siguiente, sin leei touo este couigo, compienueilo, e intentai hacei los ejeicicios que se pioponen. Este libio piopone una base funuamental paia el conocimiento ue Qt oiientauo al uesaiiollo ue aplicaciones ue pioposito geneial, y sin uominai esta base soliua, no poui seguii avanzanuo confoime a sus necesiuaues futuias en nuevos aspectos uel Fiamewoik. Tiataiemos poi tanto touos los aspectos funuamentales uel uesaiiollo ue aplicaciones u0I con touos sus componentes posibles, capaciuaues como el uibujo, impiesion ue uocumentos, acceso a bases ue uatos, acceso a la ieu, la piogiamacion concuiiente, acceso al sistema ue ficheios y el uso ue los piincipales tipos ue iecuisos. Y lo mejoi ue touo, es que este libio es libie, y se poui uistiibuii libiemente y sin coste alguno. Tiatamos ue beneficiainos con la cieacion ue una comuniuau ue piogiamauoies en espaol, nutiiua y piolifica. Poi touo ello, bienveniuo a esta maiavillosa aventuia que es apienuei C++Qt4.
$
123456 36 782962438:
1.- Instalacion uel Qt SBK 7 2.- Compilacion 9 S.- Estiuctuia ue una aplicacion 11 4.- La piimeia aplicacion Qt 1S S.- Q0bject, metaobjetos y piopieuaues 17 6.- El manejo ue la memoiia 2S 7.- Seales y Slots 27 8.- QSignalNappei SS 9.- Nanejo ue cauenas en Qt SS 1u.- Colecciones en Qt S9 11.- Tipos Qt 4S 12.- Sistema ue ficheios 4S 1S.- Esciituia y Lectuia ue ficheios 47 14.- Wiugets y Layouts 49 1S.- ventanas ue Bilogo SS 16.- Nouelo, vista y Contiolauoi. Intiouuccion. 61 17.- QListWiuget y QTableWiuget 6S 18.- Qt Cieatoi 67 19.- Nain Winuows 69 2u.- Besaiiollo ue una aplicacion completa 7S 21.- Layout a fonuo 8S 22.- Bases ue uatos 89 2S.- Reues TCPIP 9S 24.- Piogiamacion concuiiente 99 2S.- uificos e Impiesion 1uS 26.- Recuisos Exteinos 1u7 27.- Bscate la viua 1u9 28.- Instalauoies 111 Bibliogiafia 119
%
&
)%/" ; 0&+)"<"70-& '%< () +'=
A piogiamai, se apienue piogiamanuo, poi lo que antes ue comenzai a iecibii una ingente cantiuau ue infoimacion teoiica, hay que estai en la uisposicion ue pouei piobai touo lo que se iecibe ue una maneia pictica, paia que asi el ciclo uiuctico se culmine poi completo. Poi ello, antes ue naua, vamos a piepaiainos un entoino ue uesaiiollo lo suficientemente comouo paia pouei acuuii a l caua vez que lo necesitemos, mientias vamos apienuienuo nuevos conceptos. Qt es un Fiamewoik completo multiplatafoima, poi lo que vamos a vei como se instala en los S tipos ue sistemas ms extenuiuos hoy uia, a sabei: Winuows, Linux y Nac0SX.
>?@?A:6 6B +'= 36 0296A269 Qt se pueue empezai a conocei e incluso a usai nicamente en su veision 0pen Souice (uPL o LuPL), la cual pouemos bajai en su ltima veision ue la web http:qt.nokia.comuownloaus . Be touos los aichivos que alli se nos ofiece, iecomenuamos pulsai en la seccion LuPL y bajaise las veisiones "Complete Bevelopment Enviionment", que auems son las ms extensas, ya que no solo incluyen el SBK, si no tambin el Qt Cieatoi, que es el IBE ue uesaiiollo, auems ue muchas otias heiiamientas ue uesaiiollo, ejemplos y uocumentacion, eso si, en peifecto ingls. Poi lo que es ue gian ayuua al menos sei capaz ue leei y compienuei un poco el ingls infoimtico.
02:9?B?54C2 62 D4238E: FG H49:
0na vez nos hemos bajauo el ficheio qt-suk-win-opensouice-2uxx.xx.exe (uonue las xx.xx son nmeios iefeientes a ao y veision uel empaquetauo). Esta instalacion lleva incluiuo el paquete NinuW que compienue el compilauo y heiiamientas gcc , g++ y make. Solamente hay que ejecutailo, y seguii las instiucciones poi uefecto. Al final obtenemos un icono en el Esciitoiio uel Qt Cieatoi. En el pioximo tema, veiemos la estiuctuia ue lo que nos ofiece uicho IBE. No obstante pueues vei que en el men ue Aplicaciones, apaiece el giupo "Qt SBK by Nokia .", y uentio ue l, pouemos vei heiiamientas como Qt Bemo, uonue se nos piesenta una seiie ue aplicaciones ue ejemplo, uonue pouiemos ejecutailas pues ya vienen compilauas paia nuestia platafoima, y en la subcaipeta Tools, tenemos el Qt Assistant que sei nuestio asistente y ayuua uocumental paia buscai la infoimacion que necesitemos uel SBK. El Qt Besignei que nos seivii paia uiseai u0Is, y el Qt Linguistic que nos ayuuai a implementai tiauucciones a otios iuiomas ue nuestia aplicacion. El sistema ya est listo y piepaiauo paia sei usauo en nuestio cuiso. Ya pueues ii uiiecto al siguiente tema.
02:9?B?54C2 62 <42IJ FG K L* H49: Aunque algunas uistiibuciones Linux pueuen bajaise ue sus iepositoiios oficiales una veision ue Qt e incluso uel Qt Besignei, nosotios vamos a optai poi instalai, la ltima veision completa en nuestia uistio. '
Paia ello nos bajamos el ficheio qt-suk-linux-x86-opensouice-2uxx.xx.bin (uonue las xx.xx son nmeios iefeientes a ao y veision uel empaquetauo), paia Linux S2 bits o el ficheio qt-suk-linux-x86_64-opensouice-2uxx.xx.bin paia Linux 64 bits. Antes ue instalailo, es necesaiio tenei instalauos uCC, u++ y Nake, que en las veisiones ueiivauas ue Bebian se hace con un meio "apt-get install builu-essential" y en las basauas en Reu Bat se hace con una "yum install gcc gcc- c++ make". 0n vez bajauos los ficheios, uesue ioot le uamos peimiso ue ejecucion (chmou +x), y lo ejecutamos uesue la consola. Se abiii una ventana ue uilogo y pouemos instalailo en el uiiectoiio que queiamos (poi ejemplo optqtsuk-2uxx.xx). 0na vez se acaba la instalacion, vamos a piepaiai el PATB paia nuestia sesion ue usuaiio que poui acceuei al IBE. Asi poi ejemplo en el uiiectoiio ue usuaiio, en .bash_piofile, aauiiemos al PATB actual lo siguiente: PATB=$PATB:optqtsuk-2u1u.uSqtbin: optqtsuk-2u1u.uSbin volvemos a ieiniciai la sesion, y ya pouiemos acceuei uesue la consola a las uifeientes heiiamientas, como al Qt Cieatoi, tecleanuo qtcieatoi, al Qt Bemo, tecleanuo qtuemo, al Qt Assistant, tecleanuo assistant, al Qt Linguistic, tecleanuo linguistic. En el Qt Bemo, uonue se nos piesenta una seiie ue aplicaciones ue ejemplo, uonue pouiemos ejecutailas pues ya vienen compilauas paia nuestia platafoima. El Qt Assistant que sei nuestio asistente y ayuua uocumental paia buscai la infoimacion que necesitemos uel SBK. El Qt Besignei que nos seivii paia uiseai u0Is, y el Qt Linguistic que nos ayuuai a implementai tiauucciones a otios iuiomas ue nuestia aplicacion. Pueues haceite unos uispaiauoies (accesos uiiectos) en tu esciitoiio, buscanuo el ficheio en optqtsuk-2uxx.xxqtbin, y el icono en optqtsuk-2uxx.xxbin (Nokia-QtCieatoi- 128.png). El sistema ya est listo y piepaiauo paia sei usauo en nuestio cuiso. Ya pueues ii uiiecto al siguiente tema.
02:9?B?54C2 62 /?5-+M Bajauo el ficheio qt-suk-mac-opensouice-2uxx.xx.umg y pieviamente instalauo XCoue uel uisco ue Nac0SX coiiesponuiente, solo tenemos que instalailo siguienuo las opciones poi uefecto uel instalauoi. 0na vez teiminaua la instalacion, pouemos aauii accesos uiiectos a nuestia baiia a las heiiamientas que pouiemos encontiailas en BevelopeiApplicationsQt. Los ejemplos se han instalauo en BevelopeiExamplesQt. El sistema ya est listo y piepaiauo paia sei usauo en nuestio cuiso. Ya pueues ii uiiecto al siguiente tema.
-9A?: NB?9?O8AP?: La instalacion en otias platafoimas, no est explicaua en este libio, ya que no se tiata ue un tema ue caictei intiouuctoiio ni ue pioposito geneial. No obstante pueues obtenei ms infoimacion al iespecto en http:uoc.tiolltech.com4.6suppoiteu-platfoims.html y en otias secciones ue la web ue Qt Nokia.
(
)%/" G 7-/#0<"70Q&
0na vez ya tenemos nuestios SBK y heiiamientas ue uesaiiollo peifectamente instalauas, vamos a configuiai el Qt Cieatoi, y a explicai someiamente su uso, compilanuo un ejemplo. Antes ue comenzai a piogiamai, seiia inteiesante uestinai un uiiectoiio o caipeta uel sistema local paia guaiuai los ejemplos y ejeicicios que vamos a hacei. Pueue sei en cualquiei caipeta o uiiectoiio, y uentio ue esta se iin guaiuanuo en caipetas caua uno ue los pioyectos que vayamos usanuo. En esa misma caipeta pueues tambin uescompiimii touos los ejemplos que van acompaanuo a este libio, ue maneia que si uestinamos la caipeta qtsic paia este menestei, los ejemplos estain en caipetas como qtsictemaXX (uonue XX es el nmeio uel tema). vamos poi tanto ya a abiii el Qt Cieatoi, ejecutnuolo. Se nos abiii el IBE con una ventana sobie l como sta:
Pouemos pulsai sobie Cieate Pioject. paia cieai un nuevo pioyecto, u 0pen Pioject. paia abiii uno pieexistente. Si activamos el tab Bevelop, pouiemos vei las sesiones iecientes que hemos abieito y asi acceuei a ellas uiiectamente. Bien vamos a pulsai en 0pen Pioject. y vamos ii a la caipeta temau2 y uentio ue ella, vamos a entiai en la caipeta application, vamos a seleccionai el ficheio application.pio, y vamos a abiiilo. Al abiiise, pouemos vei la uisposicion uel Qt Cieatoi. A la izquieiua, hay una baiia ue heiiamientas, uonue en la paite supeiioi ue la misma, se pueue elegii la heiiamienta ue uesaiiollo a usai. Be aiiiba a abajo: Welcome (Bienveniua), Euit (euitoi, que es su foima habitual paia intiouucii couigo), Besign (acceso al Qt Besignei, paia cieai la u0I euitanuo ficheios tipo *.ui), Bebug (paia uebugeai un ejecutable), Piojects (que nos peimite configuiai opciones uel pioyecto) y Belp (paia acceuei al asistente). En la zona infeiioi ue esta misma baiia, encontiamos un icono ue una pantalla ue oiuenauoi, uonue en la paite supeiioi, inuica el nombie uel pioyecto actual poi uefecto, y si el mouo Builu es Bebug o Release (poi uefecto lo tenuiemos en Bebug, hasta que vayamos a geneiai una aplicacion paia sei uistiibuiua). Bebajo estn las heiiamientas ue Run (ejecutai), Stait Bebug (comenzai uebug) y Builu All (constiuiilo touo). )*
A la ueiecha ue esta baiia ue heiiamientas, peio an en el lauo izquieiuo, nos queua en la zona supeiioi, el ibol logico ue los ficheios que componen el pioyecto. Pouemos seleccionai uentio ue l, cualquiei ficheio, y hacienuo uoble clic sobie l, abiiilo paia euicion. En la paite infeiioi apaiecein el listauo ue touos los ficheios que tengamos abieitos, ue maneia que pouemos acceuei uiiectamente a ellos, pulsanuo sobie sus nombies, o ceiiailos, pulsanuo sobie la X que apaiece si uejamos un tiempo el cuisoi sobie un nombie ue ficheio. La paite ueiecha supeiioi, es uonue pouiemos vei el couigo ue los ficheios, y en la infeiioi, los mensajes uel compilauoi, uebuggei, etc. vamos ahoia a configuiai el entoino paia tiabajai con los ejemplos ue nuestio libio. Paia ellos entiamos a las piefeiencias, que en Winuows y Linux, est en Tools->0ptions, y en Nac0SX, est en Qt Cieatoi->Piefeiences. Nos apaiecei una ventana con opciones, las cuales vamos a uejai touas poi uefecto excepto en Piojects, uonue vamos a fijai el uiiectoiio paia nuestios pioyectos, y en Besignei, nos vamos a ceicioiai ue tenei la opcion "Aggiegation as a pointei membei" y naua ms (como pueues vei en el gifico infeiioi).
Pulsamos en 0K y nos vamos a Piojects en la heiiamientas ue la izquieiua. Alli seleccionamos Euitoi Settings, y ponemos como Befault File Encouing "0TF-8". Pulsamos ahoia en Euit, y nos vamos abajo paia pulsai en Run. Be esta maneia se compilai el pioyecto actual, y se ejecutai una vez compilauo. Nos apaiecei una ventana ue un sencillo euitoi ue texto con su baiia ue heiiamientas, que coiiesponue a la aplicacion que acabamos ue compilai y ejecutai. Si en la baiia ue la izquieiua sobie la zona infeiioi, hubieia apaieciuo una baiia en iojo con un nmeio (el ue eiioies), esto nos inuicaiia que hay eiioies en la compilacion o en el linkauo, poi lo que habiia que ievisai que la instalacion sea coiiecta, y la aplicacion que se ha caigauo. En los siguientes temas, iiemos piofunuizanuo en el uso uel Qt Cieatoi como IBE ue uesaiiollo uel SBK ue Qt. )62R? 62 5I629? SI6 T6P8: NA6N?A?38 6B 6298A28 N?A? 36:?AA8BB?A 2I6:9A?: ?NB45?54826:U N6A8 ?I2SI6 T?K? 582:6RI438 58PN4B?AB?: 62 :I V6A:4C2 $6B6?:6 W28 '6HIRXU 28 N83AY N8A9?AB?: 9?B 5I?B ? 89A? PYSI42? N?A? SI6 OI2548262 9?B 5I?BU K T?HAY SI6 98P?A 546A9?: 5I6:94826: 62 582:436A?54C2 N?A? SI6 :6 NI63?2 4PNB6P629?A 6 42:9?B?A :42 NA8HB6P?: 62 I2 :4:96P? O42?B 36 NA83I554C2Z )838 6BB8 B8 V6A6P8: 582 369624P46298 62 6B 96P? G[Z '6 P8P6298U V?P8: ? ?NA6236A ? 36:?AA8BB?AU N6A8 :4 :6 BB6V? B8: 6@65I9?HB6: ? 89A? PYSI42? :42 6B +'= 42:9?B?38U :6N? SI6 28 V?2 ? OI25482?A 36 ?296P?28Z
))
)%/" F %+)$\7)\$" '% \&" "#<07"70Q& ()*
Antes ue comenzai a vei la piimeia aplicacion en Qt4, vamos a vei cual es la estiuctuia ue una aplicacion en Qt, ue esta maneia comenzaiemos a vei el cuauio uesue lejos, antes ue empezai a auentiainos en los uetalles. Esta es la foima ms ueseable ue comenzai un estuuio que pietenue sei los ms apiovechable posible. Qt, posee una foima ue oiuenai el couigo, que uesue el piincipio es funuamental conoceilo, paia cieai couigo sencillo y legible uesue el piimei momento. No impoita lo sencillo o complejo que pueua sei un pioyecto, si el couigo se estiuctuia bien, siempie poui sei manteniuo ue una maneia ms sencilla y eficaz. %:9AI59IA? 36 I2 NA8K6598 Touo pioyecto con inteifaz visual (u0I) en Qt, tiene los mismos elementos que son: 1.- ./01&$*, 2& 3*$4+5#$/*, 63*$4,7.- Con la extension *.ui, caua ficheio uesciibe en lenguaje XNL el inteifaz gifico ue foimulaiios o ventana ue la aplicacion. Poi lo tanto caua ficheio *.ui es una ventana, peio no touas las ventanas ue la aplicacion tienen que estai en un ficheio *.ui, ya que se pueuen implementai con couigo C++. Estos ficheios son uiseauos gificamente en el Qt Besignei, el cual geneia automticamente el couigo XNL ue uichos ficheios. 2.- ./01&$*, 8#9&0&$# 61&$,7.- Con la extension *.h . Lo ms iecomenuable es que la ueclaiacion ue caua clase vaya en un ficheio cabeceia poi sepaiauo, y el nombie uel ficheio coinciua con el nombie ue la clase que se ueclaia. Asi poi ejemplo, si vamos a uesaiiollai una clase llamaua calculatoi, el ficheio cabeceia que la ueclaia poi completo la llamaiiamos "calculatoi.h". S.- ./01&$*, .+&%)& 6,*+$0&,7.- Con la extension *.cpp . Lo ms iecomenuable es que la implementacion o uesaiiollo ue caua miembio ue una clase, est conteniuo poi completo en un ficheio con el mismo nombie que la clase que implementa. Asi poi ejemplo, la implementacion ue la clase calculatoi, estaiia en el ficheio ue nombie "calculatoi.cpp". Bentio ue los ficheio fuente, siempie hay uno que contiene la funcion piincipal (main) y cuyo nombie sei "main.cpp". 4.- ./01&$* 2& -$*:&0)* 6-$*"&0)7.- Con la extension *.pio . Es un ficheio que pueue geneiaise y iellenaise automticamente si hemos cieauo el couigo con el Qt Cieatoi, o que pueue no existii, y ueba antes sei cieauoi con el comanuo "qmake -pioject" antes ue la compilacion uefinitiva. El nombie uel mismo coinciuii con el ue la caipeta ue pioyecto cieaua. Si nuestio pioyecto se llama calculatoi, el ficheio pioyecto tomai el nombie "calculatoi.pio". Touos los ficheios ue un pioyecto Qt, es iecomenuable que se encuentien en un mismo uiiectoiio iaiz, cuyo nombie coinciua con el nombie completo uel pioyecto. veamos ahoia la estiuctuia inteina ue caua uno ue los tipos ue ficheios mencionauos.
]45T6A8 O8APIB?A48 Se tiata ue un ficheio esciito en couigo XNL con la uesciipcion ue touos los elementos uel inteifaz visual ue uno ue los foimulaiios uel pioyecto. No es necesaiio conocei la estiuctuia exacta uel mismo, y ue hecho, si en el Qt Cieatoi, haces uoble click sobie un ficheio *.ui, se te abiii uiiectamente el Qt Besignei, ue maneia que se mostiai la inteifaz gifica. En la baiia ue heiiamientas ue la izquieiua, tenuis que pasai uel mouo "Besign" al mouo "Euit" paia pouei vei el couigo XNL que siempie tenui la siguiente estiuctuia.
]45T6A8 5?H656A? W5B?::2?P6ZTX vamos a paitii ue la iuea ue solamente ueclaiai una clase en un solo ficheio.
#ifndef CLASSNAME_H #define CLASSNAME_H
#include <QClasePadre> // podemos declarar aqu otras clases del proyecto que // sean usadas en la implementacin de esta clase class Claseincluida;
class Classname : public QClasePadre { // el contructor con un solo parmetro lo declararemos // siempre como explicit, y al menos con el puntero a la // clase padre inicializado a NULL explicit Classname (QClasePadre *parent = 0);
// Cuerpo con la declaracin de todos los miembros de la clase
.. }; #endif
Como pueues obseivai, es muy iecomenuable el ponei en la piimeia, segunua y ltima lineas uel mismo, las conuicionales al piepiocesauoi paia evitai la ieinclusion ue este couigo ms ue una vez. Bespus, incluimos con #incluue las clases Qt usauas en la implementacion ue esta clase, y la ueclaiacion ue clases nuestias incluiuas en este pioyecto que son usauas en la implementacion ue esta clase. Finalmente tenemos la ueclaiacion ue la clase misma con touos los elementos miembio.
]45T6A8 OI6296 W5B?::2?P6Z5NNX
#include "classname.h"
Classname:: Classname (QClasePadre *parent) : QClasePadre (parent) { // implementacin del contructor de la clase }
// implementacin del resto de miembros de la clase classname ..
)"
Piimeio incluimos la cabeceia ue nuestia clase. Luego implementamos el constiuctoi, e inicializamos el constiuctoi ue la clase pauie siempie lo piimeio. Bespus implementamos el iesto ue los miembios ue la clase.
Fichero fuente principal (main.cpp)
#include <QModulo> #include "claseinterfaz.h"
int main(int argc, char **argv) { QApplication a(argc, argv);
claseinterfaz w; w.show(); // Mucho ms cdigo que sea necesario
return a.exec(); }
Piimeiamente incluimos el mouulo necesaiio paia el couigo que vamos a incluii en la funcion main(). Lo ms logico es que vaya incluiua la clase inteifaz, que ciea la ventana piincipal. Bicha ventana poui sei un wiuget (QWiuget), una ventana ue uilogo (QBialog) o una ventana piincipal (QNainWinuow). Piimeiamente cieamos una instancia ue QApplication que pueue iecibii aigumentos ue la linea ue comanuos. Luego instanciamos la clase inteifaz, mostiamos uicho inteifaz, y finalmente con QApplication::exec() entiamos en el bucle ue eventos paia inteiactuai con el inteifaz mostiauo.
La piimeia y ltima lineas ue couigo ue la funcion main(), solo son necesaiias si se tiata ue una aplicacion con inteifaz gifico (u0I). Si se tiata ue una aplicacion ue consola, no se usain, y en puesto ue instanciai un clase inteifaz, se haiia uso ue couigo no gifico paia consola. Baiemos uso ue piogiamas paia consola, paia estuuiai y iefoizai clases ue Qt que no son gificas, paia simplificai el couigo y facilitai el apienuizaje ue los conceptos.
)#
)$
)%/" * <" #$0/%$" "#<07"70Q& (9
La mayoiia ue libios que ensean un lenguaje ue piogiamacion, siempie empiezan poi uemostiai la sencillez uel lenguaje con la tipica aplicacion Bola Nunuo. Y es una tiauicion que se ha peipetuauo poi los tiempos ue los tiempos. Sinceiamente me paiece que es una tiivialiuau, ya que no ensea absolutamente naua sobie el lenguaje ms all ue impiimii un mensaje en pantalla, peio en un munuo uonue touos vamos coiiienuo y necesitamos vei los iesultauos antes ue iecoiiei el camino, ha teiminauo imponinuose. Bien es cieito que Qt no es un lenguaje, si no un Fiamewoik que en este libio en paiticulai lo hemos ueuicauo al uesaiiollo ue Qt en C++. Asi que el lenguaje C++, es un conocimiento pievio que se piesupone antes ue leei la piimeia linea ue este libio, poi lo que un Bola Nunuo queua an ms uescolocauo, peio en fin, sucumbiiemos a la tenuencia geneializaua.
Paia uesaiiollai uicha aplicacion, vamos a usai el Qt Cieatoi, y puesto que Qt se pueue usai no solo paia cieai inteifaces gificas, si no tambin aplicaciones ue consola, vamos a vei las uos posibles aplicaciones Bola Nunuo.
,8B? PI238 582 ^\0 Abiimos Qt Cieatoi, o si ya lo tenemos abieito, abiimos un nuevo pioyecto pulsanuo en File->New File oi Pioject. Apaiecei una ventana como la ue abajo.
Elegimos 0thei Pioject -> Empy Qt Pioject (un pioyecto vacio). Be esta foima no se nos cieai ningn couigo automticamente, touo lo haiemos nosotios manualmente. Pulsamos el boton Choose. y apaiece una nueva ventana, uonue ponuiemos el nombie uel pioyecto que sei "holamunuo" y abajo en Cieate in, escogeiemos un uiiectoiio uonue tenuiemos touos nuestios pioyectos. Pulsamos Continue y luego Bone. A la izquieiua en la columna ue pioyectos (Piojects) nos apaiece, la caipeta ue nuestio nuevo pioyecto, y solo el ficheio holamunuo.pio que Qt Cieatoi se encaigai ue ii iellenanuo poi nosotios. Bacemos clic con el boton ueiecho sobie el pioyecto y uel menu emeigente escogemos la penltima opcion (Auu New.). Escogemos C++ en Files anu Classes, y C++ Souice File en la columna ue la ueiecha. Pulsamos Choose. y le ponemos el nombie al ficheio "main.cpp" en Name. Pulsamos Continue y Bone. Ahoia apaiece una nueva caipeta llamaua Souices con un ficheio main.cpp uentio ue ella. )%
Bacienuo uoble clic sobie main.cpp, pouiemos vei a la ueiecha el lienzo en blanco piepaiauo paia empezai a esciibii el couigo en l. vamos a esciibii el siguiente couigo: #include <QApplication> #include <QLabel>
int main(int argc, char **argv){ QApplication a(argc,argv);
QLabel l("Hola mundo"); l.show();
return a.exec(); }
Como se pueue vei hemos usauo una clase QLabel paia cieai el letieio uonue ponui el mensaje "Bola munuo". Puesto que usamos uos clases en este ficheio ue Qt (QApplication y QLabel), hemos teniuo que incluii sus cabeceias.
,8B? PI238 :42 ^\0 #include <QDebug>
int main(int argc, char **argv) { qDebug() << "Hola mundo\n";
return 0; }
La clase QBebug es peifecta paia sacai mensajes poi consola, y tiene sobiecaigauo el opeiauoi << paia que actue ue maneia similai a como lo hacia stu::cout en la STL ue C++. Sigue los ejeicicios ue este tema uonue se compila y se ejecutan estos 2 simples ejemplos.
)&
)%/" _ (-H@659U P69?8H@698: K NA8N463?36:
Llego el momento ue meteinos en haiina, y paia ello mejoi es empezai a conocei las paiticulaiiuaues ue Qt que la hacen uifeiente a las STL. Paia ello lo mejoi es comenzai poi la clase piincipal, pauie ue la mayoiia ue las clases que componen Qt4, esa clase es Q0bject. Luego veiemos la estiuctuia global ue clases que componen el Fiamewoik y tiabajaiemos con una ue las cualiuaues ms inteiesantes ue Qt, la /%)$*,-&00/;%.
<? 5B?:6 (-H@659 uian paite ue la magia uesplegaua en el Fiamewoik Qt, ueiiva ue la clase Q0bject, que es la clase piincipal. Touos los wiugets usauos paia cieai la u0I ueiivan ue esta clase. Be hecho Qt uespliega gian paite ue lo que Qt es: seales y slots, piopieuaues y manejo ue memoiia sencillo. Qt extienue a C++ con nuevas caiacteiisticas, ue las cuales uos son intiouuciuas poi esta misma clase como son: el mouelo ue intiospeccion, y las conexiones entie objetos meuiante seales y slots. Si ievisas la uocumentacion ue Q0bject en el asistente (Qt Assistant), veis entie sus miembios touas estas caiacteiisticas. Q0bject, poi tanto, es la clase base ue la mayoiia ue las clases uel fiamewoik Qt, sin embaigo, no ue touas. Las clases que no uepenuen ue Q0bject son: - Clases ue piimitivas gificas que iequieien tenei poco peso, sienuo ms sencillas como: Quiauient, QPaintei, QScieen, QPalette. - Clases conteneuoias ue uatos como: QChai, QStiing, QList, QNap, QBash.. - Clases que necesiten sei copiables, ya que las clases ueiivauas ue Q0bject no son copiables. La piimeia caiacteiisticas impoitante que tiene Q0bject, es que no es copiable, toua instancia ue la misma es nica. Touo objecto Q0bject es nico e inuiviuual. Poique los objetos tienen nombie (piopieuau *9"&0)<#4&), y este es nico paia caua objeto, y esto es funuamental paia implementai la intiospeccion. Caua objeto, esta situauo en algn lugai especifico ue la jeiaiquia ue clases Q0bject, y eso no iequieie sei copiable. Finalmente caua objeto, tiene conexiones con otios objetos meuiante conexiones seal-slot que veiemos ms auelante, y eso no pueue sei copiauo. Poi touas estas iazones, los objetos ue Q0bject, son nicos e incopiables en tiempo ue ejecucion como poi ejemplo si lo es un QStiing (una cauena). C++ es extenuiuo en Qt paia uotailo ue caiacteiisticas funuamentales paia el fiamewoik. 0na ue ellas, son los !"#$%$#&' . Los metauatos, llevan infoimacion sobie el objeto instanciauo, tales como el nombie uel objeto, el nombie ue su clase, sus objetos hijos, sus piopieuaues, sus seales y slots, toua una seiie ue infoimaciones sobie la clase uel mismo. Esto nos peimite una ue las ms impoitantes caiacteiisticas ue Qt, que es la intiospeccion, que facilita mucho integiai Qt con otios lenguajes ue sciipting y entoinos uinmicos (Ruby, Python, PBP, etc). Instanciauo un Q0bject, pouiiamos obtenei ue l infoimacion sobie el mismo a tiavs ue los metauatos. 0na foima, seiia meuiante el mtouo miembio Q0bject::inheiits(const chai* className), que nos peimitiiia hacei un casting uinmico sin usai el RTTI (lo cual pueue evitai muchos eiioies uel piogiamauoi): if(object->inherits("QAbstractItemView")){ QAbstractItemView *view = static_cast<QAbstractItemView *>(widget); ............ }
)'
0no ue los miembios ms impoitantes paia acceuei a los metauatos ue una clase, y poi tanto paia implementai la intiospeccion es !"#$()*"+#,- . Bevuelve un objeto ue la clase QNeta0bject, que si miiamos en el asistente touos sus miembios, pouiemos obseivai toua la infoimacion que pouemos conseguii en $+%=)/4& ue un objeto cualquieia. object->metaObject()->className(); // devuelve un char* con el nombre de la clase object->metaObject()->indexOfProperty("width");
Los metauatos, son iecabauos poi el moc (meta-object compilei) uel piopio couigo ueclaiativo ue las clases en los aichivos cabeceia. Lo piimeio que busca el moc es que la clase se ueiive ue Q0bject ue maneia uiiecta o inuiiecta, paia buscai en ella touos los metauatos y geneiai el couigo necesaiio paia ellos. Luego busca NACR0S uel tipo Q_ , como: Q_0B}ECT, Q_CLASSINF0, etc; que aauen infoimacion ue la clase. Finalmente busca palabias clave aauiuas poi Qt como slots y signals, que ueclaian los mtouos miembios ue la clase que se encaigain ue la conectiviuau ue la misma con objetos ue otias clases. El moc con touo esto geneia automticamente couigo que guaiua en ficheios que comienzan poi moc_*.cpp . 0tia funcion miembio intiospectiva muy impoitante que incoipoia Q0bject es /01%+203%4"1. La fiima ue la misma es: (<4:9`)a (-H@659bbO4237T4B3A62 W 582:9c(+9A42Rcdc1$!"ce (+9A42RWX X 582:9 que nos uevuelve una coleccion ue objetos hijos ue la clase cuyo nombie se pase como aigumento. QList es una clase template que veiemos ms auelante, peio similai a una lista o vectoi ue STL. Poi ejemplo, si queiemos obtenei los wiugets que son hijos ue un wiuget en paiticulai a tiavs ue su nombie (wiugetname), pouemos usai un couigo como este: QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");
Poi ejemplo, paia obtenei una lista con touos los botones uel tipo QPushButton, conteniuos como hijos ue paientWiuget, pouemos usai un couigo como el que sigue: QList<QPushButton *> allPushButtons = parentWidget.findChildren<QPushButton *>();
#A8N463?36: 36 I2 8H@698 Touo objeto, necesita guaiuai su estauo en algn sitio, uonue se uefina poi completo el estauo uel mismo y touas sus paiticulaiiuaues, esto es lo que llamamos 54&50"%$%"' ue un objeto. En el Qt Besignei, a abiii un ficheio foim (*.ui), pouemos pulsai sobie cualquieia ue los elementos que hay en el foim, y a la ueiecha en la paite infeiioi, vei touas las piopieuaues que uicho objeto tiene, y los valoies que esas piopieuaues toma paia ese objeto en paiticulai. Qt guaiua esas piopieuaues como metauatos, y hace uso ue una macio piopia paia ello: Q_PROPERTY(type name READ getFunction [WRITE setFunction] [RESET resetFunction] [NOTIFY notifySignal] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [CONSTANT] )
)(
Esta macio se pone en la ueclaiacion ue la clase, en el ficheio cabeceia ue la misma, uespus ue la macio Q_0B}ECT. Las paites entie coichetes (|j) no son obligatoiias. vamos a uetallai caua paite ue esta ueclaiacion: ):-&.- es el tipo ue la vaiiable que guaiuai el estauo ue uicha piopieuau uel objeto (QStiing, int.). %#4&.- es el nombie piopio ue la piopieuau en cuestion (wiuth, height..) >&).+%0)/*%.- nombie ue la funcion gettei o que lee el valoi ue la piopieuau (lo veiemos ms auelante) ,&).+%0)/*%.- nombie ue la funcion settei o que establece o cambia el valoi ue la piopieuau (lo veiemos ms auelante) $&,&).+%0)/*%.- nombie ue la funcion que pone el valoi poi uefecto a la piopieuau. %*)/3:(/>%#5.- nombie ue la seal (signal) que se piouucii inmeuiatamente uespus ue que el valoi ue la piopieuau sea cambiauo. ?&,/>%#95&.- nos uice si uicha piopieuau es accesible uesue el entoino ue uiseo, Qt Besignei. (0$/-)#95&.- nos uice si uicha piopieuau es accesible uesue el entoino ue sciipt ue Qt. ()*$&2.- la mayoiia ue piopieuaues son guaiuauas, y establecen el estauo ue un objeto en un momento concieto, otias toman valoies ue otias piopieuaues (poi ej. wiuth es paite ue size) y no son guaiuauas. @,&$.- es una piopieuau mouificable poi el usuaiio ue la aplicacion (poi ej. isCheckeu() en una QCheckBox). 8*%,)#%).- las piopieuaues ueclaiauas constant, no pueuen sei cambiauas en la instanciacion ue la clase, si no entie instanciaciones ue clases.
La gian mayoiia uel tiempo usaiemos meiamente las secciones $%"' y D$0)% paia nuestias piopieuaues, y si nuestia clase es paite ue un nuevo wiuget visual uiseauo poi nosotios, aauiiemos '%+0^&"><% tiue, y pueue que \+%$ tiue, si esta pueue sei cambiaua poi el usuaiio que use la aplicacion (no el piogiamauoi). La ueclaiacion ue una nueva piopieuau, implica una seiie ue aauiuos en los miembios ue la clase a la que peitenece, y estos son: - El constiuctoi uebe ue poneile un valoi inicial, la cual tambin pouiia sei un paimetio uel mismo, y asi pouei inicializai su valoi poi paite uel piogiamauoi en su instanciacion. - Bebe ue habei una funcion miembio que se encaigai ue la iecogiua uel valoi actual ue esa piopieuau. Es lo que llamamos un gettei. Y esta funcion uebe estai en la paite pblica paia pouei sei usaua uesue fueia ue la clase misma, a la que llamamos settei ue la piopieuau. Seiia bueno que se llamaia getPiopieuau() o Piopieuau(), e isEstauo_Piopieuau() si uevuelve un bool. - Pueue habei una funcion miembio que se encaigue ue establecei o cambiai el valoi ue piopieuau. Seiia bueno que se llamaia setPiopieuau(valoi_ue_la_piopieuau). - Bebe ue habei una vaiiable piivaua, que contenga el estauo ue la piopieuau en caua momento, ue maneia que esta no pueua sei uiiectamente accesible fueia ue la clase. En una palabia, los gettei y settei ue una piopieuau, son el inteifaz ue la piopieuau ue uicha clase con el iesto ue objetos, y solo a tiavs ue ellos, el iesto ue la aplicacion poui acceuei a uicha piopieuau. Pongamos un ejemplo sencillo ue piopieuau en una clase. Piimeio comenzaiemos con la ueclaiacion ue los miembios ue la clase en su ficheio cabeceia. !*
// Fichero angleobject.h class AngleObject : public QObject { Q_OBJECT QPROPERTY(qreal angle READ angle WRITE setAngle)
Si obseivas, veis que angle es una piopieuau que se va a guaiuai en una vaiiable uel tipo qieal (que es un typeuef ue uouble en Qt, un nmeio ieal ue uoble piecision). La vaiiable la ponemos como piivaua bajo el nombie ue m_angle (notacion especial paia uistinguii vaiiables miembio). La funcion gettei es angle() que como vemos al no cambiai el estauo uel objeto pouemos ueclaiaila como const. La funcion settei va a sei setAngle() y en la instanciacion al cieai un objeto nuevo ue esta clase, tenuiemos que ponei al menos como paimetio el valoi inicial ue uicha piopieuau. 0tia foima hubieia siuo que uentio ue la implementacion uel constiuctoi, uicha piopieuau hubieia tomauo un valoi fijo, que luego el piogiamauoi hubieia pouiuo cambiai usanuo la funcion settei coiiesponuiente a uicha piopieuau. Paia entiai un poco ms en mateiia vamos a vei la implementacion ue esta clase: AngleObject::AngleObject(qreal angle, QObject *parent) : QObject(parent), m_angle(angle) { }
vemos como en la implementacion uel constiuctoi, se inicializa llamanuo al constiuctoi ue Q0bject, la clase pauie y la vaiible piivaua m_angle con el valoi pasauo como paimetio en la instanciacion. Quizs no ests acostumbiauo a este tipo ue notacion y lo veas mejoi asi: AngleObject::AngleObject(qreal angle, QObject *parent) { QObject(parent); m_angle = angle; } Peio es exactamente lo mismo. La implementacion ue la funcion gettei es tan simple como uevolvei el valoi ue la piopieuau que se almacena en la vaiiable inteina piopia, y la implementacion ue la funcion settei, suele hacei uos cosas, piimeio cambiai el valoi ue la vaiiable inteina asociauo a la piopieuau en cuestion, y luego ponei un couigo que se encaigue ue la notificacion ue uicho cambio, y la toma ue uecisiones al iespecto (lo hemos iepiesentauo touo eso como un meio hazAlgo()). !)
El usai un settei paia cambiai el valoi ue una piopieuau, y no acceuei uiiectamente a la vaiiable piivaua uel mismo, peimite que un couigo pueua evaluai uicho valoi pieviamente antes ue asignailo a uicha vaiiable, y asi contiolai uicho valoi uentio ue un iango aumisible uentio ue la aplicacion, y ue esta maneia hacei honoi a la piopieuau ue encapsulacion C++ como lenguaje oiientauo a objetos. El tipo ue una funcion pouiia sei un enum, algo asi como: public: enum AngleMode {Radianes, Grados};
En ese caso, tenuiemos que notificai pieviamente al moc ue que, uicho tipo es un enum, usanuo la macio Q_EN0N ue la siguiente foima: Q_OBJECT Q_ENUM(AngleMode) Q_PROPERTY(AngleMode angleMode READ angleMode WRITE setAngleMode)
Tambin es posible que ese enum, uefina Flags numiicos que pueuan combinaise entie si con 0R (|). Algo asi como: Q_OBJECT Q_FLAGS(LoadHint LoadHints) Q_PROPERTY(LoadHint hint READ hint WRITE setHint)
&89?54C2 6:N654?B 36B 5C34R8 Aunque C++ y Qt poi tanto aumita libiemente la eleccion ue los nombies ue las clases, sus miembios y la oiganizacion ue las mismas. Es auecuauo paia cieai couigo fcil ue leei, y poi tanto fcil ue mantenei, si se siguen unas ieglas que se han iuo aauienuo al estilo ue piogiamacion ue Qt. Touas las clases ueben ue estai uefiniuas en ficheios apaite con el nombie ue la clase en minsculas, la ueclaiacion ue la clase y sus miembios en un ficheio *.h y la implementacion ue la misma en un ficheio *.cpp . Los nombies ue las clases ueben comenzai en mayscula, y su nombie uebe sei uesciiptivo ue lo que iepiesentan, o uel tiabajo que van a iealizai. Si es un nombie compuesto, es impoitante que caua paite uel mismo se uestaque con una mayscula, poi ejemplo venueuoiesBeRopa. A veces si ueiivamos nuestia clase ue otia pieexistente ue Qt, puesto que estas siempie comienzan poi Q, pueue sei ue ayuua el llamailas ue la misma foima peio sin la Q inicial, claio esta, como: class MainWindow : public QMainWindow
Touas las funciones comienzan en minscula, y si su nombie es compuesto, el iesto ue paites las comenzamos con maysculas. Su nombie uebe uejai claio, cual es su cometiuo uentio ue la clase a la que peitenecen. Poi ejemplo, setWiuth(), isBigit(), uockWiugetAiea(). Touas las vaiiables miembio que estn asociauas a piopieuaues que uefinen el estauo uel objeto, empiezan poi m_. Poi ejemplo m_height (paia sealai la altuia uel objeto). !!
Como ya hemos sealauo anteiioimente, no es obligatoiia este tipo ue notacion uel couigo Qt, peio es muy aconsejable si quieies que touo el munuo entienua tu couigo ue maneia sencilla, incluiuo t mismo unos meses o aos uespus ue habeilo esciito. Bacei anotaciones en el couigo es inteiesante siempie que se expliquen cosas que no salten a la vista en el mismo couigo. Be hecho, comentai en exceso el couigo es la mejoi foima ue peiuei la vision global uel mismo, poi lo que una foima ue evitai tenei que comentai, es que las vaiiables, clases y funciones tengan sigan una notacion claia y tomen un nombie altamente uesciiptivo, aunque no muy laigo. Finalizauos estos iuuimentos, vamos a vei en el pioximo capitulo, la paite ms impoitante ue una buena piogiamacion en C++, y es el manejo ue la memoiia. 0na buena piogiamacion en este sentiuo nos evitai ue muchos ue los pioblemas piopios ue la memoiia, como el tan temiuo "memoiy leak" o "fuga ue memoiia". Es muy impoitante que tomes en consiueiacion, y ueuiques el mximo esfueizo al conteniuo uel pioximo tema.
!"
)%/" L %< /"&%f- '% <" /%/-$0"
El mal manejo ue la memoiia, junto con el mal uso ue punteios, es la fuente ue la mayoiia ue los eiioies y pioblemas ue aquellos que piogiaman en C o en C++. 0n piogiamauoi ue }ava, nos uii que esa es la gian uesventaja ue piogiamai en C, y que ellos con su magnifico iecolectoi ue basuia se evitan esos pioblemas. Sin uuua es una buena solucion paia ellos, peio paia aquel que ama C++, no es iazon suficiente como paia abanuonai el uesaiiollo en este lenguaje tan potente y veistil a la vez. Be hecho touo piogiamauoi ue sistemas que se piecie, siempie antes o tempiano tenui que hacei uso ue C, y la alteinativa que quieio planteaite es usai el estilo Qt junto con su Fiamewoik paia evitai ste y otios pioblemas tipicos.
%B P?26@8 36 B? P6P8A4? 62 (9 Antes ue naua vamos a iecoiuai a unos y a explicai a otios, algo que quizs en su momento no compienuieion. Caua vez que el sistema opeiativo caiga en memoiia un piogiama paia ejecutailo, el sistema ieseiva unas ueteiminauas zonas ue memoiia paia el mismo: - La zona uel couigo o segmento ue couigo.- En ella se caiga el couigo binaiio uel piogiama que se va a ejecutai con touas sus instiucciones mquina tal cual el compilauoi las cieo. - La pila o stack. Esta zona es uonue se van apilanuo vaiiables como en una pila ue platos, usanuo el mtouo LIF0 (last in, fiist out), el ltimo que entia es el piimeio que sale. La pila es usaua caua vez que el couigo llama a una funcion, y entia en ella. En la pila se guaiuan: los paimetios que se pasan a la funcion, las vaiiables locales ueclaiauas uentio uel mbito ue la misma, y el valoi ue ietoino ue la funcion. Touas estas vaiiables son uestiuiuas una vez se vuelve ue la llamaua a la funcion. Lo que es lo mismo, fueia ue las llaves que cieiian el mbito ue la funcion, uichas vaiiables ya no existen, son uestiuiuas inexoiablemente. - El monton o heap. Esta zona se ieseiva con peticiones malloc() en C, y new en C++, y peimanecen touo el tiempo que se quieia. El piogiamauoi tiene la obligacion ue libeiai esos espacios ue memoiia usanuo fiee() en C, o uelete en C++. Si uicho espacio no es libeiauo, entonces el piogiama tiene una fuga ue memoiia (memoiy leak) y le pueue conuucii a un violento ciash. En la memoiia, y piincipalmente en el heap, es uonue va a estai el oiigen ue gian paite ue los uesaguisauos ue nuestia piogiamacion en C++. veamos antes cuales son los pioblemas tipicos en la gestion ue la memoiia: a) Pioblemas en el stack: - Leei o esciibii fueia ue los limites ue una aiiay esttico. Esto se pueue solucionai usanuo los conteneuoies que suministia Qt paia manejai colecciones y usai iteiauoies paia iecoiieilos o bucles contiolauos con foieach, una nueva palabia clave ue Qt. - Coiiupcion ue un punteio a funcion. Esto nos pueue llevai a no pouei alcanzai coiiectamente la funcion. La solucion es no usai punteios a funciones, ue hecho con el mecanismo ue conexiones entie objetos meuiante funciones seal y funciones slots, nos evitamos el uso ue callbacks. b) Pioblemas en el heap: - Intento ue libeiacion ue memoiia ya libeiaua. - Libeiacion ue memoiia no asignaua. - Intento ue esciituia en memoiia ya libeiaua. - Intento ue esciituia en memoiia no asignaua - Eiioi en la asignacion ue memoiia !#
- Lectuia-esciituia ue la memoiia fueia ue los limites ue un aiiay uinmico. Este se pueue iesolvei ue igual maneia al aiiay esttico en el stack. Paia iesolvei los cinco pioblemas sealauos en el heap, apaiece un estilo ue piogiamacion que incoipoiaiemos a Qt, y ese sei el pioposito uel pioximo paigiafo.
,6A6254? 625?362?3? La mejoi foima ue no tenei que ponei couigo paia libeiai memoiia con uelete, es que touos los objetos que componen la aplicacion tengan un pauie que o bien est en el stack, o sean a su vez pauie ue otio objeto. Be esta foima, ningn objeto que est en el heap sei huifano. vamos a ponei un ejemplo con los objetos que componen una ventana ue uilogo. QDialog *parent = new QDialog(); QGroupBox *box = new QGroupBox(parent); QPushButton *button = new QPushButton(parent); QRadioButton *option1 = new QRadioButton(box); QRadioButton *option2 = new QRadioButton(box);
Como se pueue vei, es un ibol jeiiquico uel que penuen box y button ue paient, y ue box penuen option1 y option2. El nico objeto que no tiene pauie, es paient, que seiia la ventana ue uilogo. Luego el tiuco paia que no haya que aauii ningn couigo que libeie su espacio, es colocai su cieacion en el stack. Paia ello vamos a tenei que cieai una clase ueiivaua ue QBialog, a la que llamaiemos Bialog, y vamos a cieai una instancia ue la misma en el stack ue esta maneia: #include <QApplication> #include dialog.h
int main(int argc, char **argv){ QApplication a(argc,argv);
Dialog dialog; dialog.show();
return a.exec(); }
Al ueiivai Bialog ue QBialog, tenemos que ueclaiailo en un ficheio que llamaiemos uialog.h, con el siguiente conteniuo: #ifndef DIALOG_H #define DIALOG_H
#include <QDialog>
class Dialog : public QDialog { public: explicit Dialog(QWidget *parent = 0); };
#endif // DIALOG_H
Es el minimo couigo, ya que no vamos a ieuefinii ningn mtouo, ni a aauii naua. Luego en la implementacion, uebeiemos cieai los objetos que uepenuen uel objeto uialog en su constiuctoi con new, ue esa maneia sein cieauos inmeuiatamente al sei cieauo uialog en el stack, y peimanecein en la memoiia una vez acabauo el mbito uel constiuctoi, hasta que la aplicacion se acabe, y al boiiaise uialog uel stack, poi uepenuencia heieuaua sein libeiauos los espacios ue touos sus hijos. Be esta maneia, hemos evitauo el uso ue couigo libeiauoi, que nos !$
pouiia habei llevauo a pioblemas con un couigo ms gianue y complejo. veamos pues el couigo ue implementacion que ponuiiamos en el ficheio uialog.cpp: #include "dialog.h"
Dialog::Dialog(QWidget *parent) : QDialog(parent) { QGroupBox *box = new QGroupBox(this); QPushButton *button = new QPushButton(this); QRadioButton *option1 = new QRadioButton(box); QRadioButton *option2 = new QRadioButton(box); }
Es impoitante poi lo tanto que te queues con esta filosofia ue piogiamacion, uonue siempie, touo objeto que sea huifano ha ue cieaise en el stack que iequieia ue acueiuo al tiempo que ueba ue vivii (en main, viviiia touo el tiempo ue la aplicacion). Paia ello seiia necesaiio ueiivai uicho objeto ue una clase ueiivaua ue una ue Qt, geneianuo asi uos ficheios paia implementai uicha nueva clase, y en el constiuctoi ue uicha clase, es uonue cieaiemos en el heap los objetos que uepenuan jeiiquicamente ue ste. En una u0I es poi tanto muy habitual el jeiaiquizai confoime al conteniuo. Asi, si un objeto ue una clase est conteniuo gificamente uentio ue los limites ue un objeto ue otia clase, sta sei la clase base ue aqul. Paia ello, las clases ue Qt, implementan vaiios constiuctoies, uonue al menos uno lleva solo el paimetio uel pauie inicializauo a N0LL pointei poi uefecto, ue maneia que touas las veisiones uel constiuctoi tiene como ltimo paimetio el N0LL pointei poi uefecto ue la clase pauie ue la que ueiiva. En el siguiente tema vamos a vei como en Qt se han evitauo el uso ue callbacks paia conectai funciones ue uos o ms objetos. Es otia ue las caiacteiisticas funuamentales ue Q0bject.
!%
!&
)%/" g +%h"<%+ . +<-)+
El mecanismo ue seales y slots ue Qt, ciea una foima uinmica ue comunicai eventos con los cambios ue estauo que estos piovocan y las ieacciones ue los mismos. Lo excepcional ue este mecanismo, es que los objetos que se comunican ue esta foima, no iequieien conoceise mutuamente. Paia ello Q0bject la clase base ue gian paite ue las clases que confoiman Qt, incoipoia un mtouo llamauo +&11"+#, que se encaiga ue establecei esa comunicacion entie los uos objetos. Touo objeto ueiivauo ue Q0bject pueue poseei uos tipos ue funciones piopias especiales: :4R2?B:.- funciones que peimiten emitii una seal cuanuo hay algn cambio ue estauo en el objeto al que peitenecen. :B89:.- funciones que son el final ue la conexion, y que ejecutan una seiie ue acciones una vez ieciben el mensaje ue la seal.
Como se pueue vei en el gifico supeiioi, una seal pueue conectaise a ms ue un slot, paia llevai a cabo uifeientes activiuaues. Tambin vaiios seales uifeientes pueuen conectaise con un mismo slot, y tenuiiamos una activiuau que pueue sei uesataua ue vaiias foimas uifeientes. veamos como es la fiima uel mtouo connect: bool QObject::connect ( const QObject *sender, SIGNAL(*signal), const QObject *receiver, SLOT(*slot) )
0samos las macios SIuNAL y SL0T paia envolvei a las funciones signal y slot con los tipos ue sus paimetios. !'
Pongamos un ejemplo, claio. La clase QApplication, tiene un slot llamauo quit() que simplemente hace que la aplicacion se cieiie y teimine. Poi otio lauo la clase QPushButton, que siive paia implementai botones en el inteifaz gifico, posee una signal llamaua clickeu(), que es emitiua cuanuo el estauo uel boton cambia al sei pulsauo poi el usuaiio. Asi que pouiiamos cieai una conexion entie el boton y la aplicacion que conecten la seal clickeu() uel boton, con el slot quit() ue la aplicacion, y en consecuencia una vez estableciua tal conexion, al pulsai el boton, eso haiia que la aplicacion se ceiiai y teiminai. #include <QApplication> #include <QObject> #include <QPushButton>
int main(int argc, char **argv){ QApplication a(argc,argv);
Bien, las piopieuaues ue una funcion slot son las siguientes: - Es implementaua como una funcion oiuinaiia. - Pueue sei llamaua como una funcion oiuinaiia. - 0n slot pueue sei ueclaiauo en la zona piivate, piotecteu o public ue una clase, peio eso solo le afectai si es llamaua como funcion, no como slot. Como slot siempie poui sei conectaua con objetos ue otia clase inuepenuientemente ue la zona uonue se haya uefiniuo en su clase. Y se ueclaia en la seccion con la palabia slots. - Como funcion pueue uevolvei un valoi ue ietoino, peio nunca en conexiones, solo cuanuo es llamaua como funcion. - Cualquiei nmeio ue seales pueue sei conectauas a un mismo slot.
Las piopieuaues ue una seal son las siguientes: - 0na seal es ueclaiaua en la seccion con la palabia signals. - 0na seal es una funcion que siempie ietoina voiu. - 0na seal nunca pueue sei implementaua, el moc se encaiga ue haceilo automticamente. - 0na seal pueue sei conectaua a cualquiei nmeio ue slots a la vez. - Es como una llamaua uiiecta, y poi tanto es seguia tanto en llamauas entie thieaus (hilos) como entie sockets (ieu). - Los slots son activauos poi las seales en oiuen aibitiaiio. - 0na seal es emitiua uesue cualquiei paite uel couigo ue la clase poi la palabia emit (emit nombie_signal(paiams); ).
Es impoitante tenei en cuenta las fiimas ue las seales y los slots que son conectauos, ya que como iegla Qt no peimite cieai, ni conveitii valoies entie los paimetios, poi lo que no se pueue conectai cualquiei seal con cualquiei slot, si no entie compatibles entie si, confoime a la citaua iegla. Ponuiemos ejemplos ue compatibiliuau: rangeChanged(int, int) ---------------------------> setRange(int, int) rangeChanged(int, int) ---------------------------> setValue(int) rangeChanged(int, int) ---------------------------> updateDialog()
!(
Y ahoia ue incompatibiliuau: clicked()---------------------------> setValue(int) textChanged(QString) --------> setValue(int)
vamos a vei un ejemplo ue implementacion ue una clase con signals y slots: // Fichero angleobject.h class AngleObject : public QObject { Q_OBJECT Q_PROPERTY(real angle READ angle WRITE setAngle NOTIFY angleChanged)
public slots: void setAngle(qreal); // los setters son perfectos slots
signals: void angleChanged(qreal); // declarado en NOTIFY Q_PROPERTY arriba
private: qreal m_angle; }
// Parte del fichero angleobject.cpp void AngleObject::setAngle(qreal angle) { if(m_angle == angle) return; // nunca olvides esta parte
m_angle = angle; emit angleChanged(m_angle); }
Como pueues vei en la implementacion uel settei, tambin slot, es uonue tenemos que, piimeiamente paia evitai que se cieen bucles infinitos al conectai signal y slot, ievisanuo si el valoi que entia ue angle, es nuevo o no, y si no es asi, salii uiiectamente. Si, el valoi es nuevo, entonces piimeiamente actualizaiemos el estauo uel mismo y finalmente emitiiemos la seal ue que ha habiuo un cambio en uicho estauo. Esta es la foima en como se implementan seales y slots en las clases ueiivauas ue Q0bject. Es muy tipico que uos wiugets estn conectauos entie si, ue maneia que la seal ue uno este conectauo con el slot uel otio. vamos a vei un ejemplo completo ue un conveitiuoi ue tempeiatuias ue giauos Celsius a Fahienheit y viceveisa. vamos a apiovechai este uesaiiollo paia usai touo lo apienuiuo hasta el momento, y ue esta maneia ii avanzanuo en el uesaiiollo ue aplicaciones Qt con inteifaz gifico.
782V6A:8A 36 96PN6A?9IA?: vamos a abiii un nuevo pioyecto en el Qt Cieatoi, ue nuevo un Empty Pioject (un pioyecto vacio), y le vamos a llamai "tempconveitei". Con ello ya tenemos la caipeta tempconveitei cieaua, contenienuo el ficheio uel pioyecto que el Cieatoi ha geneiauo l solo. Ahoia vamos a aauii un ficheio fuente main.cpp, hacienuo clic ueiecho sobie la caipeta, eligienuo Auu New. , luego C++ -> C++ Souice File en la ventana emeigente. Ponemos main.cpp en Name. "*
Ahoia cieamos Nuevo, y esta vez elegimos C++ -> C++ Class. Como class name le ponemos "TempConveitei", y como Base class ponemos Q0bject. Le uamos a continue, y uone y se nos han cieauo los ficheios tempconveitei.h y tempconveitei.cpp con paite ue couigo geneiauo automticamente. vamos a vei en piimei lugai el couigo que uesciibe la clase y sus miembios en el ficheio cabeceia coiiesponuiente. #ifndef TEMPCONVERTER_H #define TEMPCONVERTER_H
#include <QObject>
class TempConverter : public QObject { Q_OBJECT public: TempConverter(int tempCelsius, QObject *parent = 0);
// funciones getter int tempCelsius() const; int tempFahrenheit() const;
public slots: // funciones setter y slots void setTempCelsius(int); void setTempFahrenheit(int);
private: int m_tempCelsius; }; #endif // TEMPCONVERTER_H
Es suficiente con usai una sola vaiiable como uesciiptoia uel estauo ue la tempeiatuia, ya que la tempeiatuia es una, se esciiba en un sistema o en otio, solo cambiai el valoi ue nmeio que la iepiesenta. Tomamos poi tanto la escala Celsius como la piincipal. Sin embaigo vamos a usai ue uos funciones settei, paia que sea una ue ellas la que haga el cambio. Poi ejemplo setTempFahienheit, sei la que haga el cambio a Celsius, paia guaiuai. Puesto que ambos uiales estn inteiconectauos entie si, es uecii, si cambia uno, inmeuiatamente uebe cambiai el otio y viceveisa, paia evitai caei en un bucle infinito, tenemos que cuiuai en el settei ponei antes ue naua el couigo que ievise el cambio ue estauo. Como el estauo lo hemos uefiniuo en Celsius, vamos a hacei esto en el slot setTempCelsius. El couigo fuente ue la implementacion ue esta clase queuai ue esta foima. #include "tempconverter.h"
La clase TempConveitei que acabamos ue uefinii va a sei la encaigaua ue conveitii los valoies ue Celsius a Fahienheit y viceveisa. Peio vamos a uefinii ahoia el inteifaz con los wiugets que van a peimitii cambiai la tempeiatuia meuiante unos uiales, y mostiaila meuiante unos LCB numbeis. Como an no hemos estuuiauo las ventanas ue uilogo con wiugets y layouts, vamos simplemente a uefinii el couigo ue las conexiones implicauas, y cuanuo lleguemos al tema 14, entonces apiovechaiemos paia hacei el inteifaz gifico ue este ejemplo. Bien, queiemos que cuanuo giiemos los uiales, automticamente se cambie la tempeiatuia ue ambos LCB caua uno con sus valoies ue acueiuo a su escala ue tempeiatuias, y que ambos uiales giien el uno poi accion uel otio. Bueno pues vamos a vei, cuales son las seales y slots que vamos a usai en caua elemento gifico: El uial Celsius (celsiusBial) => Seal -> valueChangeu(int) ; Slot -> setvalue(int) El uial Fahienheit (fahienheitBial) => Seal -> valueChangeu(int) ; Slot -> setvalue(int) El LCB Celsius (celsiusLcu) => Slot -> uisplay(int) El LCB Fahienheit (fahienheitLcu) => Slot -> uisplay(int) La foima en como se conectaiian estos 4 wiugets gifico con la clase conveisoia TempConveitei, seiia como vemos en el gifico.
"!
La accion comenzaiia al giiai uno ue los uiales, supongamos poi ejemplo, el ue los giauos Celsius. Esto uispaiaiia la seal ue celsiusBial, valueChangeu(int), que iiia a 2 sitios. Al celsiusLCB uiiectamente meuiante su slot uisplay(int), y a TempConveitei, a su slot setTempCelsius(int). Como pouemos vei en el couigo, ste ultimo slot emite las 2 seales tempCelsiusChangeu(int) y tempFahienheitChangeu(int), caua una conectaua con los slots coiiesponuientes ue celsiusBial y fahienheitBial, setvalue(int) en ambos casos. Be esa maneia, tenemos touo peifectamente inteiconectauo. vamos poi tanto a vei el couigo que implementaiia esas conexiones. connect(celsiusDial,SIGNAL(valueChanged(int)),tempConverter,SLOT(setTempCelsius(int)); connect(celsiusDial, SIGNAL(valueChanged(int)), celsiusLcd, SLOT(display(int)); connect(tempConverter,SIGNAL(tempCelsiusChanged(int)),celsiusDial,SLOT(setValue(int));
0na vez hemos visto como funciona el sistema ue conexiones entie objetos en Qt meuiante seales y slots, vamos ahoia a planteainos un pioblema ms complejo ue afiontai meuiante este esquema ue tiabajo. Es muy noimal, que en algunos casos, nos lleguemos a planteai el enviai un valoi junto con la seal, sin embaigo esto no es posible. Poi ejemplo, supongamos que tenemos un conjunto ue teclas iepiesentanuo los nmeios uel u al 9, como un maicauoi telefonico, o los numeiales ue una calculauoia. Nos gustaiia sin uuua el pouei enviai junto con la seal uel clickeu() el valoi ue la tecla pulsaua. Claio una foima ue implementai este caso, seiia cieai 1u slots paia caua tecla, peio eso supone iepetii casi el mismo couigo uiez veces, y si alguna vez nos planteamos hacei algn cambio, tenuiemos que estai atentos en haceilo en 1u sitios uifeientes. Bien, paia estos casos existe una clase muy til llamaua QSignalNappei. Si buscas infoimacion ue la misma en el asistente, veis que es bastante sencilla en cuanto a miembios, slots y signals, sin embaigo, como inteimeuiaiia ue un sistema ue tiansmision ue seales uonue necesitamos enviai ue alguna maneia tambin un valoi junto con la seal, es muy inteiesante. QSignalMapper *m = QSignalMapper(this); QPushButton *b;
b=new QPushButton("1"); connect(b, SIGNAL(clicked()), m, SLOT(map()); m->setMapping(b,1);
b=new QPushButton("2"); connect(b, SIGNAL(clicked()), m, SLOT(map()); m->setMapping(b,2); ................
vamos conectanuo caua boton meuiante la seal clickeu() al slot map() uel QSignalNappei. Neuiante el mtouo setNapping lo que hacemos es vinculai al objeto uel que iecibe la seal el QSignalNappei, y que una vez, ieciba la seal en el slot map(), ste geneiai una seal mappeu(int) que lleva el valoi enteio asignauo con setNapping a uicho objeto. Como vemos en el ltimo connect, conectamos uicha seal mappeu(int) con el slot keyPiesseu(int) que pouemos ya ieuefiniilo paia llevai a cabo las acciones que queiamos, ue acueiuo al boton pulsauo. El gifico infeiioi, iepiesentaiia las ielaciones implicauas en este mtouo ue conectai elementos.
"#
"$
)%/" i /"&%f- '% 7"'%&"+ %& (9
Antes ue seguii con la piogiamacion gifica (u0I), veo muy impoitante el conocei toua una seiie ue elementos funuamentales que usaiemos en los piogiamas con entoino gifico, y que nos peimitiin hacei aplicaciones tiles. Nuchos libios ue Qt, enfocan siempie solo el aspecto gifico, e incoipoian estos elementos junto con aquellos, ue maneia que a veces pueuen agobiai al que empieza, con multituu ue conceptos, poi ello aqui he piefeiiuo sepaiai ambos aspectos completamente, y poi tanto incluso los ejemplos que vamos a usai, van a ii uespiovistos ue u0I, y su saliua sei en la consola. Ya hemos visto en el tema 4, el ejemplo ue Bola Nunuo con saliua a consola, poi lo que usaiemos qBebug(), paia nuestios ejemplos. Qt es un Fiamewoik, cuya piincipal motivacion es la ue que usanuo el mismo couigo, pouamos compilailo en uifeientes platafoimas sin tenei que hacei cambios. Poi ello, ha teniuo que abstiaei muchos ue los tipos que ya existian en C++STL paia haceilo completamente multiplatafoima. Asi ocuiie con el tiatamiento ue cauenas, en el que stu::stiing ha siuo mejoiauo, aauinuole capaciuau ue iepiesentai caiacteies unicote (chino, hebieo, iabe, etc), y ue esta maneia inteinacionalizai el mbito aplicable uel tiatamiento ue cauenas. Esto se ha hecho, cieanuo una clase llamaua (+9A42R. Si la buscas en el Qt Assistant pouis vei touas las posibiliuaues que esta clase nos biinua paia el manejo ue cauenas que en C, siempie fue complicauo, fiente a otios lenguajes ue piogiamacion. Asi, QStiing sopoita las conveisiones a otios sistemas (QStiing::toAscii, QStiing::toLatin1 . ), peimite la iepiesentacion en unicoue ue picticamente la totaliuau ue sistemas ue esciituia actuales y tambin peimite mtouos ue inspeccion y manipulacion ue cauenas ue texto.
782:9AI554C2 36 5?362?: Bay ties mtouos paia constiuii cauenas poi concatenacion: 1.- Neuiante el opeiauoi + QString res = "Hola " + "amigos ";
El mtouo 1, es mejoi que el 2 si se va a componei la cauena en muchas veces, con muchas asignaciones. El mtouo S peimite foimateai la cauena, y uejai los huecos que luego sein iellenauos poi oiuen, poi el mtouo aig que peimite intiouucii tanto cauenas como nmeios.
"%
+IH5?362?: vamos a vei una seiie ue mtouos paia tiatai subcauenas uentio ue cauenas ms gianues. Funciones left, iight, miu, ieplace: QString str = "Hola mundo"; str.left(4); // "Hola" str.right(5); // "mundo" str.mid(3,5); // "a mun" str.replace("mundo","tronco"); // Hola tronco
S'6HIRWX K (+9A42R W:?B43?: N8A 582:8B?X qBebug se usa paia sacai mensajes poi consola. Incluiuo en la clase QBebug, tiene uifeientes foimas ue tiabajai. Como piintf() en C peio aauienuo un ietoino ue caiio "n". Paia impiimii un QStiing antes uebe sei pasauo poi la funcion qPiintable incluiua en Qtulobal (no iequieie poi tanto incluii ninguna cabeceia paia su uso): QString str = "Antonio"; qDebug("Hola me llamo %s, y tengo %d aos",qPrintable(str),42);
Tambin pouemos usailo como un stieam, como stu::cout ue C++STL: qDebug() << "Hola me llamo " << str << ", y tengo " << 42 << " aos";
&jP6A8: K 5?362?: Conveitii un nmeio en una cauena: QString years = QString::number(42); // "42"
Conveitii ue cauena a nmeio: bool ok; years.toInt(&ok); // ok = true si lo convirti bien
Tambin existe toBouble(), toFloat(), etc.
+)< K (+9A42R
Si usamos una libieiia cieaua con las STL, y queiemos hacei un inteifaz con ella, paia iecibii cauenas ue ella, o enviaile cauenas hacia ella, entonces tenuiemos que auaptai la cauena paia que touo funcione bien. Paia ello existen unas funciones que vamos a vei. std::string str = "Hola mundo"; QString qstr = QString::fromStdString(str);
7?362?: V?5k?: K 5?362?: 2IB?: Becimos que una cauena es nula, si no est apuntanuo a ninguna cauena, y uecimos que est vacia si no contiene ningn caictei. Queuai aclaiauo con este ejemplo: QString str = QString; // str no esta apuntando a nada str.isNull(); // true str.isEmpty(); // true
QString str = ""; // str esta apuntando a un espacio vaco str.isNull(); // false str.isEmpty(); // true
QStiingList es un conteneuoi, similai a una aiiay ue cauenas, que vamos a vei ahoia.
(+9A42R<4:9 Es una clase especializaua en contenei QStiings en un contenei tipo lista (QList). En iealiuau es una QList<QStiing>. Esta lista pueue sei iellenaua usanuo el opeiauoi << como en un stieam. QStringList verbos; verbos = "correr" << "comer" << "coser"; // {correr, comer, coser}
QStiingList posee mtouos paia tiatai, touas las cauenas que lleva consigo, que son muy inteiesantes: verbos.replaceInStrings("er","iendo"); // {corriendo, comiendo, cosiendo} verbos.sort(); // {comer, correr, coser} verbos.filter("m"); // {comer} verbos << "comer"; // {comer, comer} verbos.removeDuplicates(); // {comer}
096A?238 :8HA6 (+9A42R<4:9 Pouemos moveinos poi una QStiingList usanuo el opeiauoi |j con ayuua ue lenght() paia no sobiepasai sus uimensiones, o con la piopieuau ue solo lectuia at(). QStringList verbos; verbos = "correr" << "comer" << "coser"; // {correr, comer, coser} for(int i; i < verbos.length(); i++){ qDebug() << verbos[i]; // verbos.at(i); }
"'
Peio la foima ms comoua y seguia ue iecoiiei una QStiingList es con foieach, incluiuo en Qtulobal poi uefecto. foreach(const QString &verbo, verbos){ qDebug() << verbo; }
0samos una iefeiencia const paia optimizai el ienuimiento uel bucle, pasanuo solo una iefeiencia. Foieach siempie tiene la misma foima, a la ueiecha como segunuo paimetio esta una coleccion ue elementos ue un ueteiminauo tipo, y a la izquieiua como piimei paimetio, ponemos una vaiiable uel tipo ue los elementos, que es la vaiiable que va a ii iecogienuo los valoies iecoiiiuos ue la coleccion, uesue el piimeio hasta el ltimo. Bien, en el pioximo tema vamos a vei las colecciones en Qt. Es conveniente que piuebes el couigo que hemos iuo vienuo en este tema, incluynuolo en el esqueleto ue una aplicacion ue consola usanuo qBebug().
"(
)%/" ;l 7-<%770-&%+ %& (9
Las colecciones en Qt estn funuamentauas sobie las mismas ue STL, peio llevauas a una implementacion multiplatafoima. vamos a ii vinuolas una a una.
(<4:9`)a Es una lista, como las ue STL, y la foima ue iellenaila es igual. vamos a vei unos ejemplos sencillos. QList<int> pares; pares << 2 << 4 << 6; pares.prepend(0); // 0,2,4,6 pares.append(10); // 0,2,4,6,10 pares.insert(4,8); // 0,2,4,6,8,10 pares.removeFirst(); // 2,4,6,8,10 pares.removeLast(); // 2,4,6,8 pares.removeAt(2); // 2,4,8 pares.removeAll(); // nada
Con takeAt(), takeFiist(), takeLast(), nos uevuelve el elemento en si y auems lo boiia ue la lista, ue maneia que si tenemos una lista ue objetos, pues nos uevolveiia la iefeiencia a uicho objeto. Pouemos acceuei a sus elementos meuiante el opeiauoi |j, y la funcion value(). Paia iteiai una lista usamos (<4:9096A?98A`)a. Que tiene funciones como hasNext() paia aseguiaise que no hemos llegauo al final.
QListIterator<int> i(pares); while (i.hasNext()){ qDebug("Numero par: %d",i.next()); }
Tambin pouemos usai /&4"$+2 paia iteiai toua la lista completa: foreach(const int &valor, pares){ qDebug("Numero par: %d",valor); }
0tias alteinativas similaies a QList, son QLinkeuList que implementa una lista vinculaua, y Qvectoi que es una coleccion vectoi como las ue STL. Los mtouos usauos son los mismos que QList. Bepenuienuo uel uso que les vayamos a hacei, usaiemos una lista, una lista vinculaua o un vectoi.
782@I298: 582 (+69 Los conjuntos o sets, tambin pouemos asimilailos a los Set ue STL. vamos a vei un poco ue couigo paia asimilailos. QSet<int> conjunto; conjunto << 1 << 3 << 7 << 9; conjunto.contains(8); // false conjunto.contains(3); // true conjunto.remove(8); // false y no borra nada conjunto.remove(3); // true y borra el 3
Pouemos tambin conveitii una lista en un conjunto y viceveisa: QList<int> pares; pares << 2 << 2 << 4 << 4 << 8; // 2,2,4,4,8 QSet<int> conjunto = pares.toSet(); // 2,4,8 QList<int> pares_no_repes = conjunto.toList();
Si hubiiamos queiiuo conseivai los elementos iepetiuos en el conjunto, hubiiamos teniuo que usai un QNultiSet.
(/?N`m6K)U)a K (,?:T`m6K)U)a Se tiata ue paies key => value, como en las STL (o las matiices ue PBP), uonue una key se coiiesponue con un nico value. Paia intiouucii elementos se hace ue la siguiente maneia: QMap<QString,int> edades; edades["Antonio"] = 42; edades["Maria"] = 42; edades["Pablo"] = 8;
La funcion key() iecoge el valoi uel piimei elemento, keys() uevuelve una QList<keyT> con touas las keys, y value(key) uevuelve el valoi asociauo con un key en paiticulai. veamos ejemplos: foreach(const QString &key, edades.keys()){ qDebug("Nombre: %s",qPrintable(key)); }
#)
Con la funcion contains(key), pouemos vei si una ueteiminaua key esta en la coleccion. if(edades.contains("Pablo")){ qDebug("Pablo tiene %d", edades.value("Pablo")); }
QBash es lo mismo que QNap, solo que la key se pasa poi una funcion hash, paia conveitiila en un valoi uint (unsigneu int), la cual peimite mayoi ienuimiento a la coleccion. Bicha funcion hash, ha ue escogeise ue maneia que no se iepita ningn valoi uint que uificulte su ienuimiento. Paia ello el tipo ue key, uebe ue pioveei ue 2 mtouos: uint qBash (tipoKey), y bool opeiatoi== (key1, key2). Si asi se hace ue maneia optima, QBash<keyT,T> uai mejoi ienuimiento en touas las opeiaciones que QNap<keyT,T>. veamos un ejemplo ue implementacion ue estas funciones, como miembios ue una clase hipottica Peisona, que tiene uos miembios bsicos llamauos euau() y nombie(). uint Persona::qHash (const Persona &p) { return p.edad() + qHash(p.nombre()); } bool Persona::operator== (const Persona &p1, const Persona &p2) { return (p1.edad() == p2.nombre()) && (p1.nombre() == p2.nombre()); }
Con esto ya pouiiamos cieai un QBash<Peison,int>, que tiabaje ue foima optima. Paia finalizai, existen las veisiones 6783#07$5 y 6783#09$'2, paia cuanuo una misma key, pueue tenei asociauos vaiios valoies a la vez. En estos casos, no se pueue usai el opeiauoi |j paia intiouucii nuevos uatos, y se utiliza inseit(). Si se quieie iecogei el valoi key una sola vez, se usa la funcion uniqueKeys(). veamos un ejemplo paia ilustiailo. QMultiMap<QString,QString> lang; lang.insert("Antonio", "C/C++"); lang.insert("Antonio", "Java"); lang.insert("Antonio", "PHP"); lang.insert("Antonio", "Erlang");
foreach(const QString &nombre, lang.uniqueKeys()){ QStringList program_lang = lang.values(nombre); // {C/C++, Java, PHP, Erlang} solo pasa una vez el bucle }
#!
#"
)%/" ;; )0#-+ (9
Como en el tema anteiioi hemos visto, uebiuo a que el pioposito ue Qt es pouei sei multiplatafoima sin tenei que mouificai el couigo, otia cosa que hubo que mouificai son los tipos como los enteios, que uepenuen uel sistema opeiativo, y ue la CP0. Asi los tipos queuan fijauos ue esta maneia en Qtulobal: qint8 ------> 8 bits enteio qint16 ------> 16 bits enteio qintS2 ------> S2 bits enteio qint64 ------> 64 bits enteio quint8 ------> 8 bits enteio sin signo quint16 ------> 16 bits enteio sin signo quintS2 ------> S2 bits enteio sin signo quint64 ------> 64 bits enteio sin signo qieal ------> uouble
(n?A4?29 Es un tipo que pueue guaiuai un tipo cualquieia. Si necesitamos sei capaces ue uevolvei cualquiei tipo, a tiavs ue un inteiface Qvaiiant nos pueue ayuuai, y finamente pouemos conveitiilo a su tipo final meuiante las funciones uel tipo toTipo() (ej. toInt(), toFloat()). veamos un ejemplo. QVariant var(5); int i; i=var.toInt(); // 5
7?:942R 342YP458 Paia hacei casting uinmico entie clases, peio sin iequeiii el uso uel RTTI uel compilauoi, en Qt existe el opeiauoi en Qtulobal llamauo :&)*"+#;+$'#01<. Si no tenemos claio, si el casting se va a iesolvei bien, entonces usaiemos este tipo ue casting, ya que ue no iesolveise bien, uevolvei un punteio nulo. QObject *obj = new QTimer; // QTimer hereda de QObject
0tio ue los sitios uonue est muy justificauo el uso ue un sistema inuepenuiente ue la platafoima es en los accesos a sistemas ue ficheios, ya que en caua opeiativo, esto es uifeiente. Be esta maneia suige una seiie ue clases en Qt que nos ayuuan a abstiaeinos ue uichas paiticulaiiuaues.
('4A Esta clase nos piovee uel manejo uel sistema ue ficheios ue maneia tianspaiente. Los uiiectoiios ms tipicos estn uefiniuos como mtouos estticos. QDir dir = QDir::current(); // directorio actual QDir dir = QDir::home(); // /home QDir dir = QDir::temp(); // directorio temporal QDir dir = QDir::root(); // directorio raiz QDir dir = QDir(QApplication::applicationDirPath()); // directorio de la aplicacion
QFileInfo es una clase que pueue contenei toua la infoimacion iefeiente a un ficheio (nombie, path, peimisos, etc). QFileInfoList es una QList<QFileInfo>. 0na funcion muy impoiante ue QBii es entiyInfoList() que uevuelve toua lista ue un uiiectoiio (es como un uii o un ls). veamos un ejemplo ue como listai un uiiectoiio. QFileInfoList infos = QDir::root().entryInfoList(); foreach(const QFileInfo &info, infos){ qDebug("%s",qPrintable(info.fileName())); }
Se pouiia hacei un filtiauo ue uicho listauo usanuo los siguientes filtios, puestos y combinauos con 0R (|) como piimei paimetio ue entiyInfoList(filtei,soit): QBii::Biis uiiectoiios QBii:: Files ficheios QBii::NoSymLinks no vinculos QBii::Reauable con piemiso ue lectuia QBii::Wiiteable con peimiso ue esciituia QBii::Executable con peimiso ue ejecucion QBii::Biuuen ficheios ocultos QBii::System ficheios ue sistema El oiuen ue listauo se pueue enviai como segunuo paimetio y estos son los filtios ue oiuenacion: QBii::Name poi nombie QBii::Type poi tipo (extension) QBii::Size poi tamao #%
QBii::Time poi fecha ue cieacion QBii::BiisFiist uiiectoiios piimeio QBii::BiisLast uiiectoiios lo ltimo QBii::Reveiseu en oiuen inveiso EntiyInfoList tambin tiene un constiuctoi uonue uelante ue estos paimetios vistos antes, se le pueue aauii un paimetio que iiia antes ue que estos con una QStiingList con filtios wilucaiu (uel tipo *.h, *.cpp, etc). veamos un ejemplo: QFileInfoList infos = QDir::root().entryInfoList(QStringList << "*.h" << "*.cpp",QDir::Files,QDir::Name); foreach(const QFileInfo &info, infos){ qDebug("%s",qPrintable(info.fileName())); }
Las uistintas paites uel path ue un ficheio estn gificamente ielatauas en el siguiente gifico.
#&
)%/" ;F %+7$0)\$" . <%7)\$" '% ]07,%$-+
Paia la lectuia y esciituia en ficheios, tenemos que al menos implicai S clases uifeientes, tanto en el caso ue que sea un ficheio binaiio, como si es ue texto. Bien vamos a vei caua una ue esas clases, y la maneia en que se ielacionan en el pioceso ue lectuia y esciituia. La clase 6=03" que ueiiva ue 6>(?"@0+", es la que se usa paia la opeiacion ue apeituia, esciituia, lectuia y cieiie uel aichivo. Los flags que iepiesentan los uifeientes mouos ue acceso al ficheio estn uefiniuos como un enum en QI0Bevice, y son los siguientes: QIODevice::ReadOnly abierto para lectura QIODevice::WriteOnly abierto para escritura QIODevice::ReadWrite abierto para lectura y escritura QIODevice::Append abierto para aadir al final del fichero QIODevice::Text cuando lee los enter los pasa a \n y cuando escribe, los enter los pasa al sistema local
Be la clase QI0Bevice vamos a usai meiamente los mouos ue acceso a los ficheios, y ue la clase QFile, vamos a usai los mtouos open() paia la apeituia uel ficheio, close() paia el cieiie, wiite() paia la esciituia en el mismo, y ieau() y similaies paia la lectuia. Tambin vamos a usai mtouos como atEnu() paia ieconocei el E0F (final uel ficheio), o seek() paia situainos en una posicion concieta uel ficheio. veamos un ejemplo ue lectuia:
QFile f("fichero.txt");
if(!f.open(QIODevice::ReadOnly)) qFatal("No puedo abrir el fichero para lectura.");
while(!f.atEnd()){ QByteArray data = f.read(1024); // Aqui puedes usar los datos leidos }
f.close();
Esto mismo pueue sei hecho ue una maneia ms intuitiva usanuo stieams. Las clases inteiface, que se encaigan ue cieai un stieam con los uatos que pioceuen o van al ficheio en nuestio caso, aunque tambin se pueue usai con cualquiei otio uispositivo. Estas clases son 6A"B#C#4"$! paia flujos ue texto, y 6?$#$C#4"$! paia flujos ue uatos binaiios. Be estas clases vamos a usai solamente el constiuctoi, inuicanuo como paimetio el uispositivo ue entiauasaliua. veamos un ejemplo ue lectuia ue ficheio ue texto usanuo un stieam: QFile f("fichero.txt"); QTextStream in(&f);
if(!f.open(QIODevice::ReadOnly) qFatal("No puedo abrir el fichero para lectura."); while(!in.atEnd()){ qDebug("%s",qPrintable(in.readLine())); } f.close();
if(!f.open(QIODevice::WriteOnly | QIODevice::Append) qFatal("No puedo abrir el fichero para escritura."); out << "Esto es un fichero de texto" << str << endl; f.close();
En el caso ue leei o esciibii uatos, uebemos uecii al compilauoi ue Qt la veision que estamos usanuo uel mismo, ya que es posible que en uifeientes veisiones, la implementacion uel uatastieam sea uifeiente. veamos un ejemplo ue esciituia. QFile f("fichero.bin"); QDataStream out(&f);
out.setVersion(QDataStream::Qt_4_6); if(!f.open(QIODevice::WriteOnly) qFatal("No puedo abrir el fichero para escritura"); out << 0xFFFC; f.close();
+9A6?P: K )4N8: Se pueue seiializai a un ficheio una clase cualquiei cieaua poi nosotios, simplemente si en la misma implementamos los opeiauoies << y >>. vamos a vei un ejemplo ue nuevo con la clase Peisona y sus miembios euau() y nombie(). QDataStream Persona::&operator<< (QDataStream &out, const Persona &p) { out << p.nombre(); out << p.edad(); return out; }
QDataStream Persona::&operator>> (QDataStream &in, const Persona &p) { QString nombre; int edad; in >> nombre; in >> edad; p = Persona(nombre, edad); return in; }
#(
)%/" ;* D0'^%)+ . <".-\)+
Los piimeios temas, uel 1 al 1S, contenian los piincipios bsicos que uifeiencian a la piogiamacion C++STL ue la piogiamacion C++Qt. Es funuamental que tenga touos esos conceptos claios, y que haya hecho touos los ejemplos, y ejeicicios posibles paia afianzailos bien. Si esto no es asi, es el momento ue que se paie, y vuelva sobie los 1S temas que acabamos ue pasai. Besue el tema actual, hasta el tema 2u incluiuo, vamos a vei los conceptos bsicos y touas las heiiamientas necesaiias paia uesaiiollai un inteifaz gifico completo. Es funuamental poi tanto que tiate este bloque ue temas como un touo, y que se ejeicite en ellos antes ue seguii auelante. Besue el tema 21 en auelante, ya se tiatan paiticulaiiuaues y ampliaciones, que con una base soliua en los 2 bloques anteiioies (1 al 1S y 14 al 2u), poui avanzai poi ellos ue maneia seguia y fiable. 0n inteifaz gifico muestia al usuaiio ventanas con elementos gificos con los que pueue inteiactuai, seleccionanuo opciones, intiouucienuo texto, pulsanuo en botones, etc. Toua aplicacion tiene una ventana piincipal, que es la que se abie al piincipio y se mantiene hasta el final, cuanuo el usuaiio ueciue ceiiai la aplicacion. A paite, pueuen habei ventanas ue Bilogo, que se supeipongan a la piincipal en el momento en que piuen alguna accion poi paite uel usuaiio. Cualquieia ue estas ventanas, esta compuesta a su vez poi unos elementos gificos bsicos que uiviuiiemos en 2 tipos: los wiugets y los layouts. Los wiugets son elementos gificos inteiactivos o no, que se uibujan uentio ue una ventana ocupanuo un iea iectangulai, como un boton, una etiqueta, un cuauio ue seleccion, etc. 0n Layout es un componente que se usa paia uisponei espacialmente los wiugets uentio ue la ventana, es uecii, paia oiganizai su posicion en ella. Layouts y wiugets negocian el espacio a ocupai. En Qt se usan unos wiugets llamauos spaceis (veitical y hoiizontal) que actan como muelles, empujanuo los wiugets hacia una zona ue la ventana, con touo esto se consigue un inteifaz elstico, que se auapta a las uimensiones que se quieia uai a la ventana que los contiene, y es muy eficaz en el caso ue queiei inteinacionalizai un inteifaz, tiauucinuolo a uifeientes iuiomas, uonue los textos, miuen uifeiente en caua iuioma, y uonue no queiemos que se tiunquen ni textos, ni gificos.
<8: E43R69: En el Qt Besignei nos pouemos encontiai ms ue 4S wiugets paia usai, y ceica ue 6u son ueiivauos ue la clase piincipal 6D0%<"#. Los wiugets estn oiganizauos en categoiias, y una categoiia impoitante son los wiugets conteneuoies, que pueuen contenei en su inteiioi otios wiugets, ue maneia que siiven paia oiganizailos, y auems pueuen actuai en su inteiactiviuau, como poi ejemplo, cuanuo metemos vaiios iauio-buttons (QRauioButton) uentio ue gioup-box (QuioupBox), conseguimos que al seleccionai uno ue ellos, los uems se ueseleccionen automticamente, poi lo que se pueue uecii que los wiugets conteneuoies pueuen afectai y mouificai la inteiactiviuau ue un wiuget conteniuo en l. 0tia piopieuau impoitante ue los wiugets, es que son capaces ue iecibii eventos uesue los uispositivos ue entiaua (poi ejemplo el iaton). Cuanuo poi causa ue un evento, o poi otia causa, el estauo uel wiuget es cambiauo, emite una seal notificanuo tal cambio. Los wiugets poi tanto pueuen conectaise con otios wiugets y objetos, meuiante el mecanismo ue signal-slot que vimos en los Q0bjects, ya que QWiuget ueiiva ue aqul.
$*
<8: <?K8I9: Los objetos layout ueiivan ue la clase QLayout. Bay S tipos uifeientes ue layouts: QBBoxLayout (que oiganiza el espacio que ocupan los wiugets hoiizontalmente), QvBoxLayout ( que oiganiza el espacio que ocupan los wiugets veiticamente) y QuiiuLayout (que oiganiza el espacio que ocupan los wiugets, sobie un giiu, uiviuienuo el espacio en filas y columnas, y situanuo a caua wiuget en la celua que le coiiesponua). Los spaceis, iellenan los espacios vacios, y ue esta maneia, layouts y wiugets, negocian su tamao y el espacio paia cieai un inteifaz elstico auaptable a touas las situaciones. 0n Layout, pueue contenei en su inteiioi otios Layouts y otios Wiugets. Asi QLayout posee unas funciones miembio especiales paia aauii estos conteniuos a su inteiioi, y cuanuo estas funciones son usauas, inmeuiatamente uicho conteniuo pasa a sei hijo ue la clase conteneuoia. Este mecanismo facilita entonces la tiansmision ue eventos y piopieuaues a lo laigo ue la jeiaiquia familiai, unuole ms consistencia al inteifaz gifico cieauo poi objetos continentes y objetos conteniuos. Tambin facilita el mecanismo ue libeiacion ue memoiia que vimos en el tema 6, evitanuo fugas ue memoiia. veamos las S funciones bsicas paia aauii elementos a un Layout: void QBoxLayout::addStretch ( int stretch= 0 ) Aaue un spacei que ocupai poi uefecto como minimo u pixeles, hasta el limite ue su conteneuoi, empujanuo al wiuget en esa uiieccion (la uel conteneuoi). Solo BoxLayouts veiticales y hoiizontales (no vale paia uiiuLayouts). void QLayout::addWidget (QWidget *w) Aaue un wiuget uentio uel Layout uel tipo que sea ste. Besue ese momento uicho wiuget pasa a sei hijo uel Layout que lo contiene. void QLayout::addLayout (QLayout *layout, int stretch = 0 ) Aaue un Layout uentio ue otio (cajas pequeas uentio ue cajas ms gianues). Besue ese momento uicho layout pasai a sei hijo ue su conteneuoi, y poi heiencia a su vez ue las cosas que aqul contenga. Be hecho, en toua ventana gifica, se pueue uibujai un ibol jeiiquico que ieciee las ielaciones paientales ue touos sus objetos. Poi lo tanto, touo el conteniuo ue una ventana uebe estai sometiuo jeiiquicamente al objeto que iepiesenta la ventana completa. Asi cuanuo uicha ventana sea boiiaua ue la memoiia, con ella se boiiain touos sus elementos, evitanuo asi pioblemas ue memoiy leaks. Es muy habitual poi tanto que los elementos gificos ue una ventana sean cieauos meuiante new uentio uel constiuctoi uel objeto que hai ue ventana. Puesto que hay muchos wiugets, y sus piopieuaues son muchas, y sus mtouos son muchos, no es pioposito ue este libio el veilos touos. Poi tanto, es conveniente que confoime los vayas necesitanuo, los vayas ievisanuo en el Qt Assistant, y apienuienuo a usai esta uocumentacion como guia a la piogiamacion. El autoiiellenauo uel Qt Cieatoi, facilita tambin la laboi ue encontiai fcilmente los elementos ue la piogiamacion que iequeiimos. vamos poi tanto a continuacion a planteainos la constiuccion ue un cuauio ue uilogo, piimeio en couigo puio, y luego en el Qt Besignei. Be esta maneia uejaiemos concietaua la enseanza que pietenuiamos paia este tema, que es el uiseo ue ventanas usanuo Layouts y Wiugets.
$)
782:9AI554C2 36 I2? V629?2? 36 '4YB8R8 582 5C34R8 vamos a constiuii una ventana ue uilogo que tenga el aspecto ue la foto que mostiamos a continuacion.
Pouemos obseivai que piimeiamente hay S cajas hoiizontales (iectngulos iojos), que son conteneuoies Layout que en su inteiioi tienen wiugets o spaceis (stietch). vamos a suponei que la constiuccion ue touo ello es hecho en el constiuctoi ue la ventana ue uilogo, poi lo que los contenuoies supeiioies, que son S, tomain como pauie a la ventana y poi tanto usaiemos el punteio this como aigumento ue los constiuctoies ue los mismos. QHBoxLayout *topLayout = new QHBoxLayout(this); QHBoxLayout *groupLayout = new QHBoxLayout(this); QHBoxLayout *buttonsLayout = new QHBoxLayout(this);
Empecemos poi el topLayout uonue hay un QLabel con el texto Piintei y un QComboBox, al que luego queiemos aauiile items ue uonue seleccionai opciones. Poi lo que aauimos uebajo ue la piimeia linea uel couigo ue antes: QComboBox *c; QHBoxLayout *topLayout = new QHBoxLayout(this); topLayout->addWidget(new QLabel("Printer:")); topLayout->addWidget(c=new QComboBox());
Bate cuenta ue que la Label solo la hemos instanciauo, peio no la hemos asignauo a ninguna vaiiable, ya que no iequeiimos haceile naua en el couigo ms auelante, no iequeiimos acceuei a ninguna vaiiable que la maneje, mientias que la ComboBox si la hemos asignauo a la vaiiable c, paia ms auelante pouei aauiile items ue seleccion meuiante uicha vaiiable. Ahoia vamos a poi el buttonsLayout, uonue tenemos que colocai un spacei piimeio, y luego los 2 botones. QHBoxLayout *buttonsLayout = new QHBoxLayout(this); buttonsLayout->addStretch(); buttonsLayout->addWidget(new QPushButton("Print")); buttonsLayout->addWidget(new QPushButton("Cancel"));
vamos ahoia a poi la caja cential que es la ms compleja ue este ejemplo. Piimeiamente vamos a aauiile a gioupLayout los 2 uioupBoxes. QHBoxLayout *groupLayout = new QHBoxLayout(this); QGroupBox *orientationGroup = new QGroupBox(); groupLayout->addWidget(orientationGroup); QGroupBox *colorGroup = new QGroupBox(); groupLayout->addWidget(colorGroup);
$!
Fijate que aqui hemos instanciauo piimeio los uioupBoxes y luego los hemos aauiuo al Layout. Bien, ahoia vamos a usai un Layout veitical uentio ue caua uiupoBox paia oiganizai el espacio ue los wiugets que van a ii uentio. QGroupBox *orientationGroup = new QGroupBox(); QVBoxLayout *orientationLayout = new QVBoxLayout(orientationGroup); // nueva groupLayout->addWidget(orientationGroup); QGroupBox *colorGroup = new QGroupBox(); QVBoxLayout *colorLayout = new QVBoxLayout(colorGroup); // nueva groupLayout->addWidget(colorGroup);
Ahoia vamos a aauiile a caua veitialLayout los wiugets que le coiiesponuen. Poi lo que el couigo completo iefeiente al Layout uel meuio se queua asi. QHBoxLayout *groupLayout = new QHBoxLayout(this); QGroupBox *orientationGroup = new QGroupBox(); QVBoxLayout *orientationLayout = new QVBoxLayout(orientationGroup); orientationLayout->addWidget(new QRadioButton("Landscape")); orientationLayout->addWidget(new QRadioButton("Portrait")); groupLayout->addWidget(orientationGroup); QGroupBox *colorGroup = new QGroupBox(); QVBoxLayout *colorLayout = new QVBoxLayout(colorGroup); colorLayout->addWidget(new QRadioButton("Black and White")); colorLayout->addWidget(new QRadioButton("Color")); groupLayout->addWidget(colorGroup);
Si te has uauo cuenta, no hemos puesto an el spacei veitical que hay entie el Layout cential y el infeiioi (el ue los botones). Paia hacei eso usanuo la funcion auuStietch, tenemos que iefeiiinos a una veiticalLayout, poi lo que vamos a tenei que conteneilo touo uentio ue un Layout ms gianue. Como este QvBoxLayout, conteneuoi ue touo, seiia el pauie ue touo, entonces tenuiiamos que iefeiii los S Layouts iniciales a ste, y ste pasaiia a sei el ms ceicano en jeiaiquia a la ventana ue Bilogo. Y asi queuaiia touo: QStringList options; options << "Office Printer" << "HP LaserJet" << "Canon OfficeJet"; QComboBox *c;
QVBoxLayout *outerLayout = new QVBoxLayout(this); // Layout superior QHBoxLayout *topLayout = new QHBoxLayout(); topLayout->addWidget(new QLabel("Printer:")); topLayout->addWidget(c=new QComboBox()); // Fin Layout superior outerLayout->addLayout(topLayout); // Layout Central QHBoxLayout *groupLayout = new QHBoxLayout(); QGroupBox *orientationGroup = new QGroupBox("Page Orientation"); QVBoxLayout *orientationLayout = new QVBoxLayout(orientationGroup); orientationLayout->addWidget(new QRadioButton("Landscape")); orientationLayout->addWidget(new QRadioButton("Portrait")); groupLayout->addWidget(orientationGroup); QGroupBox *colorGroup = new QGroupBox((Coloi options); QVBoxLayout *colorLayout = new QVBoxLayout(colorGroup); colorLayout->addWidget(new QRadioButton("Black and White")); colorLayout->addWidget(new QRadioButton("Color")); groupLayout->addWidget(colorGroup); // Fin Layout Central outerLayout->addLayout(groupLayout); outerLayout->addStretch(); // Layout Inferior QHBoxLayout *buttonsLayout = new QHBoxLayout(); buttonsLayout->addStretch(); buttonsLayout->addWidget(new QPushButton("Print")); buttonsLayout->addWidget(new QPushButton("Cancel")); // Fin Layout Inferior outerLayout->addLayout(buttonsLayout);
c->addItems(options);
$"
Bemos sangiauo los bloques que ya teniamos constiuiuos paia uejai claio el couigo que hemos aauiuo, y el sentiuo uel mismo con iespecto a los bloques que contiene, y el spacei veitical. Tambin nos hemos peimitiuo el lujo ue aauii los items uel ComboBox que hain ue opciones, meuiante una StiingList.
782:9AI554C2 36 I2? V629?2? 36 '4YB8R8 582 (9 '6:4R26A Algunos pensain que soy un masoquista, uiseanuo la ventana a tecla, peio es funuamental apienuei antes el couigo que hay uetis ue touo, antes que abanuonaise al placei uel meio y puio uiseo, que nos sepaia ue la piogiamacion y poi tanto uel entenuimiento ue las bases funuamentales. vamos a cieai un nuevo pioyecto, uonue elegiiemos Qt C++ Pioject -> Qt u0I Application. Le pouemos llamai al pioyecto "uialog". La clase base se llamai "Bialog" y la clase base va a sei QWiuget. 0na vez se han cieauo touos los ficheios, abiimos "uialog.ui" que se nos abiii en el Qt Besignei. vamos a ii uibujanuo en l, el inteiface uel uiseo que estamos siguienuo. Iiemos colocanuo piimeio en la paite supeiioi, lo mejoi que pouamos, un Label y un ComboBox, aiiastinuolo ue las heiiamientas al foimulaiio y soltnuolo. Bacemos uoble clic sobie el texto uel Label y ponemos "Piintei:". Luego en el bloque cential vamos a situai piimeio los 2 uioupBox uno al lauo uel otio. Les cambiamos los textos, poi los que les coiiesponuen. Luego aauimos en la paite infeiioi los 2 PushButtons, y les cambiamos su texto. Ahoia vamos a ponei los RauioButtons en sus iespectivos uioupBoxes, y les ponemos el texto que les coiiesponuen. Ahoia situamos el spacei hoiizontal y el veitical, confoime al uibujo uel uiseo que estamos siguienuo. Si te uas cuenta, poi mucho que lo intentes, no va a queuai touo lo alineauo que queiemos, poi eso, es el momento ue comenzai a cieai los Layouts que oiganicen touo este espacio. Esto se hace siempie ue uentio hacia fueia, empezaiemos poi agiupai los RauioButton, seleccionanuo los uel giupo izquieiuo (ambos mantenienuo la tecla Ctil pulsaua, Cmu en los Nac), y los agiupamos pulsanuo el boton Lay 0ut veitically. Apaiece una caja ioja alieueuoi ue ellos que los alinea peifectamente entie si. vamos a hacei lo mismo con los ue la ueiecha. Luego vamos a seleccionai el uioupBox izquieiuo, y pulsamos Lay 0ut veitically, que lo oiganiza con su conteniuo, los iauiobuttons. Bacemos los mismo con el uioupBox ue la ueiecha. Luego seleccionamos ioueanuo con el iaton touo el bloque cential y pulsamos en Lay 0ut Boiizontally. Luego hacemos lo mismo con el giupo supeiioi (label y combobox) y con el giupo infeiioi (spacei hoiizontal y los 2 botones). Ahoia nos queuan los S giupos y el spacei veitical. Pulsamos sobie una zona vacia uel foimulaiio, paia seleccionailo a l poi completo, y teiminamos pulsanuo en Lay 0ut veitically. Ya se nos ha oiganizauo touos los wiugets con los layouts. Be hecho pueues vei como el uiseo se auapta flexiblemente al tamao libie ue la ventana si aiiastias uno ue los boiues uel foimulaiio, cambianuo su tamao, veis como touo se oiganiza en tamao y posicion peifectamente. Con esto uamos poi teiminauo el tema iefeiente a los elementos ue una ventana (wiugets y layouts), en el pioximo tema vamos a pasai a vei las ventanas ue uilogo, elemento inuispensable ue una aplicacion gifica. Si poi cuiiosiuau quieies aauii los items uel ComboBox, abie el couigo ue "uialog.cpp" y ujalo ue esta foima: QStringList options; options << "Office Printer" << "HP LaserJet" << "Canon OfficeJet"; ui->setupUi(this); ui->comboBox->addItems(options);
$#
Fijate que hemos acceuiuo uesue el objeto ui que iepiesenta el inteifaz uiseauo en el ficheio *.ui, a la combobox, poi su nombie (objectName), y entonces ya pouemos llamai a sus mtouos libiemente. Ya veiemos esto con ms uetalle ms auelante.
$$
)%/" ;_ n%&)"&"+ '% '0"<-^-
0n wiuget , que no tenga pauie se le llama top-level wiuget. 0n top-level pueue usai el mtouo show() paia mostiaise en pantalla, y pueue poi tanto constituiise como ventana. Asi hay S tipos ue top-level Winuows (ventanas): (D43R69.- Cualquiei wiuget sin pauie es constituiuo automticamente como una ventana, una ventana plana, como la que hemos cieauo en el tema anteiioi, o como la que se geneiaba simplemente mostianuo un QLabel en el ejemplo ue BolaNunuo. ('4?B8R.- Es un wiuget especial, que confoima una ventana que auems uevuelve un valoi siempie tias ceiiaise (0K, Cancel, etc.) (/?42D4238E.- Es otio wiuget especial, que confoima la ventana ms completa y poi tanto la piincipal ue una aplicacion gifica, con mens, heiiamientas, status bai, uock, etc. Puesto que ya hemos visto a los wiugets funcionanuo como ventanas, y las NainWinuows las tiataiemos a fonuo en el tema 19, en este tema vamos a tiatai ue ceica las ventanas ue uilogo, uescenuientes ue QBialog. Toua ventana ue Bilogo lleva una seiie ue wiugets que la componen, peio lo funuamental es que lleva botones paia aceptai yo iechazai una ueteiminaua accion, y que esa uecision es uevuelta al piogiama meuiante un valoi. En este capitulo vamos a vei el couigo que confoima a una ventana Bilogo paia su uso uentio ue una aplicacion mayoi, peio no vamos a uesaiiollai un ejemplo completo, ya que nos faltan elementos que no uebemos an tocai aqui y que una vez conociuos pouiemos uniilos touos en el tema 2u. 0na ventana uepenuienuo, ue la inteiactiviuau que bloquea, pueue sei: &8 /83?B.- Si no bloquea ninguna ventana que le acompae, y peimite estanuo ella abieita, inteiactuai con otias ventanas tambin abieitas. D4238E/83?B.- Solo bloquea la ventana pauie ue la misma, no puuienuo inteiactuiai con ella, hasta que sta es ceiiaua, aunque peimite inteiactuai con el iesto. "NNB45?9482/83?B.- Bloquea a touas las ventanas ue la aplicacion, solo puuienuo inteiactuai con ella mientias est abieita. Toua ventana ue Bilogo, heieua ue QBialog, y uebe llevai botones paia seleccionai opciones y pushbuttons paia aceptai o iechazai la accion. vamos a cieai una ventana ue uilogo con el Qt Besignei, tal como hemos apienuiuo en el tema pasauo, con esta foima:
$%
Asi que esta vez el pioyecto lo basaiemos en la clase QBialog y le llamaiemos SeaichBialog. 0na vez abieito el ficheio *.ui en el Qt Besignei, selecciona el foimulaiio, y a la ueiecha, cambia la piopieuau WinuowTitle en QWiuget, poi "Seaich" paia que salga el titulo que vemos en el uibujo. Constiuye algo similai a esto:
Y pulsanuo en el cuauio azul infeiioi ueiecho ue la seleccion uel foimulaiio, haz el tamao lo minimo que se pueua ue alto, peio hazlo al menos el uoble ue ancho que ue alto, ue maneia que se paiezca al uibujo oiiginal. Cambia el nombie uel QLineEuit poi "seaichText" y el ue los iauiobuttons poi "uiiectionFoiwaiu" y "uiiectionBackwaiu" iespectivamente. 0na vez hecho el uiseo, vamos a vei el couigo que lo integiai en la funcionaliuau ue una aplicacion ms compleja. En el aichivo seaichuialog.h en el constiuctoi ponuiemos un couigo como ste: class SearchDialog : public QDialog { Q_OBJECT public: explicit SearchDialog(const QString &initialText, bool isBackward, QWidget *parent = 0); ~SearchDialog();
// los getters que recogern las opciones bool isBackward() const; const QString &searchText() const;
private: Ui::SearchDialog *ui; };
Bemos puesto aigumentos paia inicializai el texto ue bsqueua, poi ejemplo, y asi que se conseive entie las bsqueuas. Tambin se inicializa ue igual maneia la opcion ue uiieccion ue la bsqueua. 0saiemos 2 getteis paia iecogei el estauo ue las opciones. vamos a vei la implementacion ue este couigo en seaichuialog.cpp . SearchDialog::SearchDialog(const QString &initialText, bool isBackward, QWidget *parent) : QDialog(parent), ui(new Ui::SearchDialog) { ui->setupUi(this); ui->searchText->setText(initialText); if(isBackward) ui->directionBackward->setChecked(true); else ui->directionForward->setChecked(true); }
Poi uefecto la ventana es moual, peio pueue sei cambiauo meuiante el mtouo setWinuowNouality(). Estbamos acostumbiauos a mostiai la ventana con show() (no moual poi uefecto), peio ahoia al haceilo con exec() (moual poi uefecto), lo que se uevolvei una vez ceiiaua, sei un valoi enteio, que es un BialogCoue.
Constant Value QDialog::Accepted 1 QDialog::Rejected 0
n629?2?: 36 '4YB8R8 +9?23?A3
Auems ue pouei uiseai ventanas a nuestio gusto y necesiuaues, Qt incoipoia una seiie ue ventanas que son muy tipicas ue las u0Is ue touas las platafoimas. En concieto son 6 tipos ms los subtipos ue caua una ue ellas. vamos a veilas uesue la ms sencilla a las ms avanzaua.
EFG 6>158#?0$3&<A= Es una ventana ue uilogo que piovee automticamente ue un Label, un LineEuit o un ComboBox, y los botones 0K y Cancel. Pueue iecogei: un Int, un Bouble, un texto o un Item ue un combo box, y lo hace con las funciones coiiesponuientes getInt(), getBouble(), getText() y getItem(). Touas estas funciones uevuelven como ltimo paimetio un bool que uice si se eligio el boton 0K (tiue), o el Cancel (false). vamos a vei el couigo ejemplo ue las 4 posibiliuaues:
H*"!53& +&1 <"#>1#I bool ok; int i = QInputDialog::getInt(this,"Ejemplo con getInt","Porcentaje:", 25, 0, 100, 1, &ok);
H*"!53& +&1 <"#?&8)3"I double d = QInputDialog::getDouble(this," Ejemplo con getDouble", "Cantidad:", 37.56, -10000, 10000, 2, &ok);
QString item = QInputDialog::getItem(this, " Ejemplo con getItem", "Estacin:", items, 0, false, &ok); if (ok && !item.isEmpty()) itemLabel->setText(item);
H*"!53& +&1 <"#A"B#I QString text = QInputDialog::getText(this, "Ejemplo con getText", "Usuario:", QLineEdit::Normal, QDir::home().dirName(), &ok); if (ok && !text.isEmpty()) textLabel->setText(text);
$'
JFG6H44&47"''$<".- Es una ventana ue eiioi que piovee ue un TextLabel y un CheckBox.
errorMessageDialog = new QErrorMessage(this); errorMessageDialog->showMessage("Esta ventana muestra un error. " "Si el checkbox se deja, volver a mostrarse, " "si no se deja, ya no volver a mostrarse. ");
Con showNessage() ponemos el texto uel eiioi, automticamente apaiecei el checkbox uicienuo si quieie que se muestie el eiioi ue nuevo, si ueciue que no, ya no volvei a salii, aunque sea llamaua en el couigo la funcion showNessage() ue nuevo.
KFG67"''$<"L&B.- Es una ventana moual que piegunta al usuaiio una piegunta, y iecibe una iespuesta. Las hay ue 4 tipos:
if (reply == QMessageBox::Yes) // codigo de Yes else if (reply == QMessageBox::No) // codigo de No else // codigo de Cancel
/%3*$4#)/*%.-
QMessageBox::StandardButton reply; reply = QMessageBox::information(this," information", MESSAGE); if (reply == QMessageBox::Ok) // codigo de OK else // codigo de Escape (tecla escape) no todos los sistemas lo admiten
QString directory = QFileDialog::getExistingDirectory(this, "getExistingDirectory", defaultDirName, options); if (!directory.isEmpty())// codigo de apertura de directorio
%*
%)
)%/" ;L /-'%<-U n0+)" . 7-&)$-<"'-$U 0&)$-'\770-&
El piimei lenguaje que poi piimeia vez intiouujo el paiauigma NvC (Nouelo, vista, Contiolauoi) fue Smalltalk en 1979 en el laboiatoiio ue Xeiox. Actualmente muchos lenguajes y fiamewoiks lo han incoipoiauo como una ventaja al uesaiiollo inestimable, y poi supuesto Qt no iba a sei menos. En la gian mayoiia ue aplicaciones, se acceue a fuentes ue uatos, que pueuen sei, un ficheio, un sistema ue aichivos, una base ue uatos, un stieam ue uatos, etc. Luego esos uatos se muestian al usuaiio ue uiveisas foimas, y el usuaiio inteiacta con ellos, mouificnuolos, leynuolos o tiatnuolos ue alguna maneia y la fuente ue los mismos es actualizaua con uicha mouificacion o tiatamiento. El paiauigma NvC sepaia en S aspectos uifeientes ue esta activiuau, poi un lauo esta el Nouelo, que est en contacto uiiecto con la fuente ue uatos, ue maneia que es quien iecoge los uatos ue la misma y los actualiza. Esos uatos son enviauos poi el mouelo a la vista (view), que se encaiga ue visualizailos ue una maneia especifica. 0n mismo mouelo pueue alimentai vaiias vistas uifeientes y ambas sincionizai su conteniuo a la vez. Sobie la vista el usuaiio inteiacta, y la misma pueue pioveei ue mtouos paia enviai mouificaciones ue los uatos al Nouelo (mouel), y este a la fuente ue uatos, o existen tambin objetos especiales, especializauos en la inteiaccion uel usuaiio con la vista, que aqui no se llama Contiolauoi sino Belegauo (uelegate). La veiuau es que se tiata ue conceptos muy abstiactos, y cieo que lo mejoi es poneilos a funcionai paia vei ue lo que estamos hablanuo. Suponga que quieie piesentai en una ventana en foima ue ibol el conteniuo completo uel uiiectoiio ue su oiuenauoi, con ficheios y uiiectoiios. Sin uuua seiia algo uificil ue hacei meiamente con QTieeWiuget y QBii (QFileInfo, etc), y si al final lo logiaia, seguio que ocupaiia bastantes lineas ue couigo. Pues bien, el paiauigma NvC viene a nuestio iescate, paia hacei ue esta taiea algo sencillo y con poco couigo, ue hecho se pouiia hacei con solamente 4 lineas ue couigo, si no fueia poique nos gusta cambiai unas ueteiminauas piopieuaues ue la vista, peio en cualquiei caso no va a pasai ue las 1u lineas. Como es eso posible.. Qt piovee ue una seiie ue vistas suficientes paia lo que cualquieia suele piogiamai, y tambin ue los mouelos paia lo mismo, peio si esto no fueia asi, seiia mucho ms sencillo cieailos paia pouei poneilos a tiabajai juntos, a hacei un piogiama especifico con un couigo complejo y poco ieutilizable. Cuanuo un piogiamauoi se pone a esciibii mucho couigo, es poique sabe que lo va a ientabilizai en el tiempo, ue lo contiaiio, se est quieto. Bien, pues paia llevai a cabo la aplicacion que hemos comentauo, vamos a usai como vista, la clase QTieeview, que nos piovee ue un magnifico gifico en ibol muy avanzauo y paiametiizable, y como Nouelo, vamos a usai la clase QBiiNouel, que se ielaciona uiiectamente con el sistema ue aichivos como su fuente ue uatos. Aunque paiezca mentiia, simplemente hay que combinai ambas clases, Nouelo y vista paia que suija la chispa mgica, y eso se hace con el mtouo ,&)D*2&564*2&5%#4&7 , que pioveen touas las vistas. Be esta maneia la vista es caigaua con uatos que consigue el mouelo paia ella. vamos a poi el couigo. Esta vez vamos a cieai un pioyecto vacio (Empty Pioject), al que vamos a llamai "mvc". Luego vamos a aauiile un ficheio fuente "main.cpp" y vamos a empezai a esciibii uiiectamente en l. #include <QtGui> #include <QApplication> int main(int argc, char **argv) { QApplication app(argc,argv);
// Vamos a cambiar el aspecto de la vista view.setAnimated(false); view.setIndentation(20); view.setSortingEnabled(true); view.setWindowTitle("Dir View"); view.resize(640,480); // vamos a mostrar la vista view.show();
return app.exec(); }
Eso es touo el couigo, vamos a vei cual es el iesultauo final ue esas pocas lineas.
Efectivamente es impiesionante el iesultauo obteniuo con tan escueto couigo. Con esto queua justificauo sobiauamente el uso uel paiauigma NvC siempie que sea posible. Ahoia que he conseguiuo tu atencion, es hoia ue que te piesente las vistas y los mouelos ue que vas a uisponei en Qt, que como ya apuntamos van a sei suficientes paia la gian mayoiia ue aplicaciones que vas a acometei. Si esto no es asi, en un cuiso ms avanzauo pouis apienuei a cieai tus piopios mouelos, o tus piopias vistas, peio eso ya se sale uel pioposito ue este piimei libio.
<?: n4:9?: Las vistas que piopoiciona Qt son touas ueiivauas ue la clase 6Q)'#4$+#>#"!R0"S . Las vistas que ue ella se ueiivan son ties tipos piincipalmente: QListview, QTableview y QTieeview. QListview, piopoiciona una vista uniuimensional, uonue hay solo una columna (column) y muchas filas (iow). Bispone ue una seiie ue mtouos paia cambiai la piesentacion ue los items ue la misma. QTableview, es la ms usaua, sobie touo en la piesentacion ue tablas ue bases ue uatos. Tiene foima biuimensional con vaiias columnas y vaiias filas, auems posee cabeceia tanto paia las columnas como paia las filas, paia ponei sus titulos en ellas. %"
QTieeview, es usaua sobie touo en acceso a uiiectoiios, como hemos visto en el ejemplo, y uispone la infoimacion en foima ue ibol. Auems tambin uispone ue cabeceia hoiizontal (heauei), paia ponei titulos a las piopieuaues ue los items.
<8: P836B8: Los mouelos que piopoiciona Qt paia acceuei a los uifeientes tipos ue fuentes ue uatos, ueiivan ue 6Q)'#4$!>#"!7&%"3, y entie los que piopoiciona estn: QStiingListNouel, QStanuaiuItemNouel, QFileSystemNouel y QSqlRelationalTableNouel. E()$/%>F/,)D*2&5, es usauo paia guaiuai una lista ue QStiings. E()#%2#$2G)&4D*2&5, se usa paia el manejo ue estiuctuias ms complicauas en foima ue ibol, que pueuen guaiuai cualquiei tipo ue uatos. E./5&(:,)&4D*2&5, piovee ue la infoimacion que obtiene uel sistema ue ficheios, como E?/$D*2&5, peio ms avanzauo. E(C5H&5#)/*%#5I#95&D*2&5, se usa paia tiatai uatos piovenientes ue una base ue uatos ielacional. Be ella ueiiva E(C5I#95&D*2&5 que se usa paia guaiuai los uatos ue una tabla concieta ue una base ue uatos. Be ella ueiiva E(C5E+&$:D*2&5 que guaiua los uatos ue la iespuesta a una queiy a una base ue uatos.
-H:6AV?54826: O42?B6: Como pueues imaginai, combinanuo una vista o vaiias vistas con un mouelo, pueuo obtenei el inteifaz gifico que necesito paia inteiactuai con los uatos que quieio. El caso ms tipico es con una base ue uatos ielacional, como NySQL u 0iacle. Se tiataiia poi tanto ue combinai una QTableview con una QSqlTableNouel o una QSqlQueiyNouel. veiemos casos concietos en los temas que coiiesponuan a bases ue uatos.
%#
%$
)%/" ;g (<0+)D0'^%) . ()"><%D0'^%)
Beiivauas ue QListview y QTableview, tenemos 2 clases que iepiesentan vistas en foima ue lista y tablas, iespectivamente, con un mouelo pieuefiniuo. Ambos son QWiugets piopoicionauos poi la baiia ue heiiamientas uel Qt Besignei, y suelen sei usauos paia aplicaciones sencillas uonue no se usan mouelos combinauos con ellas. Estn foimauos poi items ue las clases QListWiugetItem y QTableWiugetItem, iespectivamente.
(<4:9D43R69 Paia aauii elementos a esta Lista hay 2 foimas: 1.- Constiuyenuo los items con esta clase como pauie. new QLIstWidgetItem ("Texto elemento 1",listWidget);
2.- Constiuyenuo el item sin pauie y aauinuolo a la lista ms taiue. QListWidgetViewItem *newItem = new QListWidgetViewItem; newItem->setText("Texto Elemento 1"); listWidget->insertItem(row,newItem);
En la segunua opcion tambin se pueue usai el mtouo /%,&)G%)&4,6E()$/%>F/,)7, y tambin #22G)&46E()$/%>7, que aaue al final uel anteiioi, y no es una posicion exacta. El mouo ue seleccion ue los elementos en la lista se pueue leei con la funcion ,&5&0)D*2&67, y se pueue establecei con la funcion ,&)(&5&0)/*%D*2&6,&54*2&7. Los uifeientes mouos ue seleccion son: SingleSelection (un solo elemento), NultiSelection (vaiios elementos a la vez), ContiguousSelections (vaiios elementos contiguos a la vez) y NoSelection (no se pueue seleccionai naua). La iazon ue usai QListWiugetItem en vez ue QStiings en la inseicion ue elementos, es poique, ste peimite no solo inseitai texto en las listas, si no tambin iconos. Asi tambien hay uos Nouos ue vista: IconNoue (uiag & uiop uesabilitauo poi uefecto) y ListNoue (uianu & uiop habilitauo poi uefecto). Tambin se pueue cambiai el tamao uel icono con ,&)G0*%(/J&6E(/J&7, y el espaciauo con ,&)(-#0/%>6K#5+&7. Paia boiiai items, se pueue usai )#L&G)&46$*B7, y los Items pueuen apaiecei en la lista maicauos con EF/,)M/&BG)&4NN,&)81&0L()#)&6E)NN81&0L()#)&7. La nica seal que usamos en esta clase es 0+$$&%)G)&481#%>&260+$$&%)O-$&K/*+,7, que se piouuce al cambiai el foco ue item. La funcion 0+$$&%)G)&467, nos uevuelve el item actual, y 0+$$&%)H*B67, nos uevuelve el iow (fila) uel item actual.
()?HB6D43R69 Se pueue uimensionai en la cieacion en el constiuctoi (%&B EI#95&P/2>&) 6$*B,O0*5,O-#$&%)7 ), y luego ieuimensionaila con ,&)H*B8*+%)6$*B,7 y ,&)8*5+4%8*+%)60*5,7. Pouemos aauii items con ,&)G)&46$*BO0*5O%&BG)&47, uonue newItem es un QTableWiugetItem. Se pueuen boiiai items con )#L&G)&46$*BO0*57. Pouemos ponei etiquetas en las cabeceias hoiizontales con ,&)Q*$/J*%)#5Q&$F#9&5,6E()$/%>F/,)7 y en las cabeceias %%
veiticales con ,&)M&$)/0#5Q&$F#9&5,6E()$/%>F/,)7. Tambin oiuenai poi una columna usanuo ,*$)G)&4,60*5O E)N(*$)R$2&$7. Con $*B8*+%)() pouemos contai las filas, con 0*5+4%8*+%)() las columnas, y con 05&#$() boiiai touo el conteniuo ue las celuas. QTableWiugetItem, tiene funciones inteiesantes como ,&)G0*%(), ,&).*%)() y ,&)I&S)(). Las seales ms usauas son: 0&5585/0L&26/%) $*BO/%) 0*57O 0&5581#%>&26/%) $*BO/%) 0*57O /)&485/0L&26EI#95&P/2>&)G)&4 /)&47O /)&481#%>&26EI#95&P/2>&)G)&4 /)&47.
veamos ahoia un ejemplo ue tabla con las cosas que hemos visto: #include <QtGui>
int main(int argc, char **argv) { QApplication app(argc,argv);
for(int mes=0; mes < 12; mes++){ tabla.setItem(mes,0,new QTableWidgetItem(meses[mes])); }
for(int mes=0; mes < 12; mes++){ tabla.setItem(mes,1,new QTableWidgetItem(dias[mes])); }
tabla.resize(240,400); tabla.show();
return app.exec(); }
%&
)%/" ;[ (9 7$%")-$
Queiemos ueuicai un poco ue tiempo al entoino ue uesaiiollo integiauo ue Qt, su IBE llamauo Qt Cieatoi. En un piincipio Qt no poseia un IBE, touo el couigo tenia que sei esciito en un euitoi ue texto avanzauo, o integiauo en otio IBE como Eclipse. Y an se pueue seguii hacienuo asi, peio uesue la veision 4.u uel SBK, Tiolltech incluyo Qt Cieatoi como un entoino ue uesaiiollo completo, uesue uonue se pueue acceuei al Qt Assistant, al Qt Besignei, se pueue compilai, uebugeai uesue l. Peio una ue las caiacteiisticas ms inteiesantes paia el que pica couigo, es el autoiiellenauo, y las teclas ue acceso ipiuo. Poi ello, queiemos ueteneinos un tiempo paia vei como pouemos sacai ventaja en nuestio uesaiiollo ue este IBE avanzauo.
%B ?I98A6BB62?38 Cuanuo abiimos un ficheio ue couigo *.h , *.cpp, y nos situamos en una linea paia empezai a tecleai couigo, y queiemos que el sistema nos ayuue a iellenai, uesue un ficheio cabeceia, una clase, una vaiiable ya uefiniua, solo tenemos que pulsai la tecla Ctil+espacio, paia que apaiezca toua una seiie ue alteinativas factibles, ue acueiuo a lo que ya hay esciito y ueclaiauo en el ficheio. Tecleanuo las piimeias letias ue lo que queiemos ponei, nos iin apaiecienuo las opciones caua vez ms especificas ue maneia que muchas veces no hace falta acoiuaise uel nombie exacto ue una clase, un ficheio o una vaiiable. Si entie las opciones que nos uan, no apaiece una clase o vaiiable especifica, es que no es accesible uesue esa paite uel uocumento, poi cualquiei iazon, que pueue sei uesue que no est incluiuo su ficheio cabeceia, a que uicha vaiiable no es accesible en uicha zona. Tambin nos ayuua a acceuei a los miembios ue las clases, y nos ua los aigumentos ue las funciones cuanuo esciibimos tias ellas, los paintesis. Cuanuo nos situamos sobie un elemento uel couigo, se nos iecuauia este, y touos los mismos elementos uentio ue la misma zona ue mbito. Be esta foima pouemos vei los mbitos, y haceile un seguimiento a una vaiiable. Si necesitamos ayuua uel Qt Assistant sobie algn elemento uel couigo, solo hay que situaise sobie l y pulsai F1, entonces se nos abiii a la ueiecha uel couigo la ventana ue ayuua coiiesponuiente. Confoime se esciibe, si hay algn eiioi sintctico, apaiece subiayauo en iojo, y si nos situamos sobie l, nos apaiece un mensaje emeigente, uesciibienuo el eiioi.
"9?@8: 36 965B?38 Wm6KH8?A3 :T8A95I9:X Ctil + cuisoi ueiecho .- Te lleva al final ue la linea actual. Ctil + cuisoi izquieiuo .- Te lleva al piincipio ue la linea actual. Shift + cuisoies .- Seleccion ue texto. Ctil + 0pBown.- Pasa pginas ue couigo aiiiba y abajo. Ctil + u (Cmu + 0 en Nac).- Seleccionas bloques, pulsanuo vaiias veces aumentas el bloque ue seleccion. Ctil + i (Cmu + i en Nac).- Bace que el couigo seleccionauo tome la sangiia iequeiiua. %'
Ctil + Shift + 0pBown (Cmu + Shift + 0pBown en Nac).- Peimite movei lineas completas hacia aiiiba o hacia abajo. Funciona tambin con selecciones completas, movienuo el texto seleccionauo. Ctil + (Cmu + en Nac).- Comenta y uescomenta touo un bloque seleccionauo. Shift + Bel .- Boiia toua una linea completa. F4 .- Pasa ue ficheio cabeceia a ficheio ue couigo y viceveisa. F2 .- Pasa ue la ueclaiacion a la implementacion ue una funcion o mtouo. Ctil + K .- Abie el localizauoi, paia pouei navegai poi ayuuas y uocumentos ipiuamente. Ctil + Shift + R (Cmu + Shift + R en Nac).- Peimite cambiai el nombie ue una vaiiable a la vez en touas las paites uonue tiene mbito.
%(
)%/" ;i /"0& D0&'-D+
Este es el tema ms impoitante ue touos los iefeientes al uesaiiollo gifico, ya que en l se encuentia la base funuamental ue touas las aplicaciones gificas. La ventana piincipal (QNainWinuow), es el componente funuamental, sobie la cual pueuen apaiecei toua una seiie ue wiugets: QNenuBai (baiia ue menu), QToolBai (baiias ue heiiamientas), QStatusBai (baiia ue estauo), QBockWiuget (wiugets acoplables), QNenu (menus en geneial, incluiuos los contextuales) y otios que ya hemos visto o que veiemos.
El inteifaz piincipal ue una aplicacion, la Nain Winuow (ventana piincipal), posee los elementos que vemos en la foto ue aiiiba: un men piincipal en la paite supeiioi, una o vaiias baiias ue heiiamientas con iconos, justo uebajo, que piopoiciona las opciones uel men ms tipicas en el uso cotiuiano, mejoianuo la iapiuez ue uso ue la aplicacion, luego esta el wiuget piincipal (cential wiuget), que en este caso est en la zona cential izquieiua, y es un QPlainTextEuit, a la ueiecha vemos una ventana auosable (uockable winuow), que se uifeiencia poi el icono ue la esquina supeiioi ueiecha, que nos inuica que pulsanuo sobie la baiia supeiioi y aiiastianuo, uicha ventana se sepaiaiia ue la ventana piincipal, piopoicionanuo otia ventana, finalmente en la paite infeiioi, se encuentia la baiia ue estauo (status bai) uonue se suele ponei mensajes infoimativos al usuaiio al iespecto ue lo que esta acontecienuo en la aplicacion en caua momento. Tambin caua elemento ue la ventana piincipal, pueue tenei un men contextual asociauo, que al pulsai el boton ueiecho uel iaton nos peimita llevai a cabo acciones piopias ue uicho elemento gifico. A paite ue estos elementos, una aplicacion pueue aauii ventanas ue uilogo, ueiivauas ue QBialog, que pouin apaiecei como consecuencia ue acciones uel usuaiio, como pulsai sobie una opcion uel men, una atajo uel teclauo, un mens contextual, o algn evento cualquieia (infoimacion, aviso, eiioi, etc).
("59482 La piincipal mision ue una QNainWinuow, es centializai touo el inteifaz que comunica al usuaiio, con la activiuau que la aplicacion lleva a cabo, poi ello touos los elementos que la componen estn enfocauos a piopoicionai uicha inteifaz. Sin embaigo, una aplicacion pueue iecibii oiuenes poi paite uel usuaiio paia llevai a cabo una misma accion uesue uifeientes &*
componentes, como poi ejemplo, pegai una seleccion pievia en el wiuget piincipal, pouiia haceise seleccionauo la opcion Euitai->Pegai en el men piincipal, o pulsanuo sobie el icono coiiesponuiente en la baiia ue heiiamientas, o seleccionauo Pegai, uel men contextual uel wiuget piincipal, o simplemente pulsanuo una combinacion ue teclas (shoitcut) que lleve a cabo uicha accion. Bebiuo a que una misma accion pouiia uesencauenaila uifeientes elementos, es poi lo que touas las acciones se han centializauo entoino a una clase que no tiene iepiesentacion gifica fisica, llamaua QAction. Caua opcion uel men piincipal, ue las toolbais o ue los context menus, se coiiesponuen con un objeto QAction (una accion), y una misma accion pueue sei alcanzaua uesue vaiios ue estos elementos, lo cual va a iepeicutii en como ha ue uefiniise una accion. vamos a vei la uefinicion ue una accion: QAction *actionNew = new QAction("&New",this); actionNew->setIcon(QIcon(":/images/new.png")); actionNew->setShortcut("Ctrl+N"); actionNew->setStatusTip("Crear un nuevo documento"); actionNew->setToolTip("Crear un nuevo documento"); actionNew->setCheckable(false); // set connect(actionNew, SIGNAL(triggered()), this, SLOT(newFile()));
Pouemos vei que piimeio cieamos un objeto accion que tenui el texto asociauo "&New" (uonue el & va uelante ue la letia que queiemos vaya subiayaua inuicanuo la combinacion ue teclas al usuaiio que nos llevai tambin a la misma accion). Luego meuiante una seiie ue mtouos ue QAction, vamos uefinienuo la accion, que pueue tenei asociauo un icono (ya veiemos ms auelante esto con ms uetalle), establecemos el shoitcut ue teclauo, establecemos el texto que apaiecei en el status bai, al ejecutai esta accion, tambien el tooltip o texto emeigente con la uesciipcion ue uicha accion si nos situamos sobie ella con el punteio uel iaton, ueciuiiemos si es una opcion checkable, es uecii que pueua llevai una maica ue activaua o uesactivaua, finalmente establecemos la conexion entie la seal tiiggeieu(), que se piouuce al pulsai sobie esa accion, y el slot que en este caso pueue sei una funcion que nosotios mismos vamos a uefinii lo que va a hacei.
/62j NA4254N?B Caua opcion piincipal uel men piincipal, valga la ieuunuancia, es uecii, las que se ven en la cabeceia ue la ventana sin pulsai sobie ellas, son objetos QNenuBai que son cieauos poi la QNainWinuow, caua vez que se llama a su funcion miembio !"18L$4,-, y con ello pasan a sei hechas hijas ue esta ventana. Caua opcion piincipal, poi tanto iequieie llamai la piimeia vez a uicha funcion paia cieaise, y luego va aauienuo acciones (subopciones ue la misma) y sepaiauoies. QMenu *fileMenu; fileMenu = menuBar()->addMenu("&File"); fileMenu->addAction(actionNew); fileMenu->addAction(openAction); fileMenu->addSeparator(); fileMenu->addAction(exitAction);
La funcion miembio ue NainWinuow, auuToolBai, aaue una baiia con una seiia ue acciones, que llevan su piopio icono.
&)
/62I 58296J9I?B W58296J9 P62IX Se asocia uiiectamente el wiuget que lo va a mostiai, y solo hay que aauiile las acciones que va a mostiai, y finalmente cambiai ue uicho wiuget la piopieuau ContextNenuPolicy paia que apaiezca al pulsai clic ueiecho. QPlainTextEdit *editor; editor->addAction(copyAction); editor->addAction(pasteAction); editor->setContextMenuPolicy(Qt::ActionsContextMenu);
>?AA? 36 6:9?38 W:9?9I: H?AX La baiia ue estauo noimalmente contenui wiugets uel tipo QLabel, paia mostiai texto con avisos al usuaiio. Paia ello, piimeiamente iecogemos el punteio a la baiia ue estauo con la la funcion ue QNainWinuow, '#$#8'L$4,-. Luego aauimos los wiugets, usanuo la funcion ?33D43R69WX, poi lo que como se ve, una statusbai es un conteneuoi. QLabel *label = new QLabel(); label->setAlignment(Qt::AlignHCenter); label->setMinimumSize(label->sizeHint()); statusBar()->addWidget(label);
<? V629?2? NA4254N?B W(/?42D4238EX La ventana piincipal al sei ueclaiaua e implementaua, uebe ue contenei touos los elementos que hemos uesciito antes, toua una seiie ue slots entie los cuales estain las funciones que ejecutan las acciones, como newFile(), que hemos visto en el ejemplo ue QAction. Tambin es inteiesante el ieuefinii la funcion viitual +3&'"H@"1#,6N3&'"H@"1# T"@"1#-, paia poi ejemplo inteiceptai la seal ue cieiie ue la aplicacion con alguna ventana ue uilogo que pueua pieguntai, si est seguio ue ceiiai. 0tia cosa esencial que uebe ue tenei en la implementacion ue su constiuctoi, es la uesignacion como wiuget cential, esto se hace con su funcion miembio '"#N"1#4$3D0%<"#,6D0%<"# T-.
]45T6A8: 36 A65IA:8: WoZSA5X Los iecuisos que usa una aplicacion, como pueuen sei iconos, bitmaps y otios, van uesciitos en un ficheio ue iecuisos multiplatafoima que lleva la extension qic. Qt sopoita muchos tipos ue imgenes e iconos tales como: BNP, uIF, }Pu, PNu, PNN, XNB y XPN. El ficheio qic foima paite uel pioyecto antes ue sei compilauo e incluiuo en el ejecutable. Se tiata ue un ficheio esciito en XNL con el siguiente foimato: <!uCC1?L 8CC> <8CC verslon="1.0"> <qresource> <flle>lmages/lcon.png</flle> --- <flle>lmages/goLocell.png</flle> </qresource> </8CC> En el ficheio ue pioyecto (*.pio) se aaue una linea que pone: RES00RCES = iecuisos.qic En el couigo C++ ya se pueue acceuei a esos ficheios uiiectamente meuiante la 0RL ":imagesicon.png", poi ejemplo: action->setIcon(QIcon(":/images/new.png"));
&!
Bonue vemos que el ficheio uel icono se encuentia en la caipeta uel pioyecto en "imagesnew.png".
(+69942R: W?@I:96:X Es muy til y agiauable paia el usuaiio, que el aspecto que el inteiface tenia al cieiie, vuelva a iecupeiaise al ieabiii la aplicacion al uia siguiente. Poi lo que, es muy usual que las aplicaciones moueinas guaiuen una seiie ue paimetios que ueteiminan touo esto que llamamos "settings", y lo iecupeien la pioxima vez que sea ejecutaua. Caua sistema opeiativo o platafoima, gestiona esto ue una maneia uistinta, y lo guaiua en sitios uifeientes, poi eso Qt, piovee ue una clase y mtouos paia tiatai este tema ue maneia unifoime e inuepenuiente ue la platafoima. Bicha clase es QSettings, y meuiante sus mtouos setvalue() y value(), el settei y gettei ue la misma, gestiona el almacenamiento y iecupeiacion ue uichos ajustes (settings). (+69942R:bb(+69942R: W 582:9 (+9A42R d&4<$10U$#0&1U 582:9 (+9A42R d$5530+$#0&1e (+9A42RWXU(-H@659 o5$4"1# e l X Ejemplo ue cieacion ue settings: QSettings settings("Qt Software, Inc", "TextEditor");
(n?A4?29 (+69942R:bbV?BI6 W 582:9 (+9A42R dV"WU 582:9 (n?A4?29 d%"/$83#R$38" e (n?A4?29WX X 582:9 Ejemplo ue iecupeiai cieitos settings: QRect rect = settings.value("geometry",QRect(200,200,400,400)).toRect(); bool showGrid = settings.value("showGrid",true).toBool();
+NB?:T :5A662: Son las ventanas que apaiecen mientias se caigan los elementos ue un piogiama, poi uiveisos motivos como, inuicai al usuaiio que se estn caiganuo y uaile infoimacion uuiante el tiempo ue espeia o poi puia autopiomocion. En cualquiei caso es un elemento ms ue una aplicacion que muy a menuuo se usa. Lo ms habitual es que el couigo que muestia el splash scieen, se encuentie en main() antes ue que se llame a QApplication::exec(). La clase que la uesciibe es 6C53$'2C+4""1, y usa funciones ue QWiuget como show() paia mostiaise y setPixmap(QPixmap) paia establecei el fonuo a mostiai, finalmente el mtouo showNessage() peimite sobieimpiesionai un mensaje sobie el fonuo ue uicha pantalla. V843 (+NB?:T+5A662bb:69#4JP?N W 582:9 (#4JP?N d50B!$5X V843 (+NB?:T+5A662bb:T8E/6::?R6 W 582:9 (+9A42R d!"''$<"U 429 $30<1!"1# e (9bb"B4R2<6O9U 582:9 (78B8A d+&3&4 e (9bbHB?5m X
&"
veamos un ejemplo sencillo: #include <QtGui/QApplication> #include "mainwindow.h"
int main(int argc, char *argv[]) { QApplication a(argc, argv);
QSplashScreen *splash = new QSplashScreen; splash->setPixmap(QPixmap(":/images/splash.png")); splash->show(); splash->showMessage("Iniciand ventana principal ...", Qt::AlignRight | Qt::AlignTop, Qt::white);
Bate cuenta ue que, se muestia el splash scieen con su gifico, luego se muestia el piimei mensaje sobie el Pixmap en la zona supeiioi ueiecha en texto blanco, luego se lleva a cabo la accion que inuica el mensaje, luego el siguiente mensaje, luego la accion que inuica el mismo, y asi hasta que una vez touo esta caigauo e iniciauo, entonces muestia la ventana piincipal. La funcion finish(const QWiuget&), lo que hace es espeiai a que se caigue completamente el Wiuget, en este caso la NainWinuow, antes ue hacei un close() sobie l mismo. En el pioximo tema, vamos a uesaiiollai uesue ceio una aplicacion completa con touo lo que hemos apienuiuo hasta el uia ue hoy, y lo haiemos piimeio a couigo puio, sin uiseo visual, paia compienuei y iepasai touos los conceptos bien, y finalmente veiemos como eso mismo se pueue hacei ue maneia visual en el Qt Besignei. Poi lo tanto, es muy impoitante que touos los conceptos queuen peifectamente aclaiauos con este ejemplo, ya que hasta aqui hemos completauo el bloque piincipal y bsico paia constiuii aplicaciones en Qt, y sobie esta base vamos a apoyai el iesto ue la enseanza que viene tias el tema 2u, uonue abunuaiemos en conceptos ya piesentauos, e intiouuciiemos nuevos conceptos, peio touos funuamentauos en esto piimeios 2u temas, que confoiman el nivel Bsico.
&#
&$
)%/" Gl '%+"$$-<<- '% \&" "#<07"70Q& 7-/#<%)"
En este tema vamos a uesaiiollai un euitoi ue texto, con capaciuau paia cutpaste, con men piincipal, baiia ue heiiamientas y status bai. Intiouuciiemos algunos conceptos nuevos, peio pocos, como hemos hecho en los temas anteiioies, paia seguii sienuo fieles al estilo ue enseanza giauual que estamos usanuo en este libio. El pioyecto pueues abiiilo uiiectamente en el Qt Cieatoi, peio te iecomienuo que sigas las explicaciones que se van a uai en este tema, y que luego poi tu cuenta, intentes uesaiiollai lo mismo, o algo similai uesue ceio. vamos a cieai un nuevo pioyecto "Qt uui Application", al que llamaiemos "application", la clase se llamai NainWinuow, su clase base sei QNainWinuow, y uesactivaiemos la opcion "ueneiate foim" paia asi cieai nosotios mismos el inteifaz gifico en couigo puio. Lo siguiente que vamos a hacei es copiai los iconos que vamos a usai (uiiectoiio images) en nuestio pioyecto, tambin en una caipeta llamaua images, uentio ue nuestio pioyecto. Be nuevo hacemos clic ueiecho sobie le nuevo pioyecto y aauimos un nuevo Qt->Qt Resouice File, al que llamaiemos tambin "application". Al abiiise el ficheio qic en el Qt Cieatoi, apaiece una ventana supeiioi vacia, y abajo un boton Auu. Pulsamos sobie l y luego sobie Auu Piefix. En el campo ue texto Piefix, vamos a ponei "". volvemos a pulsai en Auu-> Auu Files, y navegamos hasta el uiiectoiio images uonue hemos copiauo los iconos que vamos a usai, seleccionamos los 6 iconos y los abiimos. Ya apaiecen los 6 iconos ausciitos al piefijo "", asi que ya pouemos acceuei a ellos usanuo una 0RL uel tipo ":imagesicono.png", uonue ":" hace iefeiencia a los iecuisos inteinos.
0samos la macio Q_INIT_RES00RCE(nombie_base_uel_qic), aunque en la mayoiia ue los casos no sea necesaiio y los iecuisos se caiguen automticamente, peio en algunas platafoimas, los iecuisos se guaiuan en una libieiia esttica. Touo lo uems ya lo hemos visto anteiioimente, a paite ue los uos miembios ue QApplication que se encaigan ue guaiuai en la aplicacion el nombie ue la empiesa que hizo la aplicacion y el nombie ue la misma. Como vemos, vamos a usai una NainWinuow que hemos ueiivauo ue QNainWinuow y que esta implementaua en los ficheios mainwinuow.h y .cpp .
<? 5B?:6 /?42D4238E &%
uian paite uel couigo y ue la estiuctuia uel mismo ue esta clase, pouin sei usauos en otias aplicaciones. vamos a vei piimeiamente el wiuget que vamos a uesignai como wiuget cential o piincipal ue la ventana Piincipal (NainWinuow). Al sei una aplicacion euitoia ue texto, vamos a usai QPlainTextEuit como el wiuget piincipal. Si consultas uicha clase en el asistente (Qt Assitant), pouis vei entie sus miembios, los slots que usaiemos en los mens, como cut(), copy(), paste(). Tambin pouis vei la funcion ms impoitante, que es uocument(), que uevuelve un punteio al texto uel mismo uel tipo QTextBocument. Be entie los miembios ue ste ltimo, usaiemos isNouifieu() paia sabei si el uocumento ha siuo mouificauo en algn momento. Luego tenuiemos que miiai los slots que vamos a necesitai uefinii en la nueva clase. Puesto que caua entiaua uel men iequieie ue una conexion entie la seal tiiggeieu() ue la accion, y un slot que ejecuta la accion. Poi lo que tenuiemos que uai un iepaso a las opciones ue men que vamos a ponei, paia sabei los slots que tenuiemos que ueclaiai en esta clase. Tenuiemos un men File con los siguientes submens (Nuevo, Abiii, uuaiuai, uuaiuai como y Salii). A excepcion ue la opcion Salii, que la ejecutaiemos con el slot close() ue QWiuget, el iesto sein slots a ueclaiai e implementai. Tenemos tambin el men Euit con los siguientes submens (Coitai, Copiai y Pegai). Puesto que touos ellos pueuen ejecutaise uesue los slots pieuefiniuos en QPlainTextEuit, iespectivamente cut(), copy() y paste(), no es necesaiio implementai nuevos slots paia este men. Finalmente tenemos el men Ayuua con los submens (Aceica ue y Aceica ue Qt), ue los cuales, aceica ue Qt viene ya pieimplementauo como el slot aboutQt() ue QApplication. Cuanuo el uocumento es mouificauo, uebe ue habei una accion que cambie la piopieuau uel wiuget mouificauo, winuowNouifieu, que lo hace el settei setWinuowNouifieu. Poi tanto vamos a cieai un slot que ejecute uicho cambio al que llamaiemos uocumentWasNouifieu(). Asi los slots que vamos a ueclaiai finalmente son: private slots: void newFile(); void open(); bool save(); bool saveAs(); void about(); void documentWasModified();
Lo siguiente que vamos a ueclaiai son la funciones piivauas, que se encaigain ue llevai a cabo las taieas piincipales asignauas a los slots, y taieas secunuaiias piopias uel tipo ue aplicacion. Touas las taieas piivauas que vamos a uefinii, son piopias ue una aplicacion u0I geniica: private: void createActions(); void createMenus(); void createToolBars(); void createStatusBar();
vamos a veilas una poi una, ya que son funuamentales paia el uesaiiollo ue cualquiei aplicacion u0I, aunque pueuan sei ueclaiauas e implementauas a gusto uel piogiamauoi, peio es conveniente el estiuctuiai tus aplicaciones ue esta maneia paia hacei ms legible y mantenible tu couigo. 0$&#)&T0)/*%,.- Aqui ponuiemos el couigo que ciea touas las acciones ue touos los mens, tal cual vimos en el tema anteiioi con QAction, y las conectaiemos con los slots que ueclaiamos antes. Tambin pouemos usai esta seccion paia ueshabilitai las acciones que inicialmente lo ueban ue estai. 0$&#)&D&%+,.- Aqui es uonue vamos a ponei el couigo que ciea los mens, en nuestio caso Ficheio, Euitai y Ayuua, con sus sepaiauoies y touo. 0$&#)&I**5!#$,.- Aqui es uonue ponuiemos el couigo que ciea las baiias ue heiiamientas, en nuestio caso van a sei 2, una paia opciones ue Ficheio y la otia paia opciones ue Euitai. 0$&#)&()#)+,!#$.- Aqui es uonue ponuiemos el couigo paia cieai la baiia ue estauo, con touos sus elementos, y pouiemos mostiai un mensaje inicial si lo vemos opoituno. $(&))/%>,.- Aqui ponuiemos el couigo que se va a encaigai ue leei los settings como vimos en el tema anteiioi, y los va a aplicai. B$/)&(&))/%>,.- Aqui pouiemos el couigo que se va a encaigai ue guaiuai los settings antes ue salii ue la aplicacion. ,&)8+$$&%)./5&.- Es el settei ue la piopieuau CuiientFile que se encaigai ue llevai el nombie uel ficheio actual al que se hace alusion. Poui hacei una seiie ue acciones ielacionauas con el manejo ue ficheios y notificacion uel cambio en el conteniuo ue uicho ficheio. 5*#2./5&.- Este bloque se encaigai ue abiii el ficheio y leei su conteniuo caignuolo en QPlainTextEuit con setPlainText(). Auems hai touas las notificaciones que iequieia sobie la caiga uel ficheio, como establecei el nuevo CuiientFile o notificai su accion en el status bai. ,#K&./5&.- Este bloque se encaigai ue abiii el ficheio, esciibii su conteniuo y notificai igualmente sobie el mismo. 4#:9&(#K&.- Este bloque pueue estai integiauo en los 2 anteiioies, o pueue sei sepaiauo paia uejai ms claio el couigo. Su funcion seiia, si el uocumento ha siuo mouificauo, muestia una ventana ue uilogo waining, paia que el usuaiio ueciua si guaiua o no guaiua los cambios. Es muy tipico en las aplicaciones moueinas. ,)$/--&2<#4&.- Es una bloque simple que extiae el nombie uel ficheio, extiaynuolo uel path completo.
Las vaiiables piivauas que vamos a usai coiiesponuen con: la piopieuau cuiientFile uesciita antes, el wiuget cential que es un QPlainTextEuit, los S menus QNenu, las 2 baiias ue heiiamientas QToolBai y las acciones piopias a los mens QAction. Estas son las vaiiables que vamos a usai: QString curFile; QPlainTextEdit *textEdit;
QAction *exitAct; QAction *cutAct; QAction *copyAct; QAction *pasteAct; QAction *aboutAct; QAction *aboutQtAct; Paia finalizai la ueclaiacion ue la clase NainWinuow, vamos tambin a ieimplementai una funcion viitual ue QWiuget llamaua closeEvent(QCloseEvent) que nos peimitii inteiceptai el cieiie ue la aplicacion, paia notificai al usuaiio si el uocumento tiene cambios sin guaiuai, una caiacteiistica muy usual tambin en aplicaciones moueinas. La vamos a ueclaiai en la zona piotecteu paia que pueua sei ieimplementaua en hijos que pueuan ueiivaise ue la clase NainWinuow en futuias aplicaciones.
0PNB6P629?54C2 36 /?42D4238E
A continuacion vamos a vei la implementacion ue touos estos bloques y miembios que hemos visto anteiioimente.
Comenzamos con el constiuctoi que uefine el inteifaz inicial ue la aplicacion:
MainWindow::MainWindow() { textEdit = new QPlainTextEdit; setCentralWidget(textEdit);
Queuan muy claias touas las acciones que lleva a cabo: establecei al QPlainText como el wiuget cential, luego cieai las acciones paia los mens, luego cieai los menus, las baiias ue heiiamientas, la baiia ue estauo, leei los settings ue el ltimo cieiie, conectai la seal ue cambios en el uocumento con el slot que hemos cieauo paia ello, y establecei como ficheio actual (CuiientFile) a ninguno.
La funcion closeEvent(), es ejecutaua automticamente caua vez que un top-level wiuget es ceiiauo. Si el evento es aceptauo (accept()) entonces sale sin pioblemas, si es ignoiauo (ignoie()) entonces no es ceiiauo. Aqui sei maybeSave quien muestia la ventana ue eleccion al usuaiio, y uevolvei un bool ue acueiuo al boton pulsauo:
bool MainWindow::maybeSave() { if (textEdit->document()->isModified()) { QMessageBox::StandardButton ret; // es un int con un codigo ret = QMessageBox::warning(this, tr("Application"), tr("El documento ha sido modificado.\n" "_Quiere guardar los cambios?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); if (ret == QMessageBox::Save) &(
El iesto uel couigo pueue sei entenuiuo peifectamente con lo que hemos estuuiauo hasta ahoia. Solo haiemos la intiouuccion a un concepto nuevo que es la funcion Q0bject::ti(QStiing) que uevuelve la tiauuccion uel aigumento pasauo, y es usauo paia inteinacionalizai una aplicacion.
Ahoia llego el momento ue hacei la misma aplicacion peio usanuo el Qt Besignei paia uiseai el inteifaz gifico.
7A6?A B? ?NB45?54C2 RAYO45?P6296
Bacei uso ue Qt Besignei paia hacei una aplicacion, facilita mucho las cosas, no solo paia uibujai el inteifaz si esto es necesaiio, si no paia cieai los menus, las acciones uel mismo, y las conexiones con los slots. Pues bien vamos a abiii un nuevo pioyecto, y esta vez si vamos a cieai el ficheio *.ui , le ponuiemos ue nombie application2. Al abiii el ui veiemos que apaiece un foimulaiio como ste:
Asi que le aauimos un PlainTextEuit y ocupamos con l touo el iea que nos peimite, veiemos que en el inspectoi ue objetos ue la ueiecha supeiioi, lo ha puesto como centialWiuget.
vamos a ii iellenauo los mens hacienuo uoble clic sobie "Type Beie" y pulsamos sobie Auu Sepaiatoi paia aauii un sepaiauoi ue men, poi ejemplo antes uel Salii. Lo que tenuiemos al final es algo como esto:
'*
Asi iiemos iellenanuo los mens confoime hemos uesciito al piincipio ue este tema, opcion a opcion. veis que en la paite infeiioi, en el Action Euitoi, empieza a iellenaise el solo como esto:
Bacienuo uoble clic en caua accion, pouemos euitai sus paites ue la siguiente maneia:
Poi supuesto, se ha tenei ya cieauo y caigauo el qic tal como lo vimos en el ejemplo anteiioi, paia que apaiezcan los iconos. En el inspectoi ue piopieuaues ponemos el statusTip a mano. vamos a hacei lo mismo con touos los submens, y uejaiemos paia uespus la paite iefeiente a las conexiones.
Ahoia vamos a cieai los slots que van a iecibii las acciones, excepto los que ya vienen ue heiencia. Paia ello, hacemos clic ueiecho sobie accion_Nuevo, y elegimos "go to slot", y pulsamos sobie la seal tiiggeieu(), que es la que vamos a conectai. Inmeuiatamente nos lleva al couigo uel slot que se acaba ue cieai, *%U#0)/*%U<+&K*U)$/>>&$&267, que se ha cieauo automticamente. Touos los slots cieauos en el Qt Besignei, llevan esta foima, on_ActionName_SignalName(). Asi vamos a cieai slots tambin paia abiii, guaiuai, guaiuai como, aceica ue. El iesto ue acciones las vamos a llevai a slots pieuefiniuos en las clases coiiesponuientes ue Qt como hemos visto ya.
Los slots que se han cieauo automticamente ue esta maneia son: ')
y auems se ha estableciuo la conexion automticamente entie la seal tiiggeieu() ue uicha accion con uichos slots, poi lo que no hace falta estableceilas en el couigo fuente, ya estn en el *.ui.
Ahoia, nos vamos al Signal & Slots euitoi, uonue esta touo vacio. Pulsamos sobie el boton veiue +, y lo hacemos justo el nmeio ue veces que conexiones necesitamos paia las acciones ue los mens que van a slots pieuefiniuos en Qt (son 4). Ahoia vamos a ii iellenanuo touas las conexiones ue caua accion, con los slots que les coiiesponuen, con lo que una vez lleno queuaiia ue esta maneia:
Como pueues obseivai no hemos pouiuo ponei la conexion uel aboutQtAct uebiuo a que no apaiece el ieceivei qApp, poi lo que es paite tenuiemos que poneila en el constiuctoi ue NainWinuow a mano.
volvamos a activai el Action Euitoi, y ahoia hacemos clic ueiecho en la clase NainWinuow en el inspectoi ue objetos y elegimos "auu toolbai". Ya tenemos 2 toolbais, la piimeia la llamamos fileToolBai y la segunua euitToolBai, cambianuo su objectName en el inspectoi ue piopieuaues. Aiiastianuo los iconos uel Action euitoi ue Nuevo, Abieito y uuaiuai sobie la piimeia ToolBai, cieamos los S botones ue uicha baiia ue heiiamientas. Bacemos lo mismo con Coitai, Copiai y Pegai en la segunua baiia ue heiiamientas. El iesultauo final es algo asi:
Ya tenemos toua la paite gifica constiuiua, y ya solo nos queua ii iellenanuo el couigo coiiesponuiente ue la clase NainWinuow. Ahoia eligienuo las acciones ue Coitai y Pegai, vamos a uesactivailas poi uefecto en el panel ue piopieuaues, ueshabilitanuo el cuauio "enableu". veis que los iconos se vuelven ms apagauos. Y esto es touo lo que se pueue hacei con el Qt Besignei, el iesto hay que tecleailo a mano.
'!
Si ievisamos el couigo ue mainwinuow.h, veiemos que hay algo nuevo que hace iefeiencia al conteniuo que hay en el ficheio *.ui, y es el couigo: namespace Ui { class MainWindow; }
private: Ui::MainWindow *ui;
Lo que uesigna ese couigo es un punteio al inteiface que hay en ui, y poi lo tanto paia acceuei a los objetos uentio uel mismo, tenuiemos que haceilo uesue ese punteio, lo cual es tan sencillo como esto:
ui->actionGuardar->setEnabled(false);
que uesactivaiia uiiectamente la accion uuaiuai, y que si piuebas a esciibiilo en cualquiei paite ue la implementacion ue NainWinuow, veis que el autoiellenauo te va uanuo pistas ue touos los objetos y miembios accesibles uesue ui.
Bejamos poi tanto como ejeicicio ue iepaso paia el lectoi, la cumplimentacion uel couigo necesaiio paia que esta aplicacion funcione igual que su antecesoia hecha completamente en couigo. No obstante te obsequiamos con el couigo uel constiuctoi ue la clase NainWinuow paia que te siiva como oiientacion:
Resumiiemos poi tanto los 7 pasos a seguii paia cieai una aplicacion con ayuua uel Qt Besignei (foima visual):
1.- Situai el centeiWiuget uebajo uel toolbai y encima uel status bai. 2.- Esciibii touas las opciones uel men piincipal. S.- Euitai las acciones que se ciean con el men piincipal cumplimentauo paia aauiiles iconos, status tips, su estauo inicial, etc. 4.- Cieai las toolbai que se iequieian aiiastianuo los iconos ue las acciones sobie aquellas. S.- Cieai los slots que se iequieian ue las acciones con boton ueiecho-> go to slot, luego uailos ue alta en el Qt Besignei como miembios ue NainWinuow. 6.- Bacemos touas las conexiones entie las acciones y los slots en el signal-slot euitoi. 7.- Ya pouemos aauii el couigo que haga falta, con ayuua uel nuevo punteio *ui paia uesignai el uiseo.
'"
)%/" G; <".-\) " ]-&'-
En el tema 12 ya tocamos el tema uel layout como el meuio meuiante el cual, los wiugets negociaban el espacio ue la ventana que los contiene, cieanuo una inteiface flexible a mltiples ciicunstancias como cambio ue iuiomas sin tiuncauo ue palabias, o auaptacion uel u0I a otias platafoimas. En este capitulo vamos a aauii nuevas clases a este estuuio paia uisponei el espacio ue una ventana vienuo QSplittei, que ciea baiias que uiviuen una ventana en vaiios espacios, QSciollAiea, que peimite que una zona pueua veise en paite y el iesto pueua sei acceuiuo meuiante una baiia ue scioll, QWoikSpace o QNuiAiea que nos intiouucii en las aplicaciones NBI (multi-uocumento), uonue se pouin abiii ms ue un uocumento a la vez en la misma ventana. Como uijimos entonces, touo wiuget ocupa un espacio iectangulai, como una caja, y las cooiuenauas ue las vitices supeiioi izquieiuo e infeiioi ueiecho se guaiuan en la piopieuau "geometiy", que pueue sei acceuiua meuiante el gettei geometiy() como vimos en el ejemplo uel tema anteiioi paia los settings, y pueue sei cambiauo meuiante el settei setueometiy(). Sin embaigo, nauie usa estos mtouos paia posicionai ue maneia absoluta ningn wiuget uentio ue la ventana, si no que usa ue layouts paia ello.
(+9?5m63<?K8I9 Esta clase ciea un conjunto ue wiugets hijos que piesentan pginas apilauas, y solo pueue mostiai una a la vez, ocultanuo el iesto al usuaiio. QStackeuWiuget, es una wiuget que piovee Qt, y que lleva uentio un QStackeuLayout. No se piovee ue ningn contiol paia que el usuaiio pueua navegai poi las pginas, asi que esto solo pueue hacei meuiante el uso ue couigo. Las pginas estn numeiauas uel u en auelante, y pouemos hacei una visible meuiante el settei setCuiientInuex(page). Paia aveiiguai el inuex ue un wiuget conteniuo en este Layout se usa la funcion inuex0f(QWiuget), que uevuelve su enteio. Bien, una ue tantas foimas ue hacei funcionai este Layout, es vinculai las opciones ue un wiuget con las uifeientes pginas uel stackeu layout. Esto se pueue hacei con un ComboBox, o una QListWiuget. vamos a vei un ejemplo: PreferenceDialog::PreferenceDialog(QWidget *parent) : QDialog(parent) { //appearancePage, webBrowserPage, mailAndNewsPage, advancedPage listWidget = new QListWidget; listWidget->addItem(tr("Apariencia")); listWidget->addItem(tr("Navegador")); listWidget->addItem(tr("Correo y foros")); listWidget->addItem(tr("Avanzado"));
stackedLayout = new QStackedLayout; stackedLayout->addWidget(appearancePage); stackedLayout->addWidget(webBrowserPage); stackedLayout->addWidget(mailAndNewsPage); stackedLayout->addWidget(advancedPage);
Aqui pieviamente, appeaiancePage, webBiowseiPage, mailAnuNewsPage y auvanceuPage, son wiugets, poi ejemplo layouts con toua una seiie ue wiugets uentio, que confoiman una ventana ue uilogo completa. Son aauiuos como wiugets a su vez uel stackeu layout, y lo que hacemos es vinculai una listWiuget con l meuiante la seal cuiientRowChangeu(int) que vimos en el tema '#
17, con el settei y auems slot setCuiientInuex(int), ya que ambos pasan un inuice igual (uesue u a N). Be esta maneia pouemos uisponei espacialmente a ambos wiugets contenenuoies, uentio ue una ventana ue uilogo ue seleccion ue piefeiencias. Fijate en el uetalle, ue que fijamos la posicion inicial uel ambos con setCuiientRow(u). Como se haiia esto mismo en el Qt Besignei.. Pues siguienuo estos sencillos pasos: 1.- Cieai un foimulaiio nuevo basauo en QBialog o en QWiuget. 2.- Aauii un QListWiuget y un QStackeuWiuget al mismo. S.- Rellenai caua pgina con wiugets y layouts confoime sea necesaiio. (hacienuo clic ueiecho sobie el layout, y escogienuo "Inseit Page" paia aauii nuevas pginas, y paia navegai poi ellas, usanuo las flechitas en la zona supeiioi ueiecha). 4.- Conectai ambos wiugets, pulsanuo en el boton "Euit signal" ue aiiiba uel Besignei, y pulsamos sobie el ListWiuget y aiiastiamos hacia el StackeuWiuget, ue maneia que una flecha los conectai. Al soltai el iaton apaiecei la ventana paia elegii la seal y el slot que estain conectauos.
S.- Aauimos los items ue las opciones en el ListWiuget con clic ueiecho->euit items. Luego ponemos la piopieuau cuiientRow uel listWiuget a u. Asi ue fcil seiia uiseailo, luego habiia que aauii los botones ue la ventana ue uilogo tipicos, 0K y Cancel (QButtonBox), y ue igual maneia conectailos con la ventana ue uilogo, y conectai las seales, accepteu() ue paite ue los botones, con accept() uel uilogo, y iejecteu() ue paite ue '$
los botones, con ieject() uel uilogo. Ya pouiiamos usai este uilogo en la aplicacion completa, usanuo uialog.exec() paia ejecutailo en mouo moual y que nos uevuelva un valoi con nuestia seleccion, QBialog::Accepteu o QBialog::Rejecteu.
(+NB4996A Es un wiuget que contiene otios wiugets, y estos estn sepaiauos poi sepaiauoies. Los usuaiios pueuen cambiai el tamao ue los wiugets sepaiauos, uesplazanuo los sepaiauoies. Los wiugets sepaiauos, se van ponienuo uno al lauo uel otio confoime se van cieanuo y segn la uisposicion. int main(int argc, char *argv[]) { QApplication app(argc, argv);
QTextEdit *editor1 = new QTextEdit; QTextEdit *editor2 = new QTextEdit; QTextEdit *editor3 = new QTextEdit;
Los splitteis pueuen aniuaise hoiizontales con veiticales y cieai uisposiciones ms complejas. Los setting pueuen guaiuai la posicion ue los mismos, usanuo giupos en la giabacion ue los mismos. void MailClient::writeSettings() { QSettings settings("Software Inc.", "Mail Client");
Como uiseai con splitteis en el Qt Besignei.. Es similai a como uisponiamos los wiugets con layouts veiticales y hoiizontales. Pones 2 o ms wiugets juntos, los seleccionas, y en la baiia ue heiiamientas supeiioi pouemos elegii, "Layout Boiizontally in Splittei" o "Layout veitically in Splittei".
(+5A8BB"A6? Piovee una zona visible (viewpoit) y 2 baiias ue scioll (veitical y hoiizontal). Paia aauii baiias ue sciolling a un wiuget, solo hay que cieai un objeto QSciollAiea y aauiile uicho '%
objeto con setWiuget(QWiuget *). Pouemos acceuei al wiuget y sus miembios meuiante QSciollAiea ::viewpoit() que uevuelve un punteio uel mismo. int main(int argc, char *argv[]) { QApplication app(argc, argv);
IconEditor *iconEditor = new IconEditor; iconEditor->setIconImage(QImage(":/images/mouse.png"));
QTextEuit y QAbstiactItemview (y ueiivauos), al estai ueiivauos ue QAbstiactSciollAiea, no iequieien esto paia poseei baiias ue uesplazamiento.
('85mD43R69 K (/?42D4238E 0n uock wiuget es un wiuget que pueue apaicaise en un lauo ue una NainWinuow, o pueue queuaise flotanuo como una ventana apaite. Las iea ue enganche ue las uock winuows, en NainWinuow son, una aiiiba, otia abajo, y una a caua lauo uel cential Wiuget. Estas ventanas tiene su piopio titulo incluso enganchauas a la piincipal, y el usuaiio pueue moveilas solo cogienuo uel titulo y aiiastianuo ue ellas. Pueuen sei ceiiauas como una ventana noimal. Con la funcion setWiuget(QWiuget), se aaue un wiuget a un uock winuow. QNainWinuow, tiene una funcion paia aauii uocks wiugets, que se llama auuBockWiuget(zona, wiuget). QDockWidget *shapesDockWidget = new QDockWidget(tr("Shapes")); shapesDockWidget->setWidget(treeWidget); shapesDockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); addDockWidget(Qt::RightDockWidgetArea, shapesDockWidget);
/'0 Toua aplicacion que uentio ue su ventana cential pueua abiii vaiios uocumentos a la vez, es llamaua una aplicacion NBI. Se hace hacienuo que la clase QWoikspace sea el centialWiuget, y entonces caua uocumento que se abia, que sea hijo ue QWoikspace. Suele sei muy tipico que una aplicacion NBI, piovea ue un menu Winuow, que peimite manejai los uistintos uocumentos, y activailos o uesactivailos, y esa opcion suele sei checkable inuicanuo en caua momento la ventana uel uocumento que est activa. MainWindow::MainWindow() { workspace = new QWorkspace; setCentralWidget(workspace); connect(workspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(updateMenus()));
Este es un constiuctoi tipico ue una aplicacion NBI. Conectamos la seal winuowActivateu() con un slot nuestio que piogiamaiemos que actulizai el conteniuo ue los mens (poi ejemplo, hacienuo toggle en el men Winuow). Caua vez que se pulsa en el men Ficheio->Nuevo, no se boiiai el uocumento actual, si no que se cieai uno nuevo uevolvienuo un punteio al mismo. El constiuctoi ue los wiugets uocumentos que se abien, uebe ue activai el atiibuto ue boiiauo al ceiiai, paia evitai los memoiy leaks. setAttribute(Qt::WA_DeleteOnClose);
Paia pouei manejai caua uocumento, es necesaiio pouei iecupeiai un punteio al mismo, lo cual seiia imposible sin el uso ue un casting uinmico. Editor *MainWindow::activeEditor() { return qobject_cast<Editor *>(workspace->activeWindow()); } Aqui, la funcion activeEuitoi ue NainWinuow, pueue iecupeiai el punteio a uicho uocumento (en este caso es un Euitoi), hacienuo un casting al valoi uevuelto poi QWoikspace::activeWinuow(), que es un QWiuget *. Si no hay activa ninguna ventana entonces uevolvei un N0LL pointei, poi lo que es impoitante que cuanuo se llame a este mtouo uesue cualquiei paite, se obseive si uevuelve un valoi nulo. En este tema vamos a hacei que nuestia aplicacion euitoia ue texto uel tema 2u, pueua sei NBI, peio lo haiemos usanuo QNuiAiea y QNuiSubWinuow, como nuevo enfoque a las aplicaciones NBI.
''
'(
)%/" GG >"+%+ '% '")-+
La gian mayoiia ue aplicaciones ue gestion, suelen guaiuai toua la ingente cantiuau ue uatos que maneja en un motoi ue base ue uatos. Qt en su veision piivativa incluye los uiiveis ue la mayoiia ue motoies ue uatos. Qt en su veision 0pen Souice, no incluye aquellos que tienen licencia. Paia aquellos usuaiios acostumbiauos a usai la sintaxis SQL, Qt piovee ue la clase QSqlQueiy. Paia usuaiios que piefieien evitai esto, y uesean tiabajai a un nivel ms alto, hay 2 mouelos incluiuos en las clases QSqlTableNouel y QSqlRelationalTableNouel, las cuales ya mencionamos en el tema 16.
782659?A 6 4296AA8R?A 582 +(< vamos a empezai tiatanuo la piimeia foima ue tiabajai con bases ue uatos, uonue conectaiemos con una base ue uatos NySQL, y la inteiiogaiemos meuiante la sintaxis SQL. bool createConnection() { QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL"); db.setHostName("localhost"); db.setDatabaseName("megafonia"); db.setUserName("root"); db.setPassword("admin"); if (!db.open()) { QMessageBox::critical(0, QObject::tr("Database Error"),db.lastError().text()); return false; } return true; }
Esta es una conexion a la base ue uatos NySQL, en el host local, con nombie megafonia, con el usuaiio y passwoiu uel usuaiio que tenga acceso a la misma, ue acueiuo a las queiies SQL que vamos a enviaile. Lo siguiente sei enviaile una queiy, y esto se hace asi: QSqlQuery query; query.exec("SELECT almacen, ntiendas FROM almacenes"); while (query.next()) { QString almacen = query.value(0).toString(); int ntiendas = query.value(1).toInt(); qDebug("Nombre: %s - Tiendas: %d",qPrintable(almacen),ntiendas); }
Como pueues vei la funcion exec() ejecuta el queiy, next() iecoiie el punteio poi la tabla iespuesta, y value es una lista Qvaiiant, uonue los campos tienen inuices uel u en auelante, ue esta foima value(u) contenuiia el campo almacen que es el piimeio en la iespuesta, y en value(1) estaiia el campo ntienuas. Paia que este couigo compile bien, es necesaiio que se aaua el mouulo sql al pioyecto, es uecii al ficheio *.pio con la linea: QT += sql
(*
/n7 ?NB45?38 ? >?:6: 36 '?98: Como ya vimos en el tema 16, pouemos combinai una vista y un mouelo que acceua a la base ue uatos como su fuente. Aqui la vista ms tipica paia vei una tabla ue uatos es QTableview, y el mouelo pueue sei QSqlTableNouel, si vamos a vei una tabla en concieto, sin ms. Las funciones ms tipicas ue este mouelo, son: setTable(QStiing tableName) -> que fija la tabla ue la base ue uatos a fijai setEuitStiategy(stiategy) -> Besciibe la estiategia a usai paia actualizai los uatos ue la base ue uatos, que pueue sei: 0nFieluChange (touo cambio en la vista es inmeuiato en la base ue uatos), 0nRowChange(se guaiuan los uatos al cambiai ue fila o iegistio), 0nNanualSubmit (se guaiua en una cache hasta que el piogiama ejecuta un submitAll() o un ieveitAll() ). select() -> Rellena el mouelo con los uatos ue la tabla. setBeaueiBata(int section, Qt::oiientation, Qvaiiant heauei) -> Naica los nombies ue las cabeceias. cleai() -> boiia el mouelo ue touos los uatos que pieviamente tuvieia caigauos en su cach (buffei). Paia los siguientes ejemplos vamos a usai una base ue uatos giabaua en SQLite en un ficheio que llamaiemos uatabase.ub, en los ejeicicios veiemos como es esta base ue uatos. #include <QtGui> #include <QtSql>
static bool createConnection() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("database.db"); if (!db.open()) { QMessageBox::critical(0, "No se puede abrir la base de datos", "Imposible establecer una conexi_n con la base de datos.\n" "Pulsar Cancel para salir.", QMessageBox::Cancel); return false; } return true; }
Peio lo ms noimal es que tengamos vaiias tablas, ielacionauas entie ellas meuiante un iuentificauoi numiico (en SQLite meuiante el iowiu), y lo que queiemos es piesentai una tabla uonue apaiece la ielacion entie ellas. Paia ello usaiemos el mouelo QSqlRelationalTableNouel. veamos un ejemplo similai con la misma base ue uatos y las S tablas. #include <QtGui> #include <QtSql>
static bool createConnection() { QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName("database.db"); if (!db.open()) { QMessageBox::critical(0, "No se puede abrir la base de datos", "Imposible establecer una conexi_n con la base de datos.\n" "Pulsar Cancel para salir.", QMessageBox::Cancel); return false; } return true; }
void createRelationalTables() { QSqlQuery query; query.exec("create table employee(id int primary key, name varchar(20), city int, country int)"); query.exec("insert into employee values(1, 'Espen', 5000, 47)"); query.exec("insert into employee values(2, 'Harald', 80000, 49)"); query.exec("insert into employee values(3, 'Sam', 100, 1)"); query.exec("create table city(id int, name varchar(20))"); query.exec("insert into city values(100, 'San Jose')"); query.exec("insert into city values(5000, 'Oslo')"); query.exec("insert into city values(80000, 'Munich')"); query.exec("create table country(id int, name varchar(20))"); query.exec("insert into country values(1, 'USA')"); query.exec("insert into country values(47, 'Norway')"); query.exec("insert into country values(49, 'Germany')"); }
7B46296 )7# W()5N+85m69X Explicai los piotocolos TCPIP no es el objetivo ue este libio, poi lo que se ua poi supuesto el pievio conocimiento y uifeienciacion entie piotocolos TCP y 0BP. Asi que comenzaiemos con la implementacion ue un cliente TCP. Se tiata ue un seiviuoi que una siive poi un pueito TCP, fiases ue la foituna, como las ue los iollitos ue piimaveia. Asi que cuanuo el cliente se conecta, el seiviuoi le siive una fiase al azai sobie su foituna. vamos a usai QBataStieam paia enviai los uatos uesue el seiviuoi, y tambin paia iecogeilas en el cliente. El flujo ue uatos es muy sencillo, tan solo lleva como cabeceia un quint16 con la longituu uel mensaje que le sigue, luego viene una cauena con la fiase. Bien, en piogiamacion ue sockets hay 2 apioximaciones uistintas en cuanto a si la conexion es bloqueante o no-bloqueante. 0na conexion bloqueante, es aquella que espeia y no hace naua hasta que el seiviuoi ha iesponuiuo y ha siuo estableciua poi completo. Suele usaise en aplicaciones multi-hilo o ue consola uonue se hai uso ue funciones como QTcpSocket::waitFoiConnecteu. En nuestio caso, vamos a usai la apioximacion no-bloqueante, uonue llamaiemos a la funcion connectToBost(), y seguiiemos a lo nuestio, y meuiante una conexion ue Qt, una vez el socket se establezca QTcpSocket emitii la seal connecteu(). vamos a ueiivai la clase Cliente ue QBialog, y le vamos a aauii los slots necesaiios y las piopieuaues piivauas necesaiias. class Client : public QDialog { Q_OBJECT
Apaite ue los componentes visuales, vamos a usai la cauena cuiientFoitune paia guaiuai la fiase actual, y su tamao en blockSize. Los slots que vamos a usai son: iequestNewFoitune -> que va a sei ejecutauo cuanuo se haga clic en el boton ue "vei mi foituna". (#
ieauFoitune -> que sei uispaiauo cuanuo el socket TCP meuiante el QBataStieam, envie la seal QI0Bevice::ieauyReau(), uicienuo que nuevos uatos estn uisponibles en el uispositivo ue entiauasaliua. uisplayEiioi -> va a estai conectauo con la seal eiioi() que se uispaia si hay eiioi en la conexion. enableuetFoituneButton -> este es un meio slot ue u0I paia que se habilite un boton. vamos ahoia a poi la implementacion uel constiuctoi que es uonue se inicia el socket: CllenL::CllenL(CWldgeL *parenL) : Culalog(parenL) [ hosLLabel = new CLabel("&l Servldor:"), porLLabel = new CLabel("&uerLo:"), // 8usca Lodas las dlrecclones del hosL acLual CSLrlng lpAddress, CLlsL<CPosLAddress> lpAddressesLlsL = CneLworklnLerface::allAddresses(), // va a usar la prlmera l no localhosL (127.0.0.1) Llpo lv4 for (lnL l = 0, l < lpAddressesLlsL.slze(), ++l) [ lf (lpAddressesLlsL.aL(l) != CPosLAddress::LocalPosL && lpAddressesLlsL.aL(l).Lolv4Address()) [ lpAddress = lpAddressesLlsL.aL(l).LoSLrlng(), break, } } // sl no encuenLra nlnguna usar la localhosL (127.0.0.1) lf (lpAddress.lsLmpLy()) lpAddress = CPosLAddress(CPosLAddress::LocalPosL).LoSLrlng(), hosLLlneLdlL = new CLlneLdlL(lpAddress), porLLlneLdlL = new CLlneLdlL, porLLlneLdlL->seLvalldaLor(new ClnLvalldaLor(1, 63333, Lhls)), hosLLabel->seL8uddy(hosLLlneLdlL), porLLabel->seL8uddy(porLLlneLdlL), sLaLusLabel = new CLabel(("LsLe e[emplo requlere que usLed e[ecuLe el lorLune server")), geLlorLune8uLLon = new Cush8uLLon("ver ml lorLuna"), geLlorLune8uLLon->seLuefaulL(Lrue), geLlorLune8uLLon->seLLnabled(false), qulL8uLLon = new Cush8uLLon("Sallr"), buLLon8ox = new Culalog8uLLon8ox, buLLon8ox->add8uLLon(geLlorLune8uLLon, Culalog8uLLon8ox::AcLlon8ole), buLLon8ox->add8uLLon(qulL8uLLon, Culalog8uLLon8ox::8e[ecL8ole), LcpSockeL = new C1cpSockeL(Lhls),
CCrldLayouL *malnLayouL = new CCrldLayouL, malnLayouL->addWldgeL(hosLLabel, 0, 0), malnLayouL->addWldgeL(hosLLlneLdlL, 0, 1), malnLayouL->addWldgeL(porLLabel, 1, 0), malnLayouL->addWldgeL(porLLlneLdlL, 1, 1), malnLayouL->addWldgeL(sLaLusLabel, 2, 0, 1, 2), malnLayouL->addWldgeL(buLLon8ox, 3, 0, 1, 2), seLLayouL(malnLayouL), seLWlndow1lLle("CllenLe 1C")), porLLlneLdlL->seLlocus(), } Aqui a paite ue los wiugets visuales, inicializamos la IP uel oiuenauoi uonue estamos en la LineEuit, tambin le aauimos un valiuauoi al LineEuit uel pueito paia que no aumita pueitos fueia uel iango ue 1-6SSSS. Se inicializa el socket y se hacen las conexiones Qt entie slots y seales comentauas antes. ($
Cuanuo se pulsa el boton ue vei Ni Foituna, se uispaia el slot coiiesponuiente que establece la conexion con el seiviuoi ue esta maneia: void Client::requestNewFortune() { getFortuneButton->setEnabled(false); blockSize = 0; tcpSocket->abort(); tcpSocket->connectToHost(hostLineEdit->text(),portLineEdit->text().toInt()); } Inicializamos la piopieuau blockSize con el tamao a u, luego aboita la conexion actual si la hay, ieseteanuo el socket, luego conecta con el host uanuo su uiieccion IP y pueito. Cuanuo el socket ya haya siuo conectauo coiiectamente, y haya uatos nuevos en el uispositivo, entonces se lanzai el slot coiiesponuiente: void Client::readFortune() { QDataStream in(tcpSocket); in.setVersion(QDataStream::Qt_4_6);
if (blockSize == 0) { if (tcpSocket->bytesAvailable() < (int)sizeof(quint16)) return; in >> blockSize; }
if (tcpSocket->bytesAvailable() < blockSize) return;
QString nextFortune; in >> nextFortune;
if (nextFortune == currentFortune) { QTimer::singleShot(0, this, SLOT(requestNewFortune())); return; }
currentFortune = nextFortune; statusLabel->setText(currentFortune); getFortuneButton->setEnabled(true); } Los uatos, no tienen poi qu venii touos ue golpe, y poi tanto iequieia ue vaiias ejecuciones ue este slot, paia teneilos touos. Poi ello, si es la piimeia lectuia (blockSize == u), y si los bytes que estn piepaiauos paia sei leiuos son menos que 2 bytes, el tamao uel heauei que inuica el tamao ue la fiase, entonces salimos uel slot y espeiamos a que nos llamen con ms uatos. Si hay ms uatos, pues leemos piimeio el blockSize. Luego igualmente salimos uel slot, mientias no estn touos los uatos uisponibles. Finalmente leemos el mensaje que iecogemos en una cauena QStiing. Si el mensaje es el mismo que el anteiioi que nos uio el seiviuoi, entonces usamos un Timei ue nico uispaio, paia que uispaie ue nuevo el slot iequestNewFoitune que ya uesciibimos antes, piuienuo un mensaje nuevo. Finalmente vamos a vei el couigo que va a tiatai los uifeientes eiioies ue conexion: void Client::displayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, "Cliente TCP","No se encontr el servidor."); break; case QAbstractSocket::ConnectionRefusedError: QMessageBox::information(this,"Cliente TCP","Conexin rechazada por el cliente. Servidor apagado."); break; default: QMessageBox::information(this, "Cliente TCP", QString("Error: %1.") .arg(tcpSocket->errorString())); } getFortuneButton->setEnabled(true); } (%
No hay comentaiios que aauii a esto.
+6AV438A )7# W()5N+85m69X El seiviuoi, es tambin ueiivauo ue QBialog. Su nico slot es senuFoitune, que est conectauo a la seal newConnection(). class Server : public QDialog { Q_OBJECT
La implementacion uel constiuctoi es muy simple: Server::Server(QWidget *parent) : QDialog(parent) { statusLabel = new QLabel; quitButton = new QPushButton("Salir"); quitButton->setAutoDefault(false); tcpServer = new QTcpServer(this); if (!tcpServer->listen()) { QMessageBox::critical(this, "Servidor TCP", QString("Imposible iniciar servidor: %1.") .arg(tcpServer->errorString())); close(); return; } QString ipAddress; QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses(); for (int i = 0; i < ipAddressesList.size(); ++i) { if (ipAddressesList.at(i) != QHostAddress::LocalHost && ipAddressesList.at(i).toIPv4Address()) { ipAddress = ipAddressesList.at(i).toString(); break; } } if (ipAddress.isEmpty()) ipAddress = QHostAddress(QHostAddress::LocalHost).toString(); statusLabel->setText(tr("Servidor corriendo en \n\nIP: %1\npuerto: %2\n\n" "Ejecute el cliente TCP ahora.") .arg(ipAddress).arg(tcpServer->serverPort())); fortunes << tr("Has llevado una vida de perros. Bajate del sofa.") << tr("Tienes que pensar en el ma_ana.") << tr("Te ha sorprendido una sonido fuerte.") << tr("Tendr_s hambre dentro de una hora.") << tr("Tienes nuevo correo."); connect(quitButton, SIGNAL(clicked()), this, SLOT(close())); connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendFortune())); QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addStretch(1); buttonLayout->addWidget(quitButton); buttonLayout->addStretch(1); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(statusLabel); mainLayout->addLayout(buttonLayout); setLayout(mainLayout); setWindowTitle("Servidor TCP"); }
(&
Apaite ue inicializai la u0I y ue buscai la IP local como el cliente, solamente inicia la escucha ue clientes con listen() y conecta la seal newConnection() con el slot que va a enviai las fiases: void Server::sendFortune() { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_6);
out << (quint16)0; out << fortunes.at(qrand() % fortunes.size()); out.device()->seek(0); out << (quint16)(block.size() - sizeof(quint16));
clientConnection->write(block); clientConnection->disconnectFromHost(); } 0na vez iniciauo el BataStieam como un ByteAiiay, piimeio ponemos en el buffei uel mismo la cabeceia a u, luego meuiante una funcion ianuom, se elije una fiase al azai, y se envia al buffei, luego iebobinamos a la posicion u "out.device()->seek(0) , le ponemos el tamao ue solo la fiase (poi eso iestamos al tamao uel bloque, el tamao ue la cabeceia - 2 bytes). Llamanuo a nextPenuingConnection(), se uevuelve el socket que ha siuo conectauo. Conectamos la seal ue uisconnecteu al slot Q0bject::ueleteLatei(), que hace que si hay uesconexion uel socket, el objeto que iepiesenta uicha conexion sea boiiauo poi Qt. Ya pouemos enviai el bloque completo, poi uicho socket conectauo, y una vez hecho, ya pouemos uesconectai al cliente, y se boiiai el objeto uel socket como acabamos ue vei.
%P4:8A \'# W(\3N+85m69X El emisoi ue uatagiamas 0BP va a usai un QTimei paia caua segunuo enviai paquetes poi un pueito. veamos la implementacion completa: Sender::Sender(QWidget *parent) : QDialog(parent) { statusLabel = new QLabel("Preparado para enviar datagramas por el puerto 45454"); startButton = new QPushButton("Enviar"); quitButton = new QPushButton("Salir"); buttonBox = new QDialogButtonBox; buttonBox->addButton(startButton, QDialogButtonBox::ActionRole); buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
timer = new QTimer(this); udpSocket = new QUdpSocket(this); messageNo = 1;
Iniciamos el timei con stait(1uuu) una vez apietamos el boton ue Enviai, como tenemos conectaua la seal uel timei, timeout() con bioaucastBatagiam, sta se encaiga ue esciibii el uatagiama a enviai con wiiteBatagiam(uatos, tamao_uatos, IP_ieceptoi, pueito). Nuy sencillo como vemos.
$656N98A \'# W(\3N+85m69X El ieceptoi, meiamente vincula el pueito y la uiieccion IP uel inteifaz ue ieu poi uonue va a escuchai con binu(). Aqui ue nuevo conectamos QI0Bevice::ieauyReau(), que nos inuica que hay nuevos uatos espeianuo sei leiuos, con nuestio slot ue lectuia piocessPenuingBatagiams. Esto lo hace meuiante un bucle usanuo hasPenuingBatagiams() paia sabei si an queua algo poi piocesai. La funcion penuingBatagiamSize() nos uevuelve los bytes que queuan penuientes ue lectuia. Con ieauBatagiam(uatos, tamao) leemos los uatos que se ponuin en QByteAiiay::uata(). veamos la implementacion: Receiver::Receiver(QWidget *parent) : QDialog(parent) { statusLabel = new QLabel("Escuchando mensajes enviados"); quitButton = new QPushButton("Salir");
udpSocket = new QUdpSocket(this); udpSocket->bind(45454, QUdpSocket::ShareAddress);
Con la ayuua uel tema siguiente, que tiata ue la piogiamacion concuiiente o multi-hilo, vamos a implementai el ejemplo uel seiviuoi TCP, peio esta vez con mltiples hilos paia pouei manejai a muchos clientes a la vez.
((
)%/" G* #$-^$"/"70Q& 7-&7\$$%&)%
0na aplicacion noimalmente usa un solo hilo ue ejecucion, uonue lleva a cabo una sola taiea a la vez. Peio existe la posibiliuau ue que la taiea piincipal, geneie nuevos hilos ue ejecucion inuepenuientes, y que estos se comuniquen con la taiea piincipal, o que tiabajen juntos en una misma cosa, tenienuo que sincionizai su tiabajo. No es nuestia iuea, explicai el tiasfonuo ue la piogiamacion multi-hilo en este libio, ya que eso peitenece a un bagaje que se supone ya auquiiiuo, lo que si vamos es a explicai ue qu maneia Qt implementa las aplicaciones ms tipicas multi-hilo.
()TA6?3 Esta es la clase que piovee ue hilos ue maneia multiplatafoima. Caua objeto ue esta clase iepiesenta un hilo ue ejecucion uifeiente a los uems y uifeiente al piincipal que se inicia y se teimina con main(). 0n hilo compaite uatos con otios hilos, peio se ejecuta ue maneia inuepenuiente ue los uems. En vez ue comenzai en main() como el hilo piincipal, los hilos QThieaus comienzan y teiminan en su funcion iun(). Asi que iun() ejecutaiia un hilo e iniciaiia su piopio bucle ue eventos con exec(), como hace main(). Paia cieai tus piopios hilos, solo hay que ueiivai una clase ue QThieau y ieimplementai la funcion iun(), con las taieas que este hilo vaya a ejecutai. class MyThread : public QThread { public: void run(); };
void MyThread::run() { QTcpSocket socket; // conecta las seales de QTcpSocket ... socket.connectToHost(hostName, portNumber); exec(); }
Esto seiia un hilo que conecta un socket con un host y luego inicia su piopio bucle ue eventos. Paia comenzai la ejecucion ue un hilo, una vez se ha instanciauo en el hilo piincipal, es usanuo la funcion stait(). Recueiua instanciai caua hilo, ponienuo como aigumento pauie al hilo uel que nace, ue esa maneia, cuanuo el pauie finalice, touos los hilos cieauos ue l se boiiain tambin, evitanuo memoiy leaks. La ejecucion ue un hilo acaba cuanuo se sale ue iun(), igual que un piogiama cuanuo teimina main(). QThieau notifica con seales cuanuo un hilo, comienza (staiteu()) o finaliza (finisheu()). Tambin se pueuen usai los getteis isFinisheu() o isRunning() paia sabei si ha finalizauo o an esta coiiienuo. No se pueuen usai wiugets en un hilo. Si se pueuen usai QTimeis y sockets, y se pueuen conectai seales y slots entie uifeientes hilos. Paia vei un uso ieal ue esta concuiiencia ue hilos, vamos a vei como queuaiia el couigo uel seiviuoi TCP uel tema anteiioi, ue maneia que pueua aumitii mltiples conexiones ue clientes, caua una en un hilo inuepenuiente. )**
Como los wiugets, hemos uicho que no pueuen coiiei en un hilo, han ue coiiei en la taiea piincipal que inicia main(), ha ue sepaiaise el couigo que geneia toua la inteifaz gifica y que inicia la escucha con listen(). FortuneThread::FortuneThread(int socketDescriptor, const QString &fortune, QObject *parent) : QThread(parent), socketDescriptor(socketDescriptor), text(fortune) { }
QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_0); out << (quint16)0; out << text; out.device()->seek(0); out << (quint16)(block.size() - sizeof(quint16));
tcpSocket.write(block); tcpSocket.disconnectFromHost(); tcpSocket.waitForDisconnected(); } Ahoia, hemos cieauo una clase hilo uel seiviuoi que envia las fiases y en iun() es uonue se encaiga ue hacei touo lo que hace, uesue que es uespeitauo paia conectaise con el cliente, hasta que envia la fiase, se uesconecta y espeia la uesconexion (mouo bloqueo). Cieamos un QTcpSocket y lo asociamos al uesciiptoi ue socket que nos va a pasai el seiviuoi (socketBesciiptoi), que iuentifica a cual ue los clientes nos vamos a conectai. Bien, esto es lo que hace el hilo que uespacha a un cliente. FortuneServer::FortuneServer(QObject *parent) : QTcpServer(parent) { fortunes << tr("Has llevado una vida de perros. Bajate del sofa.") << tr("Tienes que pensar en el ma_ana.") << tr("Te ha sorprendido una sonido fuerte.") << tr("Tendr_s hambre dentro de una hora.") << tr("Tienes nuevo correo."); }
Y aqui est la paite piincipal uel seiviuoi, y esta vez se ueiiva ue QTcpSeivei, asi el couigo que ponuiiamos en el hilo piincipal, cieaiia un seiviuoi FoituneSeivei al que ponemos a escuchai con listen(), cuanuo un cliente conectaia su socket con l, automticamente se enviaiia la ejecucion a incommingConnection, que pasa como paimetio el enteio que iepiesenta el uesciiptoi uel socket conectauo. Y en esta funcion cieamos un hilo ue ejecucion paia uespachai al cliente, como hemos visto aiiiba, que pasaiia el uesciiptoi uel socket TCP paia que no se confunua ue cliente, y la fiase a enviaile. Tambin conectamos la seal finisheu() ue uicho hilo con su boiiauo, paia que cuanuo acabe su ejecucion sea boiiauo, y finalmente iniciamos uicho hilo con stait().
)*)
+425A824q?54C2 36 T4B8: Ya hemos visto el ejemplo ms sencillo ue hilos, uonue un piogiama piincipal, geneia hilos que hacen cosas uifeientes, y uonue no hay inteiaccion entie los hilos. Peio, hay casos uonue vaiios hilos pueuen compaitii uatos o couigo ue maneia que pueua esto afectai al iesultauo. vamos a ponei 2 supuestos iesueltos ue maneia uifeiente. Supongamos que el couigo ue vaiios hilos acceue a la vez al couigo que aumenta un contauoi comn. Pouiia ocuiiii que un hilo acceua al valoi antes ue inciementailo, mientias otio hilo ya lo esta inciementanuo, ue maneia que ambos uejaiian el mismo iesultauo en el contauoi, cuanuo uebieian contaise el paso ue los 2 hilos ue maneia inuepenuiente. La nica foima ue iesolvei esto, es usai un Nutex, es uecii una zona bloqueaua, a uonue solo un hilo pueue entiai a la vez, ue esta maneia el hilo que entia, bloquea esa zona, solo l iecoge el valoi uel contauoi ahoia, y lo aumenta, luego sale ue la zona, peimitienuo que otio hilo entie, y asi, se evitaiia el pioblema inicial. En Qt esto es hecho con la clase QNutex, que se ueclaiaiia como piivaua uentio uel QThieau, y llamanuo a la funcion lock() se piouuce el bloqueo, y llamanuo a la funcion unlock() el uesbloqueo ue la zona. void Thread::run() { mutex.lock(); counter++; mutex.unlock(); }
Paia ms comouiuau se cieo QNutexLockei(QNutex *) que el objeto que ciea, al nacei bloquea el mutex, y al boiiaise, uesbloquea el mutex. Be esta maneia el mismo couigo queuaiia asi ue simple: void Thread::run() { QMutexLocker locker(&mutex); counter++; }
El segunuo supuesto, se tiata uel tipico pioblema uel piouuctoi-consumiuoi, uonue 2 hilos compaiten un mismo buffei ue memoiia, uonue un esciibe y el otio lee ue la siguiente maneia. El hilo piouuctoi, esciibe en uicho buffei hasta que llega a su final, y una vez alli vuelve ue nuevo al piincipio paia seguii esciibienuo. El hilo consumiuoi, lee lo que el otio esciibe confoime es piouuciuo y lo saca poi la saliua estnuai ue eiioi (ceii). Si usiamos solamente un mutex paia bloqueai el acceso simultneo al buffei, bajaiia la piouuctiviuau uel mismo, ya que no peimitiiiamos acceuei al buffei a uno ue los hilos, mientias el otio, est tiabajanuo en l, cuanuo iealmente no habiia pioblema alguno, si caua uno tiabajaia en zonas uifeientes en touo momento. Paia iesolveilo vamos a usai 2 QWaitConuition y 1 QNutex. veamos antes qu es QWaitConuition. QWaitConuition, piovee una vaiiable conuicion paia sincionizai hilos. Los hilos se queuan en espeia cuanuo llegan a la funcion wait(&mutex). Wait lo que hace es que un mutex pieviamente bloqueauo, es uesbloqueauo y el hilo, se queua en espeia, hasta que otio hilo lo uespieite, cuanuo es uespeitauo, el mutex vuelve a bloqueaise y el hilo sigue la ejecucion uespus ue wait(). Paia uespeitai a los hilos que espeian, un hilo exteino (poi ejemplo, el piincipal), lo hace usanuo wakeAll() paia uespeitailos a touos o wake0ne() paia uespeitai solo a uno ue ellos, el oiuen en que esto ocuiie es aleatoiio y no se pueue contiolai. )*!
vamos entonces ahoia a iesolvei el pioblema uel piouuctoi y consumiuoi, paia ello vamos a uefinii las siguientes vaiiables globales que van a compaitii touos los hilos, incluiuo el piincipal: const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize];
QWaitCondition bufferNotEmpty; QWaitCondition bufferNotFull; QMutex mutex; int numUsedBytes = 0;
Batasize en la cantiuau ue bytes que va a esciibii el consumiuoi en buffei. El tamao uel buffei es infeiioi a esa cantiuau, poi lo que el consumiuoi tenui que uai vaiias vueltas, lo que hace con un couigo como ste: buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; Lo que esciibe son aleatoiiamente las letias ACuT (bases uel couigo gentico). Be esta maneia no se sale uel buffei y lo esciibe ciclicamente. La conuicion ue espeia buffeiNotEmpty, sei sealaua poi el piouuctoi cuanuo haya esciito algn uato, uespeitanuo al consumiuoi paia que lo lea. La conuicion ue espeia buffeiNotFull, la sealai el consumiuoi cuanuo haya leiuo algn uato, uespeitanuo al consumiuoi paia que siga esciibienuo. num0seuBytes, va a sei el nmeio ue bytes en el buffei que contiene uatos esciitos poi el piouuctoi, y que no han siuo leiuos poi el consumiuoi. El mutex, se encaigai ue bloqueai el acceso a la vaiiable comn num0seuBytes, paia que sea leiua y cambiaua poi un solo hilo en caua momento. num0seuBytes no poui exceuei el tamao uel buffei nunca, o el consumiuoi estai sobiesciibienuo uatos an no leiuos poi el consumiuoi. Poi lo tanto el couigo que gobieina el hilo piouuctoi es: class Producer : public QThread { public: void run(); }; void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == BufferSize) bufferNotFull.wait(&mutex); mutex.unlock();
mutex.lock(); ++numUsedBytes; bufferNotEmpty.wakeAll(); mutex.unlock(); } } Inicializa la semilla ianuom con el timei. Antes ue acceuei a num0seuBytes bloquea con el mutex su acceso, si se ha llenauo el buffei completo ue uatos, entonces se queua en espeia ue la conuicion buffeiNotFull y libeia el mutex. Si no ha llenauo el buffei, libeia el mutex, esciibe en la posicion siguiente y ue nuevo antes ue inciementai num0seuBytes (el contauoi comn uel buffei), bloque esta seccion, inciementa su valoi, y uespieita al hilo consumiuoi, luego libeia el mutex, y sigue el bucle a su iitmo.
)*"
El couigo uel hilo consumiuoi seiia complementaiio a ste: class Consumer : public QThread { public: void run(); };
void Consumer::run() { for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == 0) bufferNotEmpty.wait(&mutex); mutex.unlock();
El hilo consumiuoi tambin tiene su bucle paia leei touos los uatos que el consumiuoi va uejanuo en el buffei, y sacnuolos poi la saliua estnuai ue eiioi. Antes ue ievisai el valoi ue num0seuBytes, bloquea la seccion con un mutex, si no hay uatos que leei nuevos, entonces se queua espeianuo que se cumpla la conuicion ue espeia buffeiNotEmpty y libeia el mutex. Si no es asi, tambin libeia el mutex, lee el siguiente uato uel buffei, y luego bloquea ue nuevo con el mutex el cambio ue num0seuBytes, que es ueciementauo, inuicanuo que hay un uato menos poi leei, luego uespieita al hilo piouuctoi con su seal buffeiNotFull, y libeia el mutex. Y sigue en su bucle tambin a su iitmo. Be esta maneia, ambos hilos se autosincionizan, sin pisaise el uno al otio. Sin embaigo, existe una segunua foima ue hacei esto ue maneia tambin optima, usanuo semfoios. En Qt esto se hace con la clase QSemaphoie. Poi tanto veamos antes como funciona esta clase. QSemaphoie, piovee ue un contauoi geneial con semfoio. Nientias un mutex, solo pueue sei bloqueauo una vez, hasta que es uesbloqueauo, un semfoio pueue sei bloqueauo mltiples veces. Paia ello el semfoio inicia el contauoi con un nmeio que uefine los iecuisos uisponibles, y caua vez que se llama al semfoio con la funcion acquiie() se piuen iecuisos, si lo hay, el hilo sigue la ejecucion, peio si no los hay paia auquiiiilos, entonces se bloquea la ejecucion uel hilo en ese punto hasta que hayan iecuisos suficientes paia sei auquiiiuos, poi lo que iealmente funciona como un mutex especial. veamos un ejemplo sencillo: QSemaphore bytes(6); bytes.acquire(4); bytes.acquire(3);
Aqui, se ciea un semfoio bytes con el contauoi a 6, cuanuo el hilo llega a la piimeia auquisicion ue 4 bytes, no hay pioblema ya que an queuan 2, poi lo que la ejecucion sigue, peio en la siguiente al intentai auquiiii S, ya no pueue, asi que el hilo se queuaiia ahi, hasta que haya bytes uisponibles paia seguii. Paia uevolvei los bytes habiia que llamai a la funcion ielease(int n). Poi uefecto si no se pone un nmeio en acquiie o en ielease, se piesupone que es 1. Be esta maneia pouemos cieai 2 semfoios en nuestio caso, con los 2 casos extiemos que paiaiian la ejecucion ue alguno ue los hilos. El semfoio fieeBytes poi ejemplo pouiia inuicai el nmeio ue bytes libies paia sei esciitos, y que el piouuctoi pouiia auquiiii antes ue vei si pueue seguii esciibienuo, y el consumiuoi pouiia libeiai con ielease(), una vez lo haya leiuo. Lo inicializaiiamos con un valoi igual al nmeio total ue bytes uel buffei. Poi otio lauo otio semfoio llamauo useuBytes pouiia inuicai el nmeio ue bytes uisponibles paia lectuia, el hilo consumiuoi auquiiiiia antes uno, paia pouei leei, y si no lo hay, entonces queuaiia bloqueauo, hasta que lo hubieia, y el piouuctoi, libeiaiia bytes en este semfoio una vez haya esciito en el buffei. Bicho semfoio se inicializaiia con el valoi a u, o lo que es lo mismo instanciauo poi )*#
uefecto. Be esta maneia, caua hilo tiene su piopio semfoio, y ambos hilos inuican al otio las nuevas situaciones, libeianuo uel semfoio contiaiio, y auquiiienuo uel suyo piopio. Asi veis que el couigo queua mucho ms sencillo que usanuo el mutex y las 2 conuiciones ue espeia. const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize];
class Producer : public QThread { public: void run(); };
void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { freeBytes.acquire(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; usedBytes.release(); } }
class Consumer : public QThread { public: void run(); };
void Consumer::run() { for (int i = 0; i < DataSize; ++i) { usedBytes.acquire(); fprintf(stderr, "%c", buffer[i % BufferSize]); freeBytes.release(); } fprintf(stderr, "\n"); }
Compienuiuo el mecanismo que hemos explicauo ue los semfoios, su iniciacion, auquisicion y libeiacion, no hay mucho que comentai ue este couigo. Bueno y hemos uejauo paia el final, el hilo piincipal, que en ambos casos seiia el mismo. Besue main(), se iniciaiian ambos hilos con stait(), y luego se llamaiia en ambos a wait(), paia que no acabe la funcion main() y mueian los hilos antes ue que teiminen su tiabajo. Lo que hace esa funcion (wait) es espeiai a que uicho hilo acabe, y una vez acaba, uevuelve #48". int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; }
Ambos wait() se ejecutan uno uetis uel otio, ya que son hilos uifeientes, y se espeia a que estos acaben, paia teiminai la ejecucion ue main().
)*$
)%/" G_ ^$r]07-+ % 0/#$%+0Q&
Los gificos 2B en Qt estn basauos en QPaintei, que pueue uibujai uesue foimas geomtiicas como, puntos, lineas, iectngulos, etc, hasta mapas ue bits, imgenes y textos. Pueue aplicai efectos como antialiasing, alpha-blenuing, iellenauo con giauientes, etc. Pueue aplicai tiansfoimaciones y ms cosas. Pueue hacei touo esto sobie un QWiuget, un QPixmap o un QImage. Pueue sei usauo en conjuncion con QPiintei paia impiimii o paia geneiai PBFs, asi que el mismo couigo que usamos paia uibujai nos pueue peimitii impiimii. 0na alteinativa a QPaintei es el mouulo Qt0penuL, que acceue a la libieiia 2B y SB 0penuL. La foima ms tipica ue usai QPaintei en un Wiuget es poi ejemplo ieuefinienuole la funcion paintEvent() que se encaiga ue uibujailo. Esto es un ejemplo sencillo: void SimpleExampleWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 30)); painter.drawText(rect(), Qt::AlignCenter, "Qt"); }
Touas las funciones uiaw.(), son las encaigauas ue uibujai con QPaintei. Pieviamente a uibujai hay que uefinii las caiacteiisticas uel pintauo con las funciones settei setPen(), setBiush() y setFont(), que uefinen el lpiz ue tiazauo ue uibujo, el iouillo ue iellenauo ue foimas, y la fuente paia el texto, iespectivamente. Esas heiiamientas pueuen sei cambiauas en cualquiei momento. Las funciones ue uibujauo ue foimas ms impoitantes son: uiawPoint(), uiawLine(), uiawPolyline(), uiawPoints(), uiawLines(), uiawPolygon, uiawRect(), uiawRounuRect(), uiawEllipse(), uiawAic(), uiawChoiu(), uiawPie(), uiawText(), uiawPixmap() y uiawPath(). QPaintei sita el oiigen ue cooiuenauas poi uefecto en la esquina supeiioi izquieiua (u,u). Sin embaigo seiia ms comouo tenei una ventana con cooiuenauas logicas y que el sistema las pasaia a fisicas sin que el piogiamauoi tenga que hacei las conveision. Pues bin, llamamos viewpoit al iectngulo con cooiuenauas fisicas, y Winuows al iectngulo con cooiuenauas logicas. Esto se hace con QPaintei::setWinuow(). Luego esta la matiiz munuo, que es una matiiz paia aplicai tiansfoimaciones afines como iotaciones y tianslaciones. QNatiix es quien implementa uicha matiiz, y usanuo sus funciones iotate() y tianslate() se llevan a cabo las tiansfoimaciones, y finalmente se aplican al QPaintei meuiante su funcion setNatiix(QNatiix). Si iequeiimos ue ms caliuau, aunque esto ieuunua en menos velociuau, pouemos usai QImage paia uibujai. Paia ello cieamos un objeto QImage() con un tamao y foimato ue coloi, y luego instanciamos con QPaintei(QImage *), paia ii uibujanuo con l, seiia su uispositivo ue pintauo. (#A4296A Impiimii en Qt es similai a uibujai con QPaintei y se tiata ue seguii los siguientes pasos: 1.- Cieai QPiintei paia que siiva como el uispositivo ue pintauo (painting uevice). 2.- Abiii una ventana QPiintBialog, que peimita al usuaiio ajustai la impiesoia y uems ajustes. S.- Cieai un QPaintei que opeie con QPiintei. 4.- Pintai una pgina usanuo QPaintei. )*%
S.- Llamai a QPiintei::newPage() paia avanzai a la pgina siguiente. 6.- Repetii los pasos 4 y S hasta que se impiima touo. Se pueue tambin impiimii a un PBF llamanuo a set0utputFoimat(QPiintei::PufFoimat). QPrinter printer(QPrinter::HighResolution); QPrintDialog *dialog = new QPrintDialog(&printer, this); dialog->setWindowTitle("Imprimir Documento"); if (dialog->exec() != QDialog::Accepted) return;
QPainter painter; painter.begin(&printer);
for (int page = 0; page < numberOfPages; ++page) { // Usar painter para imprimir la pagina.
if (page != lastPage) printer.newPage(); }
painter.end();
El tamao ue la zona impiimible uel papel viene ueteiminauo poi QPiintei:pageRect(), que uevuelve el QRect ue la zona impiimible, con ello se pueuen hacei los clculos paia ueteiminai la vaiiable numbei0fPages y lastPage.
)*&
)%/" GL $%7\$+-+ %M)%$&-+
Acabanuo ya los temas que iesumen touo lo que es necesaiio sabei paia uesaiiollai una aplicacion ue pioposito geneial, hemos queiiuo metei en un mismo tema con el nombie ue iecuisos exteinos, una seiie ue picticas que nos peimiten hacei colaboiai a Qt con su exteiioi. Comenzanuo poi la posibiliuau ue caigai en tiempo ue ejecucion un uiseo ue ventana ue uilogo en foimato *.ui con las uitools, pasanuo poi la posibiliuau ue ejecutai piocesos o aplicaciones exteinas meuiante la clase QPiocess, y acabanuo poi la posibiliuau ue aauii la capaciuau ue uso ue libieiias exteinas a Qt.
'4YB8R8: 342YP458: W(\4<8?36AX Llamamos uilogos uinmicos a aquellos que han siuo cieauos en el Qt Besignei como ficheios *.ui, peio que no han siuo compilauos junto con la aplicacion, poi lo que el uic (ui compilei), no ha pouiuo pasailos a C++, y luego sei compilauos, si no que van a sei caigauos en tiempo ue ejecucion poi la aplicacion piincipal como .ui tal cual. Paia ello existe una clase capaz ue tal manejo, que es Q0ILoauei, que meuiante su funcion loau(QFile), pueue caigai uicho ficheio con toua su inteifaz. QUiLoader uiLoader; QFile file("dialog.ui");
QWidget *dialog = uiLoader.load(&file);
if(dialog){ // cdigo para recoger los widgets QComboBox *combo1 = dialog->findChild<QComboBox *>("combo1"); // si combo1 no existe devuelve un puntero nulo if (combo1).........
}
Bate cuenta que aqui caigamos el ficheio .ui con el 0iLoauei, y iecupeiamos su estiuctuia en un punteio QWiuget (uialog). 0sanuo ue la intiospeccion ue Qt, pouemos meuiante finuChilu, ii iecupeianuo punteios a sus componentes, conociuos sus nombies (objectName). Pouemos ue esta maneia ya usai uialog->show() paia mostiailo ue maneia no-moual o uialog- >exec() paia haceilo ue maneia moual. Paia usai Q0iLoauei tenemos que aauii a *.pio el mouulo uitools ue la siguiente maneia: C0NFIu += uitools Si vas a usai el compilai NSvC 6, es necesaiio que en vez ue usai finuChilu<T>() ue QWiuget, uses qFinuChilu<T> ue Qtulobal, ya que el piimeio no es sopoitauo poi uicho compilauoi.
#A8RA?P?: 6J96A28: W(#A856::X 0na ue las utiliuaues ue uesaiiollai una u0I, es facilitai el manejo ue una aplicacion ue consola que pieviamente existia, y cuya linea ue comanuos eia muy laiga e incomoua ue usai. Nos pouemos planteai el constiuiile una u0I paia pouei usaila ue una maneia ms gifica y comoua poi lo tanto. Qt, nos peimite eso meuiante la clase QPiocess.
)*'
Paia simplemente ejecutai una aplicacion exteina, usaiemos la funcion execute() ue maneia similai a sta: QString cmd = "cp a.txt b.txt"; QProcess::execute(cmd);
Si lo que queiemos es establecei una comunicacion entie el piogiama exteino y la aplicacion, si aqul lo peimite, en ese caso usaiemos la funcion stait(), y usaiemos wiite() paia enviaile uatos, y ieauAll() paia leei uel mismo. 0saiemos close() paia ceiiai el canal ue comunicacion. 0n ejemplo ue este tipo ue comunicacion es posible con piogiamas como el bash ue Linux, o Telnet, o cmu.exe ue Winuows. veamos un ejemplo: QProcess bash; bash.start("bash"); if(!bash.waitForStarted()){ qDebug() << "NO RULA"; return -1; } bash.write("ls"); bash.closeWriteChannel(); if(!bash.waitForFinished()){ qDebug() << "NO RULA"; return -1; } QByteArray response = bash.readAll(); qDebug() << response.data(); bash.close();
\:8 36 B4HA6Ak?: 6J96A2?: Cuanuo queiemos usai libieiias paia linkailas nuestio piogiama, simplemente hay que aauii a nuestio ficheio *.pio una linea como esta: LIBS += -lnombie_libieiia Siembie que compilemos con el uN0 Compilei. Asi la libieiia matemtica seiia -lm, la libieiia cuil seiia -lcuil, y asi sucesivamente. Peio hay veces que queiiemos llamai en tiempo ue ejecucion a funciones ue una libieiia uinmica, que en Winuows tiene extension .ull, en Nac0SX suele sei .uylib, y en Linux es .so . Paia tal caso, Qt piovee ue un sistema multiplatafoima a tiavs ue la clase QLibiaiy. Toua libieiia tiene sus funciones expoitauas como simbolos. Supongamos que una libieiia llamaua "mylib" con la extension coiiesponuiente uel opeiativo uonue est instalaua, tiene una funcion que en C tiene como piototipo "int avg(int, int)" que lo que hace es iealizai la meuia aiitmtica ue los 2 paimetios que se le pasan, y uevuelve esa meuia en foimato enteio. Si queiemos llamai a uicha funcion uesue Qt, habiia que usai el siguiente couigo: QLibrary library("mylib"); typedef int (*AvgFunction)(int, int);
Si, has leiuo bien, este capitulo se llama "bscate la viua", esto no quieie uecii que ya me haya cansauo ue esciibii este libio, ni ue explicai nuevas cosas. Qt es un Fiamewoik que ya tiene casi la veintena ue aos, poi lo que a uia ue hoy ha cieciuo enoimemente, tanto que ningn libio que lo tiate pueue aspiiai a tocai absolutamente touas sus clases. Tambin es cieito que hemos tocauo las clases que ms vas a usai siempie que uesaiiolles aplicaciones ue pioposito geneial, peio es posible que alguna vez te plantees hacei otia cosa, y esto no est cubieito en ningn libio. Bay que pensai que Qt, seguii ciecienuo en el futuio, poi lo que la nica foima ue manteneise al uia, es usanuo el Qt Assistant, es uecii, buscnuose uno mismo la viua. Poi tanto, lo que pietenuemos con este capitulo es cubiii esa paite que viene uespus ue cuanuo acabes este libio, y tengas que empezai a esciibii couigo, y en algunas ocasiones te tiopieces con que tienes que usai cosas, que no has estuuiauo antes, y nunca las has usauo, e incluso que no pueuas encontiai en los foios a nauie que lo haya usauo antes. Qt est muy bien uocumentauo, peio en ingls, poi lo que es funuamental entenuei al menos el iuioma ue Shakespeaie a nivel ue lectuia tcnica. Pues bien, paia piacticai, se me ha ocuiiiuo planteai unas clases que no hemos visto, y que cuiiosamente eches ue menos, si has piogiamauo en otios entoinos. Se tiata ue la hoia, la fecha e incluso uel uso ue timeis, aunque en el tema 2S hemos visto un ejemplo ue ste ltimo. Poi ello vamos a piacticai en este tema a buscainos la viua en el asistente. Realmente pouiia habei centiauo la bsqueua en cualquiei otio tema ms complejo, peio simplemente lo seiia poi tenei ms funciones, piopieuaues, seales y slots, o poi que el texto ue la uesciipcion es mucho ms extensa. Asi que si seguimos bien estas S clases, no habiia poi qu habei ningn pioblema en cualquiei otia. Lo piimeio seiia sabei qu clases pouiian encaigaise ue la hoia, ue la fecha, o ue un piopoicionai un timei. Bebiuo a que un poco ue ingls si que sabemos, y ms si hemos tiabajauo con libieiias similaies en C, C++ u otio lenguaje, sabemos que la hoia es Time, que la fecha es Bate y Timei est claio lo que es, asi que no seiia muy uescabellauo pensai que uichas clases se llamen QTime, QBate y QTimei. Asi que nos vamos al asistente, y buscamos las S clases, veiemos que hemos aceitauo en touo. Caiamba, que sueite tenemos . Be touas foimas si no tuviiamos claio el concepto ue nuestia clase, siempie pueue uno uaise una paseo poi touas, paia uetectai uentio ue su nombie un atisbo ue luz. Poi ejemplo, ue qu ciee que tiatai la clase QNimeBata o QFtp ..
()4P6 Es eviuente que el constiuctoi ue esta clase, uebe ue peimitii iniciai una instancia con una hoia ueteiminaua. vemos entie las public functions, siempie en piimei lugai los uistintos constiuctoies, uno sin paimetios, poi lo que es una meia instanciacion, y uebe ue existii poi tanto una funcion que ms taiue pueua ponei la hoia, que poi su piototipauo, uebe ue sei setBNS(). 0tia ue las cosas impoitantes que hay que miiai en una clase, es queuaise con las piopieuaues o vaiiables piivauas, ya que asociauas a ellas vamos a encontiai una seiie ue funciones settei y gettei impoitantes paia su manejo. Asi nos encontiamos con houi(), minute() y seconu() en los gettei, y el ya mencionauo setBNS() como el nico settei. Luego nos encontiaiemos con una seiie ue funciones que llevan a cabo una laboi especial, que pouemos leei en su uesciipcion ue qu se tiata. Busca poi tanto, la laboi ue stait(), iestait() y ellapseu(). Estn muy ielacionauas entie si, y asi apaiece en sus uesciipciones. Tambin es muy impoitante aquella que iecoge la hoia exacta actual, que ue seguio es ))*
cuiientTime(), entie los static public. Bentio ue los opeiauoies, vemos que se pueuen compaiai 2 objetos QTime entie si, lo cual pueue sei muy til. Y an ms til una seiie ue funciones que peimiten aauii a la hoia, inteivalos ue tiempo vaiiables, en segunuos (auuSecs). Te animo a que hagas piuebas con ellas en un couigo sencillo ue consola.
('?96 Se tiata ue una clase ue similai uisposicion a la anteiioi. Poi ello te animamos a que la uesciibas t mismo, y luego compiuebes su funcionaliuau en un couigo tambin sencillo.
()4P6A Esta clase, eia funuamental explicaila, ya que es muy til siempie el uso ue timeis. El uejaila paia un tema autosuficiente como ste, nos va a peimitii sei ms autonomos ue aqui en auelante a la hoia ue manejai el Fiamewoik ue Qt, poique otia posibiliuau que nos pueue ocuiiii, es que se nos olviue la funcionaliuau ue algunas ue las clases que ya hemos explicauo, y no tengas ceica este libio paia iepasailas, mientias que tenienuo el asistente, siempie pouis sacai el tiabajo auelante. Lo piimeio que nos uice el asistente es que QTimei piovee ue timeis iepetitivos y ue un solo uispaio. Los timeis iepetitivos son aquellos que caua inteivalo, se uispaia el evento uel timei, y los ue un solo uispaio, solo se piogiamai y se uispaian una sola vez. Es ue suponei que paia inuicai que ha llegauo al final ue su contauoi, uispaie una seal. Y asi es, ue hecho solo pouemos vei la seal timeout(). veamos sus piopieuaues, que son: active, que es un bool que estai a tiue cuanuo est activo, y false cuanuo no lo est; inteival, que es un enteio, que ue seguio contiene el inteivalo piogiamauo; y singleShot que es un bool que estai tiue si es ue nico uispaio, o a false, si es iepetitivo. En toino a estas piopieuaues, ueben hacei getteis y setteis. Como setteis tenemos setInteival() y setSingleShot(), y como getteis tenemos, isActive() e isSingleShot(). Como public functions, tenemos las ms impoitantes, que son stait() paia ponei en maicha el timei, y stop() paia paiailo en cualquiei momento. Bay otia funcion llamaua singleShot() que nos peimite, piogiamai el inteivalo y el slot a ejecutai ue un ueteiminauo objeto, cuanuo uicho inteivalo haya pasauo. Puesto que QTimei piovee ue una seal, timeout() es tambin muy logico el usaila paia conectaila a slots ue otios objetos que hagan algo una vez pasauo el tiempo. Te animamos a que esciibas un piogiama sencillo, que caua segunuo, aumente el valoi ue un contauoi en un QLCBNumbei.
Quizs este tema te haya paieciuo muy tiivial, si es asi, es que ya estas piepaiauo paia nauai t solo en el univeiso Qt. Peio an no te vayas, poique el ltimo tema es el siguiente, y tiata ue algo que muy pocos suelen tiatai, esto es, ue como piepaiai un instalauoi paia nuestia aplicacion paia los S opeiativos ms impoitantes: Linux, Nac0SX y Winuows.
)))
)%/" G[ 0&+)"<"'-$%+
Al final uel tema 2, cuanuo piepaiamos el entoino ue uesaiiollo, paia pouei uesaiiollai touos los ejemplos uel libio sin pioblemas, avisbamos ue que las aplicaciones uesaiiollauas poi uefecto con estas instalaciones poi uefecto uel SBK ue Qt, no pouian sei implementauas tal cual en sistemas ue piouuccion uonue el SBK no va a estai instalauo. Llego el momento ue tomai en consiueiacion qu aichivos uebemos ue llevainos con nuestias aplicaciones fueia uel oiuenauoi uonue se efectuo uesaiiollo, paia que touo funcione coiiectamente. El entoino ue uesaiiollo instalauo poi uefecto, funciona con libieiias ue enlace uinmico, poi lo que vamos a compilai ejecutables que son poco pesauos, peio que enlazan en tiempo ue ejecucion con una seiie ue libieiias uinmicas, poi lo que nos tenuiemos que llevai junto con el ejecutable, toua una seiie ue libieiias y plugins, sobie la que el mismo se va a apoyai paia pouei funcionai. Poi ello es muy inteiesante uisponei, no solo ue un oiuenauoi opeiativo paia el uesaiiollo, si no tambin, uisponei ue otio (mquina ieal o viitual) uonue est instalauo el opeiativo poi uefecto sin ms, uonue vamos a piobai que entiegamos touo lo necesaiio paia que nuestia aplicacion funcione. 0na vez tengamos en una caipeta a paite, touos los elementos necesaiios paia que la aplicacion funcione autonomamente, pouiemos iecuiiii a cieai un sistema ue instalacion que se encaigue ue copiai uichos elementos en la maneia uebiua al sistema en piouuccion. vamos poi tanto a seguii un ejemplo, en los S sistemas opeiativos ue siempie (Winuows, Linux y Nac 0SX), y lo vamos a hacei con la aplicacion que uesaiiollamos en el tema 2u que es un euitoi ue textos uonue estn piesentes los elementos tipicos ue una aplicacion ue pioposito geneial. vamos pues a usaila paia cieai el paquete ue instalacion coiiesponuiente a caua uno ue los sistemas opeiativos objetivo.
D4238E: Si no lo has hecho anteiioimente, abie el aichivo ue pioyecto (.pio) en tu entoino ue uesaiiollo (Qt Cieatoi), y pulsanuo en el mouo Piojects (iconos ue la izquieiua), selecciona en "Euit Builu configuiation" la opcion Release. Luego, vamos a ieconstiuii la aplicacion con Rebuilu Pioject. Pouemos incluso ejecutaila. No uebe ue habei ningn pioblema, ya que queuo completamente cieaua y piobaua en el tema 2u. Ya tenemos en el uiiectoiio uonue guaiuemos nuestios fuentes, una caipeta que se llamai application-builu-uesktop, en cuyo inteiioi encontiaiemos en la caipeta Release, el ejecutable final (application.exe). Si usas visual Stuuio 2uu8 como compilauoi, y en el sistema est iegistiaua la iun-time ue visual C++ 9.u "msvcp9u.ull", pouis ejecutai sin pioblemas la aplicacion. Si usas el compilauoi NinuW que va en el paquete ue Qt4, las libeiias uinmicas coiiesponuientes no estain iegistiauas en el sistema, y la ejecucion ue la aplicacion uesue su caipeta, te uai eiioi inuicnuote la piimeia libieiia uinmica que intenta enlazai peio que no encuentia. Sea como fueie, uebemos piepaiaile al ejecutable, touo lo que iequieie en su piopia caipeta, asi que vamos a ello. Paia sabei ue qu uepenue nuestia aplicacion, en Winuows vamos a tenei que usai una heiiamienta que no viene incluiua en el SBK ue Qt, llamaua Bepenuency Walkei. Pueues bajaila ue http:www.uepenuencywalkei.com. En nuestio caso hemos bajauo la veision ue S2 bits (foi x86). Al ejecutaila, vamos a File -> 0pen, y abiimos nuestio ejecutable (application.exe). Se nos uespliega en la ventana supeiioi izquieiua touo un ibol ue uepenuencias, peio lo que nos inteiesa, est en las iamas piincipales ue uichos iboles. Si colapsamos uichas iamas, en un sistema con vS2uu8 tenuiiamos algo asi: ))!
Como pouemos obseivai, nuestia aplicacion compilaua con visualC++ 2uu8 (9.u) uepenue ue 4 ulls, peio una ue ellas, ya viene piovista poi el sistema opeiativo Winuows (keinelS2.ull), poi lo que iealmente vamos a iequeiii ue las Blls Qtuui4.ull, QtCoie4.ull y NSvCR9u.ull . Be hecho estas S uepenuencias, las pouiamos pieveei, ya que si miiamos el conteniuo uel ficheio ue pioyecto (application.pio) veiemos que piue aauii los mouulos "coie" y "gui": QT += coie gui Poi lo que, es ue suponei que iequeiii ambas libieiias uinmicas. La teiceia uepenuencia es tipica ue quien usa el compilauoi vS2uu8. Quien use NinuW se encontiai con 2 uepenuencias, las ue los ficheios mingwm1u.ull y libgcc_s_uw2-1.ull . Bonue pouemos encontiai esas libieiias.. Pues las libieiias ue Qt se encuentian en el uiiectoiio bin ue la instalacion uel Qt SBK. La libieiia ue visual C++ est en el uiiectoiio ue instalacion ue vS2uu8 (Aichivos ue PiogiamasNiciosoft visual Stuuio 9.uvCceull), uonue pouis elegii la aiquitectuia ue CP0, en nuestio caso en la caipeta x86 (paia PC). Asi que tiaslauamos esas S uepenuencias al mismo sitio uonue esta nuestio ejecutable. Si llevamos esos 4 ficheios en una caipeta a cualquiei PC con Winuows XP, vista o 7, veis que se pueue ejecutai sin pioblema alguno. Babin aplicaciones que hacen uso ue plugins, como pueuan sei uiiveis ue bases ue uatos, uiiveis ue foimatos gificos, etc. veiemos luego en un apaitauo qu hacei en ese caso.
<42IJ Si no lo has hecho anteiioimente, abie el aichivo ue pioyecto (.pio) en tu entoino ue uesaiiollo (Qt Cieatoi), y pulsanuo en el mouo Piojects (iconos ue la izquieiua), selecciona en "Euit Builu configuiation" la opcion Release. Luego, vamos a ieconstiuii la aplicacion con Rebuilu Pioject. Pouemos incluso ejecutaila. No uebe ue habei ningn pioblema, ya que queuo completamente cieaua y piobaua en el tema 2u. La aplicacion queuai en su uiiectoiio ue maneia que pueue ejecutaise uiiectamente uesue l (.application). Paia compiobai sus uepenuencias, hay una heiiamienta que ya viene con las heiiamientas uN0, que es 3%%. luu .application Nos iesponuei con una seiie ue libieiias uinmicas uel tipo .so . La gian mayoiia ue esas libieiias suelen estai instalauas en un sistema limpio con gestoi ue ventanas unome o KBE. Peio es conveniente que antes te ceicioies ue ello. Y si es asi, es posible que uicha libieiia se instale meuiante algn paquete que se pueua bajai ue los iepositoiios oficiales ue la uistiibucion ue Linux en cuestion. Finalmente uichas libieiias siempie acabain en lib, usilib o usilocallib. Be esta maneia son siempie accesibles a la aplicacion. Peio a paite ue estas libieiias veiemos otias que no estn en esos uiiectoiios que ue seguio son: ))"
libQtuui.so.4 y libQtCoie.so.4 . Estas las vamos a tenei que ponei al alcance ue nuestia aplicacion en su piopio uiiectoiio. Puesto que se tiatan ue links a ficheios ue otio nombie lo hacemos ue la maneia: cp -R qtsukqtliblibQtuui.so.4* application_foluei cp -R qtsukqtliblibQtCoie.so.4* application_foluei Babin aplicaciones que hacen uso ue plugins, como pueuan sei uiiveis ue bases ue uatos, uiiveis ue foimatos gificos, etc. veiemos luego en un apaitauo qu hacei en ese caso.
/?5 -+M 0na aplicacion paia Nac, lleva la extension .app, y en si mismo es una caipeta en cuyo inteiioi lleva el veiuaueio ejecutable y touos los iecuisos, plugins, fiamewoiks, etc, que necesita paia funcionai. En iealiuau un .app es un bunule y tiene la foima que uefinimos en el gifico siguiente:
Si no lo has hecho anteiioimente, abie el aichivo ue pioyecto (.pio) en tu entoino ue uesaiiollo (Qt Cieatoi), y pulsanuo en el mouo Piojects (iconos ue la izquieiua), selecciona en "Euit Builu configuiation" la opcion Release. Luego, vamos a ieconstiuii la aplicacion con Rebuilu Pioject. Pouemos incluso ejecutaila. No uebe ue habei ningn pioblema, ya que queuo completamente cieaua y piobaua en el tema 2u. Inicialmente application.app contiene: Info.plist Nac0S PkgInfo Resouices Paia vei las uepenuencias uel ejecutable en si (no uel bunule), usamos una heiiamienta que lleva el XCoue, que se llama &#&&3: otool -L application.appContentsNac0sapplication En nuestio caso iesponue asi en Nac 0SX 1u.6.4: application.appContentsNac0sapplication: Qtuui.fiamewoikveisions4Qtuui (compatibility veision 4.7.u, cuiient veision 4.7.u) QtCoie.fiamewoikveisions4QtCoie (compatibility veision 4.7.u, cuiient veision 4.7.u) usiliblibstuc++.6.uylib (compatibility veision 7.u.u, cuiient veision 7.9.u) usiliblibgcc_s.1.uylib (compatibility veision 1.u.u, cuiient veision 62S.u.u) usiliblibSystem.B.uylib (compatibility veision 1.u.u, cuiient veision 12S.2.u)
))#
Las S libieiias infeiioies (.uylib) son piopias ue touo sistema poi uefecto. Las 2 supeiioies, son libieiias que se han instalauo en foima ue Fiamewoik, que es como se instalan poi uefecto las libieiias uel Qt4 SBK en Nac. Be hecho pueues veilas a touas en LibiaiyFiamewoiks. Como cieai a mano el bunule con touo lo que necesita, seiia laigo y teuioso, Nokia nos ofiece una heiiamienta con el SBK que lo hace poi nosotios ue maneia sencilla y comoua. Se llama "macueployqt", que piue los siguientes iequisitos paia la constiuccion uel bunule final: 1.- Las veisiones uebug ue los plugins no son aauiuas al bunule. 2.- Los plugins uesignei no son aauiuos al bunule. S.- Los plugins paia foimato ue imgenes si que son aauiuos al bunule. 4.- SQL uiiveis, Sciipts plugins, Phonon back-enu plugins, Svu Icon plugins, siempie son aauiuos al bunule si la aplicacion usa los mouulos coiiesponuientes QtSql, QtSciipt, Phonon y QtSvg. S.- Si quieies aauii una libieiia no-Qt al bunule, tenuis que antes aauiila al pioyecto .pio como una libieiia explicita. En tal caso, se aauiiia sin pioblemas a bunule. Bien, como en nuestio caso cumplimos sin pioblemas touas estas piemisas, vamos a cieai el bunule ue una vez y poi touas hacienuo: macueployqt application.app Tias lo cual, el conteniuo uel bunule habi cambiauo a: Fiamewoiks Info.plist Nac0S PkgInfo PlugIns Resouices Pouemos vei que en Fiamewoiks se han aauiuo los que hacian falta, y alguno ms. Pouemos boiiai a mano los que sobian si queiemos ahoiiai espacio. Ya pouemos uistiibuii la aplicacion sin pioblemas, y paia instalaila en otio equipo el usuaiio solamente tenuiia que aiiastiai el icono coiiesponuiente al .app a la caipeta Aplicaciones. Babin aplicaciones que hagan uso ue plugins, como pueuan sei uiiveis ue bases ue uatos, uiiveis ue foimatos gificos, etc. veiemos en el siguiente apaitauo como hacei esto, aunque nuestia heiiamienta ya se haya encaigauo tambin ue colocai los plugins que consiueia necesaiios en sus iespectivas caipetas uentio uel bunule.
#BIR42: Los plugins en Qt, peimiten aauii nuevas funcionaliuaues a las aplicaciones. Asi hay plugins que peimiten aauii nuevos foimatos ue imgenes legibles en Qt, o nuevos tipos ue bases ue uatos, etc. Los plugins incluiuos en el SBK, estn en el uiiectoiio qtplugins en su caipeta ue instalacion. Los nombies ue esas caipetas son fijos, y si se tiaslauan tal cual a la caipeta uel ejecutable ue la aplicacion, la misma no tenui pioblemas en encontiai uicho plugin si lo iequieie, ya que poi uefecto es ahi uonue los buscai. Si queiemos poneilos en otio sitio uifeiente, entonces en la funcion main() ue la aplicacion tenuiemos que ueciile uonue encontiaila usanuo QCoieApplication::auuLibiaiyPath() . Los plugins paia bases ue uatos que el SBK piovee son muy limitauos (0BBC y SQLite). Nosotios hemos aauiuo el ue Postuiesql y el ue NySQL en nuestios ejemplos, paia cualquieia ue las S platafoimas que hemos explicauo. Pueues compilai t mismo cualquiei plugin bajanuo los fuentes uel SBK (qt-eveiyone-sic), y compilanuo lo que necesites confoime a los REABNE que le acompaan. El ltimo paigiafo ue este tema explica el piocesos ue compilacion uel uiivei paia NySQL. ))$
02:9?B?38A6: 62 D4238E: K <42IJ Sabienuo ya el paquete que uebemos copiai, pouiiamos nosotios mismos cieai un instalauoi meuiante una aplicacion, sciipt o similai. vamos a pioponeite una opcion ms sencilla paia que pueuas tenei en cuenta a la hoia ue entiegai tus aplicaciones. Y vamos a empezai poi Winuows y Linux. Aunque hay muchas aplicaciones que estn especializauas en hacei instalauoies ue un paquete, nosotios hemos escogiuo una en paiticulai uesaiiollaua en TkTcl que peimite cieai instalauoies paia Winuows, Linux y otios 0NIX. Su nombie es Install}ammei, que es giatuito, ue couigo abieito y multiplatafoima, como a nosotios nos gusta. Cieai un instalauoi con esta heiiamienta es muy sencillo e intuitivo a pesai ue que est en ingls. vamos a seguii con nuestia aplicacion paia hacei el ejemplo ue cieacion uel instalauoi. Al aiiancai Install}ammei, pulsamos en New Pioject, y se nos abie un wizaiu paia cieai el pioyecto uel instalauoi. Rellenamos los uatos que se nos van piuienuo. Contestauas touas las pieguntas, pulsamos en Finish, y se nos abie el Install Besignei con una seiie ue items que pouemos ii cambianuo a nuestio gusto, o uejanuo su valoi poi uefecto. Bejamos al usuaiio el husmeai poi toua una ingente cantiuau ue paimetios. vamos a constiuii con los valoies poi uefecto paia Winuows o paia Linux confoime necesitemos. Pulsamos sobie Builu Install, y vemos en la ventana como se nos ciea Application-1.u-Setup.exe (poi ejemplo paia Winuows). Si pulsamos sobie su link, se nos abie la caipeta uonue se ha cieauo el ejecutable instalauoi, listo paia sei usauo. Asi ue sencillo es cieai un instalauoi con este sencillo piogiama.
02:9?B?38A6: 62 /?5 -+M Paia cieai instalauoies en Nac, no hay ninguna aplicacion simple y libie como la que acabamos ue vei, peio si pouemos usai heiiamientas que vienen en nuestio sistema poi uefecto, una vez hemos instalauo XCoue, y que nos peimitiin cieai un instalauoi con aspecto piofesional. vamos a haceilo ue 2 maneias uifeientes: una meuiante una imagen .umg uonue se aiiastia el .app sobie la caipeta Aplicacion, y otia cieanuo una paquete instalable meuiante la heiiamienta PackageNakei ue XCoue. Seguimos usanuo nuestio ejemplo ya empaquetauo en un bunule completo, tal como lo uejamos, piepaiauo paia llevai a otio equipo (application.app). vamos a cieai una imagen BNu con la utiliuau ue uiscos. Pulsaiemos sobie Nueva Imagen, y vamos a ponei los ajustes ue la imagen ue a continuacion:
))%
La cieamos uel tamao suficiente paia que quepan .app y una fonuo en PNu que cieaiemos ue 7uux4uu, similai a ste:
Nontamos con un uoble clic la imagen BNu vacia iecin cieaua, y aiiastiamos a ella el bunule .app. Luego nos vamos al uisco iaiz, y cieamos un alias ue la caipeta Aplicacion, la aiiastiamos al BNu y le cambiamos el nombie a Aplicacion. Con el BNu montauo y abieito en el finuei, pulsamos Cmu+}. Se abien las opciones ue caipeta, y hacemos algo como esto:
El fonuo lo elegimos hacienuo uoble click en el cuauio ue aiiastiai la imagen, y seleccionamos el PNu. Ya se vei el BNu montauo con la imagen ue fonuo, y pouiemos situai los iconos, y ieuimensionai la ventana paia ajustaila al tamao uel fonuo. Expulsamos el BNu montauo, y nos vamos a la utiliuau ue uiscos, y eligienuo la imagen BNu cieaua, pulsamos en conveitii, y la guaiuamos esta vez compiimiua. Se ciea el BNu final piepaiauo paia sei uistiibuiuo. Al montailo queuai algo como esto:
Bonue queua claia la intencion ue que se aiiastie el icono ue application.app sobie la caipeta Applicaciones, paia que se piouuzca la instalacion. Pasemos a la segunua opcion, que consiste en cieai un paquete ue instalacion uel tipo *.pkg con el PackageNakei uel XCoue. Bicha aplicacion la pueues encontiai en BevelopeiApplications0tilitiesPackageNakei. Al aiiancaila, lo piimeio que nos piue es la oiganizacion (tipo com.nombie_oiganizacion), y el opeiativo objetivo minimo. Pulsanuo sobie el ))&
+ en la esquina infeiioi izquieiua pouemos aauii los componentes a instalai, que en nuestio caso es solamente uno (application.app). Si navegas poi esta heiiamienta, veis que tambin es muy intuitiva y potente, y est en ingls. En la zona ue conteniuos, se pueuen ponei vaiios elementos (aplicaciones, libieiias, fiamewoiks, ayuuas, etc). En Configuiation, pouemos elegii qu vamos a instalai y uonue, si vamos a peimitii que el usuaiio ieubique la instalacion y si se va a iequeiii autentificacion poi paite uel auministiauoi paia instalaila, ue maneia que pouiemos tambin copiai ficheios en zonas uel sistema. En Contents pouemos elegii el usuaiio y giupo al que peitenecei este conteniuo y sus peimisos. Si seleccionamos el paquete ue uistiibucion (encima ue Contents), pouiemos euitai las opciones uel paquete completo, poninuole un nombie, los tipos ue seleccion accesibles al usuaiio, el uestino ue instalacion, pouiemos piogiamai iequisitos paia instalailo, como espacio libie en uisco uuio, CP0, veision uel sistema opeiativo y muchos ms, tambin se pouin piogiamai acciones a llevai a cabo antes ue pioceuei a la instalacion, y una vez sta ha finalizauo. En la zona supeiioi ueiecha, tenemos el icono "Euit Inteiface", que nos peimite euitai el inteifaz ue instalacion, cambianuo su fonuo, y el texto ue caua uno ue los pasos ue la instalacion. 0na vez, ya tenemos touas las opciones iellenauas confoime a nuestia necesiuau, pouemos pulsai en el icono ue la zona supeiioi izquieiua "Builu", que constiuii el paquete ue instalacion. Bicho paquete pueue entiegaise como tal, o pueue meteise en una BNu tal como apienuimos anteiioimente.
78PN4B?54C2 36 I2 3A4V6A +(< El ltimo ue los escollos a soiteai paia uistiibuii nuestia aplicacion es que tengamos el uiivei uel tipo ue base ue uatos que vamos a usai en nuestia aplicacion compilauo. La veision 0pen Souice ue Qt4, poi cuestiones ue licencias no lleva compilauos los uiiveis ms que ue 0BBC y SQLite (que va integiauo en Qt4), y quizs con esto haya suficiente paia muchos, peio una gian cantiuau ue gente usa otias bases ue uatos, y aunque pouiian usai el uiivei 0BBC paia ello, siempie es iecomenuable usai el uiivei nativo sin ms aauiuos. vamos poi tanto a explicai, como compilai el uiivei paia una ue las bases ue uatos ms usauas, que es sin uuua NySQL. Paia pouei haceilo, auems ue tenei instalauo el sistema ue uesaiiollo completo, como ya tenemos, paia pouei ejecutai qmake, g++ y make uesue la linea ue comanuos, tenuiemos que bajainos los fuentes ue NySQL y ue Qt4. Los fuentes ue NySQL, pouemos bajailos ue http:www.mysql.comuownloausmysql en la veision essentials. A paite ue la instalacion completa, tenuiemos uos caipetas funuamentales que son lib y incluue, uonue tenuiemos iespectivamente la libieiia necesaiia paia nuestio cliente, y los fuentes ue NySQL. ))'
Los fuentes ue Qt4, estn en la web ue Nokia http:qt.nokia.com , y se llama qt- eveiywheie-opensouice-sic-4.x.x . En este paquete encontiaiemos los fuentes que necesitamos ue nuestio uiivei en la caipeta $QT_S00RCESsicpluginssqluiiveismysql. Ahi encontiaiemos un ficheio main.cpp con el couigo uel uiivei y el ficheio ue pioyecto mysql.pio . Situauos en el uiiectoiio ue los fuentes uel uiivei paia Qt4, ejecutaiemos los siguientes comanuos en linea: 1.- Winuows (vS2uu8): Piesuponemos PATB_NYSQL como el iaiz ue los fuentes ue NySQL. qmake INCL0BEPATB+=PATB_NYSQLincluue LIBS+=PATB_NYSQL liboptlibmysql.lib mysql.pio nmake uebug nmake ielease
Tenuiemos al final las veisiones uebug y ielease ue los uiiveis, esttica y uinmica (qsqlmysql4.ull qsql_mysql.lib).
2.- Linux: Piesuponemos $PATB_NYSQL como la iaiz ue los fuentes ue NySQL qmake INCL0BEPATB+=$PATB_NYSQLincluue LIBS+=-L$PATB_NYSQLlib -lmysqlclient_i mysql.pio make
Se cieai la veision ielease uinmica libqsqlmysql.so .
S.- Nac 0SX: Piesuponemos $PATB_NYSQL como la iaiz ue los fuentes ue NySQL qmake -spec macx-g++ INCL0BEPATB+=PATB_NYSQLincluue LIBS+=-LPATB_NYSQLlib -lmysqlclient_i mysql.pio make uebug make ielease
Se cieain la veision ielease y uebug uinmicas libqsqlmysql.uylib y libqsqlmysql_uebug.uylib .
Con esto uamos poi finalizauo el conteniuo ue este libio, en el que hemos intentauo uotailo ue touo el conteniuo pictico necesaiio paia el uesaiiollo eficaz ue aplicaciones ue pioposito geneial en Qt4, peio an queua mucho camino poi anuai, peio sin uuua ya tenemos los funuamentos paia que este viaje sea ms agiauable y sencillo.
))(
>0><0-^$"]0"
An lnLroducLlon Lo deslgn paLLerns ln C++ wlLh CL4 - renLlce Pall - Alan & aul LzusL
1he book of CL4. 1he arL of bulldlng CL appllcaLlons - no SLarch ress - uanlel MolkenLln
C++ Cul rogrammlng wlLh CL4 - renLlce Pall - !asmln 8lancheLLe & Mark Summerfeld
CL AsslsLanL - C1 nCklA Suk 1he C++ rogrammlng Language - Addlson Wesley - 8[arne SLrousLrup