November 29th, 2011
Hace unos días en el blog oficial de Qt anunciaron el lanzamiento de las nuevas Qt Developer Guides, no quería escribir sobre estas guiás sin antes darles una mirada en profundidad, las guiás son muy completas, están dividas en varios capítulos en donde se abordan diferentes conceptos y funcionalidades, los cuales son aplicados en el desarrollo de una aplicación de ejemplo a lo largo de toda la guiá.
Las dos primeras guiás liberadas se centran en el desarrollo usando Qt Quick y JavaScript, tanto para Symbian (aunque todo lo explicado puede ser aplicado en MeeGo) como para Desktop, con estas guiás pueden aprender sobre el uso de Qt Quick Components, Animations, Transitions, States, persistencia de datos usando Offline Storage, creación de controles personalizados y mucho mas.
Si recién están empezando a trabajar con Qt y con Qt Quick, les recomiendo que lean y hagan los ejercicios que vienen en estas guiás, son una forma rápida de experimentar todo el proceso de desarrollo de una aplicación y van a aprender fácilmente, conceptos, buenas practicas y la forma de aplicarlos en sus propios desarrollos.
Programming with Qt Quick for Symbian^3 Devices
Pueden descargar esta guiá en los siguientes formatos:
Si se topan con algún error o tienen sugerencias, pueden dejarlas aquí
Qt Quick Application Developer Guide for Desktop
Pueden descargar esta guiá en los siguientes formatos:
Si tiene ideas, sugerencias o encuentran algún bug pueden reportarlo aquí
Espero estas guiás les sean útiles y manténganse atentos que pronto se vienen muchas mas.
Actualización – 13/12/2011
La guiá Programming with Qt Quick for Symbian^3 Devices ha sido actualizada hoy, ha pasado a llamarse Programming with Qt Quick for Symbian and MeeGo Harmattan Devices y se le ha agregado todo un nuevo capitulo con consejos y buenas practicas para portar aplicaciones Symbian a MeeGo.
Actualización – 12/01/2012
La gente de Zona Qt ha traducido al español la guiá Programming with Qt Quick for Symbian and MeeGo Harmattan Devices, pueden acceder a ella desde aquí.
October 15th, 2011
SubteGo, es una guiá para el servicio de Subte (Metro, Subway) de Capital Federal (Buenos Aires, Argentina), SubteGo es una aplicación para Symbian^3, desarrollada con Qt haciendo uso extensivo de QML y de Qt Components para la UI, de Qt Webkit y el API de Nokia Maps (ex Ovi Maps) para la parte de mapas y de Offline Storage para persistir los datos.
La aplicación ya esta disponible para su descarga desde Nokia Store de forma gratuita, una versión para MeeGo esta en proceso de ser enviada para su aprobación por el equipo de QA en Nokia Store.
El código fuente tanto de la versión para Symbian como el de la versión para MeeGo, va a estar disponible luego de que las dos aplicaciones hayan sido aprobadas por Nokia Store.
SubteGo es un proyecto que nació como un experimento (por eso forma parte de los labs) con el objeto de crear una aplicación en la que pueda aplicar las ultimas novedades de Qt y conocer el proceso de aprobación de aplicaciones que lleva a cabo Nokia Store, también tenia como objetivo el que sea una aplicación útil para un gran numero de personas y que pueda ser un medio de consulta recurrente.
Espero que la aplicación les sea útil si es que la descargan, y que el código fuente que pronto sera liberado les permita aprender un poco mas acerca de Qt y el proceso de desarrollo de aplicaciones para Symbian y MeeGo.
Download SubteGo
October 4th, 2011
Si están leyendo este post es muy posible que sea porque tienen problemas para que Smart Installer detecte e instale Qt Components, se supone que al compilar nuestro proyecto teniendo la opción de que lo haga junto con Smart Installer y que en el .pro este presente la siguiente linea de código:
# Add dependency to Symbian Qt Components
CONFIG += qtquickcomponents
Smart Installer detectara en el momento de la instalación, si el dispositivo ya cuenta con Qt Components, caso contrario se encargara de descargarlo e instalarlo, lamentablemente esto ha veces no pasa, ya que por alguna extraña razón, muchas personas (incluido yo) han estado reportado que Smart Installer ni siquiera detecta que Qt Components es una dependencia, por lo cual no lo instala y como resultado tenemos una aplicación que directamente no arranca o en el mejor de los casos arranca pero falla miserablemente en las vistas en donde se haga uso de Qt Components.
La solución
La solución ha este problema consiste en decirle a Smart Installer explícitamente que tiene a Qt Components como dependencia, para hacerlo solo debemos agregar las siguientes lineas de código al .pro de nuestro proyecto.
symbian {
components.pkg_prerules +=
"; Dependency to Symbian Qt Quick components"
"(0x200346DE), 1, 0, 0, {"Qt Quick components"}"
DEPLOYMENT += components
}
Espero que este tip les haga ahorrar horas de trabajo y hasta un posible bochazo en la Ovi Store.
Actualización
Tal como comenta (ver abajo) Lucian Tomuta (Chief Engineer en Forum Nokia), hay una solución mas simple y elegante a este problema, solo debemos usar la siguiente línea en el .pro de nuestro proyecto.
# Add dependency to Symbian Qt Components
CONFIG += qt-components
March 19th, 2011
Hace un tiempo escribí sobre lo fácil que es consumir XML con QML, hoy le toca el turno a JSON, consumir JSON con QML requiere un poco mas de trabajo comparado con XML, pero no mucho mas.
Pasemos al código, lo primero que haremos sera crear un archivo data.js que contendrá la lógica que poblara al Model con los datos, para este ejemplo vamos a usar el API de Wikileaks para mostrar un listado con los últimos cables liberados, lo siguiente es agregar el ListModel, el Delegate cuyo código esta al final y no necesita muchos comentarios, el ListView que mostrara los datos y vamos a disparar la función getLatestCables() cuando la view se haya cargado.
main.qml
import QtQuick 1.0
import "data.js" as Data
Rectangle {
width:360
height:640
Component.onCompleted:Data.getLatestCables();
ListModel {
id:cablesModel
}
CablesDelegate {
id:cablesDelegate
}
Item {
id:cablesList
anchors.fill:parent
ListView {
model:cablesModel
delegate:cablesDelegate
anchors.fill:parent
}
}
}
La magia que no es mucha, pasa aquí, esto es simple y puro JavaScript, utilizaremos un XMLHttpRequest para acceder al feed con los datos, luego lo parseamos e iremos agregando uno a uno los datos al Model.
data.js
function getLatestCables(){
var xhr = new XMLHttpRequest;
xhr.open("GET", "http://api.leakfeed.com/v1/cables/latest.json");
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var a = JSON.parse(xhr.responseText);
for (var c in a) {
var i = a[c];
cablesModel.append({identifier: i.identifier, classification: i.classification, office: i.office, subject: i.subject});
}
}
}
xhr.send();
}
CablesDelegate.qml
import QtQuick 1.0
Component {
Rectangle {
border.color:"#b7b7b7"
border.width:1
width:parent.width
height:cableIdentifier.height + cableOffice.height + cableClass.height + cableSubject.height + 10
color:"#fff"
Item {
width:parent.width
height:parent.height
Grid {
rows:4
width:parent.width
anchors.verticalCenter:parent.verticalCenter
anchors.left:parent.left
anchors.leftMargin:5
anchors.right:parent.right
anchors.rightMargin:5
Text {
id:cableIdentifier
text:identifier
font.bold:true
font.pixelSize:18
smooth:true
color:"#333"
}
Text {
id:cableOffice
color:"#0076A3"
text:office
font.pixelSize:18
font.bold:true
smooth:true
}
Text {
id:cableClass
color:"#aa1317"
text:classification
font.pixelSize:16
font.bold:true
smooth:true
}
Text {
id:cableSubject
text:subject
font.pixelSize: 14
wrapMode:Text.WrapAtWordBoundaryOrAnywhere
width:parent.width
smooth:true
color:"#333"
}
}
}
}
}
Si todo sale bien, al correr la demo deberíamos obtener como resultado algo parecido a los que se ve en la siguiente imagen.
November 22nd, 2010
Lo bueno de QML es que permite que casos de uso como una simple vista Maestro Detalle pueda ser mejorada agregando animaciones y layouts personalizados con muy poco esfuerzo.
El ejemplo a implementar es muy simple, vamos a usar un archivo XML como data source y para presentar los datos vamos a usar un GridView en donde seleccionaremos el item a mostrar en en el ListView que hace las veces de details view.
La acción central ocurren en el delegate usado para poblar el GridView el cual espera a que se haga click en alguno de los items, para pasar el index al ListView y disparar la animación que remueve el GridView de la escena para cambiar la opacidad del ListView de 0 a 1 para poder hacerlo visible, por ultimo hay en elemento Text que hará de botón para volver a la vista original.
import Qt 4.7
Rectangle {
width: 360
height: 640
id:container
XmlListModel {
id: oranjeModel
source: "http://localhost:3002/players.xml"
query: "/players/player"
XmlRole {
name: "name"
query: "name/string()"
}
XmlRole {
name: "number"
query: "number/string()"
}
XmlRole {
name: "position"
query: "position/string()"
}
XmlRole {
name: "picture"
query: "picture/string()"
}
XmlRole {
name: "bio"
query: "bio/string()"
}
}
Component {
id: oranjeDelegate
Item {
width: 80
height: 110
Image {
source: picture
width: parent.width
height: parent.height
fillMode: "Stretch"
opacity: 0.5
}
MouseArea {
anchors.fill: parent
focus: true
onClicked: {
oranjeDetails.currentIndex = index
container.state = "detailsView"
}
}
}
}
Component {
id: oranjeDetailsDelegate
Grid {
rows: 3
spacing: 6
Row {
Image {
source: picture
width: 160
height: 230
fillMode: "Stretch"
}
Column {
Text {
text: number
font.pointSize: 24
}
Text {
text: name
font.pointSize: 18
}
Text {
text: position
font.pointSize: 14
}
}
}
Row {
Text {
text: bio
font.pointSize: 8
width: container.width
wrapMode: "Wrap"
}
}
Row {
Text {
text: "Back"
font.pointSize: 12
color: "#ed1e24"
width: container.width
MouseArea {
anchors.fill: parent
onClicked: container.state = ""
}
}
}
}
}
GridView {
id: oranjeList
model: oranjeModel
delegate: oranjeDelegate
width: container.width
height: container.height
cellWidth:90
cellHeight: 120
}
ListView{
id: oranjeDetails
model: oranjeModel
delegate: oranjeDetailsDelegate
opacity: 0
}
states: [
State {
name: "detailsView"
PropertyChanges {
target: oranjeList
x: -container.width
}
}
]
transitions: [
Transition {
from: ""
to: "detailsView"
NumberAnimation {
properties: "x"
easing.type: "OutBounce"
}
PropertyAnimation {
target: oranjeDetails
property: "opacity"
to: 1
}
},
Transition {
from: "detailsView"
to: ""
NumberAnimation {
properties: "x"
easing.type: "OutSine"
duration: 250
}
PropertyAnimation {
target: oranjeDetails
property: "opacity"
to: 0
}
}
]
}