O qooxdoo é um framework javascript universal usado para criar aplicações interativas, aplicativos para dispositivos móveis, aplicações web single-page, entre outros.
Irei repassar aqui um tutorial da própria qooxdoo para criar uma pequena aplicação web single-page contendo um cliente do twitter onde o usuário possa ler tweets públicos e poder postar tweets também.
No tutorial estarei utilizando o windows 7.
Primeiro passo é baixar o python para poder usar a poderosa ferramenta de gerar aplicações.
Link: http://www.activestate.com/activepython/downloads
Agora é só baixar a SDK do qooxdoo.
Link: http://downloads.sourceforge.net/qooxdoo/qooxdoo-2.0.1-sdk.zip
Instale o python, após a instalação extraia a sdk e coloque em uma pasta de sua preferência, aqui coloquei em C:\qooxdoo-2.0.1-sdk. Antes de começarmos a criar nossa aplicação vamos colocar o python na lista de variáveis de ambiente do windows.
Abra o cmd e digite o comando set PATH=C:\Python27; %PATH% sem aspas, onde C:\Python27 é o diretório de instalação do python.
Para criar uma aplicação é muito simples basta rodar o script create-application.py localizado em tool/bin na pasta da SDK, ainda no cmd digite: C:\qooxdoo-2.0.1-sdk\tool\bin\create-application.py –name=twitter
Isto irá criar uma aplicação chamada twitter contendo toda a estrutura de diretórios e configurações necessárias para o funcionamento da mesma, agora basta executar o comando cd twitter e entrar na pasta da aplicação agora digitando o comando generate.py para gerar os scripts de sua aplicação.

Depois de gerar os scripts, crie na pasta source/class/twitter um arquivo chamado MainWindow.js e dentro deste arquivo escreva o seguinte código.
qx.Class.define("twitter.MainWindow",
{
extend : qx.ui.window.Window,
construct : function()
{
this.base(arguments, "twitter");
}
});
O que acabamos de fazer com esse código foi definir uma classe chamada “twitter.MainWindow” que extende da classe Window do qooxdo, o construtor da classe sobrescreve o construtor da super-classe passando como parâmetro o título da janela, no caso “twitter”. Salve este arquivo e abra o Application.js e abaixo do bloco de comentário coloque o seguinte código.
var main = new twitter.MainWindow();
main.open();
Nós apenas instânciamos nossa classe MainWindow e executamos o método open. Antes de testarmos nossa aplicação no navegador devemos gerar mais uma vez os scripts, já que estamos utilizando a classe Window do qooxdoo como dependência, então execute mais uma vez o comando generate.py no cmd e abra o arquivo index.html para visulaizar a aplicação no navegador. Você deve ver algo parecido com isto:
Vamos agora fazer algumas alterações na interface gráfica da nossa janela, ainda no Application.js acrescente este código:
main.moveTo(50, 30);
movemos nossa janela para uma nova localização. Voltando agora para o arquivo MainWindow.js coloque o seguinte código no construtor da janela:
//Esconder os botões da janela
this.setShowClose(false);
this.setShowMaximize(false);
this.setShowMinimize(false);
// ajustar o tamanho da janela
this.setWidth(250);
this.setHeight(300);
Atualize a página e veja as mudanças. Abaixo coloque o seguinte código:
// add o layout
var layout = new qx.ui.layout.Grid(0, 0);
this.setLayout(layout);
// toolbar
var toolbar = new qx.ui.toolbar.ToolBar();
this.add(toolbar, {row: 0, column: 0, colSpan: 2});
// lista
var list = new qx.ui.form.List();
this.add(list, {row: 1, column: 0, colSpan: 2});
this.setContentPadding(0);
layout.setRowFlex(1, 1);
layout.setColumnFlex(0, 1);
// Botão recarregar
var reloadButton = new qx.ui.toolbar.Button("Recarregar");
toolbar.add(reloadButton);
// textarea
var textarea = new qx.ui.form.TextArea();
this.add(textarea, {row: 2, column: 0});
// Botão postar
var postButton = new qx.ui.form.Button("Postar");
this.add(postButton, {row: 2, column: 1});
reloadButton.setToolTipText("Recarregar os tweets.");
textarea.setPlaceholder("Digite sua mensagem aqui...");
postButton.setToolTipText("´");
Na linha 2 criamos um layout do tipo grid e setamos ele em nossa janela, na linha 6 criamos uma toolbar e adicionamos ela a nossa janela já preparada para receber os componentes e ajusta-los em forma de grade, mesma coisa com a lista da linha 10. Na linha 13 setamos o padding da janela no valor 0, já as linhas 14 e 15 servem para deixar a lista flexível. Na linha 18 é adicionado um botão na toolbar para recarregar os tweets e nas linhas seguintes são adicionados um textarea e outro botão à janela, nas linhas finais são dados alguns toques para finalizar a nossa janela como mostrar pra que serve o botão quando o mouse fica sobre ele.
No final do construtor acrescente este código:
event :
{
"reload" : "qx.event.type.Event",
"post" : "qx.event.type.Data"
}
E abaixo de postButton.setToolTipText(“Poste esta mensagem no twitter.”); coloque:
reloadButton.addListener("execute", function() {
this.fireEvent("reload");
}, this);
postButton.addListener("execute", function() {
this.fireDataEvent("post", textarea.getValue());
}, this);
Até agora nosso arquivo MainWindow.js está assim:
qx.Class.define("twitter.MainWindow",
{
extend : qx.ui.window.Window,
construct : function()
{
this.base(arguments, "twitter", "twitter/t_small-c.png");
// hide the window buttons
this.setShowClose(false);
this.setShowMaximize(false);
this.setShowMinimize(false);
// adjust size
this.setWidth(250);
this.setHeight(300);
// add the layout
var layout = new qx.ui.layout.Grid(0, 0);
layout.setRowFlex(1, 1);
layout.setColumnFlex(0, 1);
this.setLayout(layout);
this.setContentPadding(0);
// toolbar
var toolbar = new qx.ui.toolbar.ToolBar();
this.add(toolbar, {row: 0, column: 0, colSpan: 2});
// reload button
var reloadButton = new qx.ui.toolbar.Button("Reload");
toolbar.add(reloadButton);
reloadButton.setToolTipText("Reload the tweets.");
reloadButton.addListener("execute", function() {
this.fireEvent("reload");
}, this);
// list
var list = new qx.ui.form.List();
this.add(list, {row: 1, column: 0, colSpan: 2});
// textarea
var textarea = new qx.ui.form.TextArea();
this.add(textarea, {row: 2, column: 0});
textarea.setPlaceholder("Enter your message here...");
textarea.addListener("input", function(e) {
var value = e.getData();
postButton.setEnabled(value.length < 140 && value.length > 0);
}, this);
// post button
var postButton = new qx.ui.form.Button("Post");
this.add(postButton, {row: 2, column: 1});
postButton.setToolTipText("Post this message on twitter.");
postButton.addListener("execute", function() {
this.fireDataEvent("post", textarea.getValue());
}, this);
postButton.setWidth(60);
postButton.setEnabled(false);
},
events :
{
"reload" : "qx.event.type.Event",
"post" : "qx.event.type.Data"
}
});
Vamos agora para nosso arquivo Application.js e escrever este código:
main.addListener("reload", function() {
this.debug("reload");
}, this);
main.addListener("post", function(e) {
this.debug("post: " + e.getData());
}, this);
Até agora nosso arquivo Application.js está desta forma:
/* ************************************************************************
Copyright:
License:
Authors:
************************************************************************ */
/* ************************************************************************
#asset(twitter/*)
************************************************************************ */
/**
* This is the main application class of your custom application "twitter"
*/
qx.Class.define("twitter.Application",
{
extend : qx.application.Standalone,
/*
*****************************************************************************
MEMBERS
*****************************************************************************
*/
members :
{
/**
* This method contains the initial application code and gets called
* during startup of the application
*
* @lint ignoreDeprecated(alert)
*/
main : function()
{
// Call super class
this.base(arguments);
// Enable logging in debug variant
if (qx.core.Environment.get("qx.debug"))
{
// support native logging capabilities, e.g. Firebug for Firefox
qx.log.appender.Native;
// support additional cross-browser console. Press F7 to toggle visibility
qx.log.appender.Console;
}
/*
-------------------------------------------------------------------------
Below is your actual application code...
-------------------------------------------------------------------------
*/
var main = new twitter.MainWindow();
main.moveTo(50, 30);
main.open();
main.addListener("reload", function() {
this.debug("reload");
}, this);
main.addListener("post", function(e) {
this.debug("post: " + e.getData());
}, this);
}
}
});
Gere mais uma vez os scripts e veja como está a aplicação, ela deve está parecida com esta imagem:

Agora vamos dar início a interação com o twitter, crie outro arquivo na mesma pasta que Application.js e MainWindow.js chamado de TwitterService e inicialmente escreva o seguinte código:
qx.Class.define("twitter.TwitterService",
{
extend : qx.core.Object,
members :
{
}
});
Diferente da classe MainWindow, esta não precisa extender de uma classe complexa como a Window, ela extende da classe Object que é uma classe simples. Acrescente este código antes de members:
properties : {
tweets : {
nullable: true,
event: "changeTweets"
}
},
events : {
"postOk" : "qx.event.type.Event"
},
E dentro de members o seguinte código:
__store : null,
fetchTweets : function() {
if (this.__store == null) {
var url = "http://api.twitter.com/1/statuses/public_timeline.json";
this.__store = new qx.data.store.Jsonp(url, null, "callback");
this.__store.bind("model", this, "tweets");
} else {
this.__store.reload();
}
},
post : function(message)
window.open("http://twitter.com/?status=" + encodeURIComponent(message));
}
}
Aqui em cima criamos uma propriedade chamada tweets, que pode ser nulo e possui um evento chamado “changeTweets“. Criamos também um evento chamdo “postOk” do tipo “qx.event.type.Event” além dos membros, um atributo privado chamado “__store” (dois “__” fazem com que o atributo torne-se privado) e dois métodos o fetchTweets e o post, fetchTweets responsável pela captura de tweets públicos do twitter e post por postar o conteúdo no twitter.
Vamos voltar agora ao nosso arquivo Application.js e criar uma instância da nossa classe TwitterService e digite o seguinte código:
var service = new twitter.TwitterService();
E troque este trecho de código:
main.addListener("reload", function() {
this.debug("reload");
}, this);
Por esse:
main.addListener("reload", function() {
service.fetchTweets();
}, this);
E este:
main.addListener("post", function(e) {
this.debug("post: " + e.getData());
}, this);
Por este:
main.addListener("post", function(e) {
service.post(e.getData());
}, this);
Vamos agora para o arquivo MainWindow.js e criar um acessor para a lista, então troque onde tem var list = new qx.ui.form.List();por:
this.__list = new qx.ui.form.List();
E onde estiver list trocar por this.__list, faça o mesmo para textarea. Ainda no mesmo arquivo abaixo de events crie dois membros o __list e o __textarea ficando assim:
events :
{
"reload" : "qx.event.type.Event",
"post" : "qx.event.type.Data"
},
members : {
__list : null,
__textarea : null,
Ainda dentro de members crie duas funções a getList e a clearPostMessage com o seguinte conteúdo:
getList : function() {
return this.__list;
},
clearPostMessage : function() {
this.__textarea.setValue(null);
}
O nosso arquivo MainWindow agora está assim:
qx.Class.define("twitter.MainWindow",
{
extend : qx.ui.window.Window,
construct : function()
{
this.base(arguments, "twitter", "twitter/t_small-c.png");
// hide the window buttons
this.setShowClose(false);
this.setShowMaximize(false);
this.setShowMinimize(false);
// adjust size
this.setWidth(250);
this.setHeight(300);
// add the layout
var layout = new qx.ui.layout.Grid(0, 0);
layout.setRowFlex(1, 1);
layout.setColumnFlex(0, 1);
this.setLayout(layout);
this.setContentPadding(0);
// toolbar
var toolbar = new qx.ui.toolbar.ToolBar();
this.add(toolbar, {row: 0, column: 0, colSpan: 2});
// reload button
var reloadButton = new qx.ui.toolbar.Button("Reload");
toolbar.add(reloadButton);
reloadButton.setToolTipText("Reload the tweets.");
reloadButton.addListener("execute", function() {
this.fireEvent("reload");
}, this);
// list
this.__list = new qx.ui.form.List();
this.add(this.__list, {row: 1, column: 0, colSpan: 2});
// textarea
this.__textarea = new qx.ui.form.TextArea();
this.add(this.__textarea, {row: 2, column: 0});
this.__textarea.setPlaceholder("Enter your message here...");
this.__textarea.addListener("input", function(e) {
var value = e.getData();
postButton.setEnabled(value.length < 140 && value.length > 0);
}, this);
// post button
var postButton = new qx.ui.form.Button("Post");
this.add(postButton, {row: 2, column: 1});
postButton.setToolTipText("Post this message on twitter.");
postButton.addListener("execute", function() {
this.fireDataEvent("post", this.__textarea.getValue());
}, this);
postButton.setWidth(60);
postButton.setEnabled(false);
},
events :
{
"reload" : "qx.event.type.Event",
"post" : "qx.event.type.Data"
},
members : {
__list : null,
__textarea : null,
getList : function() {
return this.__list;
},
clearPostMessage : function() {
this.__textarea.setValue(null);
}
}
});
Vamos voltar agora para o Application.js e criar um controle para nossa lista com o seguinte código:
var controller = new qx.data.controller.List(null, main.getList());
controller.setLabelPath("text");
controller.setIconPath("user.profile_image_url");
controller.setDelegate({
configureItem : function(item) {
item.getChildControl("icon").setWidth(48);
item.getChildControl("icon").setHeight(48);
item.getChildControl("icon").setScale(true);
item.setRich(true);
}
});
Agora vamos chamar o método bind para vincular o controle com o modelo vindo do twitter e chamar os tweets quando iniciar a aplicação:
service.bind("tweets", controller, "model");
service.fetchTweets();
Gere novamente os scripts e recarregue a página e teste nosso aplicativo funcionando.

Na hora de postar você será redirecionado para o site do twitter para autenticação, pois é muito complicado fazer a autenticação pelo aplicativo, pois o twitter só usa o OAuth para autenticar os usuários. Para baixar o projeto clique aqui.
Fonte: qooxdoo Docs