Tags: Artikel mit dem Tag «App» durchstöbern
Qt4 Designer und Ruby - erste Schritte
Vor Kurzem habe ich ein bisschen mit Ruby herumgespielt und festgestellt, dass es keine ordentliche und aktuelle Kurzeinführung gibt, wie man die Interfaces aus dem Qt4 Designer mit Ruby Programmen verbindet. Darum habe ich die ersten Schritte hier kurz zusammengefasst:
Als erstes installiert man die Qt4-Development-Tools und die Ruby-Qt-Komponenten mit dem Paketmanager.
Interface im Qt4 Designer erstellen
Dann kann man sich ans Buttons zusammenklicken machen. Das Beispielinterface sieht im Qt Designer so aus:
Ich habe zwei QPushButtons und ein QListWidget in Layouts gepackt. Was es an Widgets gibt und was diese können steht in der Qt4 Dokumentation. In der Ruby API heißen die Klassen stets Qt::Name stat QName. Beim Basteln wichtig ist, dass ObjectName irgendwie Sinn hat, weil damit die Widgets dann benutzt werden können.
Rubycode mit rbuic erstellen
Als nächstes muss man die vom Designer erzeugte XML-Datei mit der Endung .ui in Ruby-Code umwandeln. Dazu gitb es rbuic bzw. rbuic4:
rbuic4 Sample.ui -o Sample.ui.rb
Jetzt haben wir ein Rubyscript in dem das Interface erstellt wird.
Interface in Rubyscript einbinden
Jetzt ist es Zeit dem Interface etwas Leben einzuhauchen. Dazu verbindet man die Signale - wer Webinterfaces Programmiert kennt das als „Events“ - mit den Entsprechenden Slots, die so ähnlich wie callbacks funktionieren. Das geht recht fix mit QMetaObject::connectSlotsByName. Damit dies funktioniert müssen die Funktionen, die aufgerufen werden sollen das Namensmuster on_ObjectName_Signal einhalten, wobei der ObjectName vorher im Designer festgelegt wurde und das Signal heißt z.B. triggered.
Wie man die GUI-Komponente in der Anwendung benutzt, z.B. hier durch Subclassing, und anderes will ich direkt am Beispiel erklären:
#!/usr/bin/ruby
#Laden der Qt-Klasse:
require 'Qt'
#Manchmal auch:
#require 'Qt4'
#Laden des generierten Interfaces:
require 'Sample.ui.rb'
#Initialisieren der Anwendung
app = Qt::Application.new ARGV
#Eine Klasse, um das Verhalten des Interfaces festzulegen:
class AppCommunicate < Qt::MainWindow
#Die Liste der Slots
#Sie werden von setupUi automatisch verbunden
slots :on_actionQuit_triggered, :on_add_clicked, :on_rem_clicked
def initialize
puts "init"
@item_count=0
#Da wir vererben initialisieren wir so:
super
#Jetzt erstellen wir das Interface
@ui=Ui_MainWindow.new
#Und weisen es dem MainWindow zu
@ui.setupUi self
#Man könnte Slots auch manuell verbinden:
#connect a.actionQuit, SIGNAL('triggered()'), $qApp, SLOT('quit()')
end
#Ein Handler für das Beenden:
def on_actionQuit_triggered
puts "Shutting down."
#So wird die Anwendung gestoppt:
$qApp.quit
end
# "add" ist der name des Buttons, bei click wird dieses signal gesendet
def on_add_clicked
puts "Adding item"
#Es gibt attr_readers für alle Widgets
#So können wir ihre Methoden aufrufen
@ui.listWidget.addItem("Hallo Welt ##{@item_count} at #{Time.now.ctime}")
#Hier könnten z.B. Daten der Anwendung ausgegeben werden
#Zu demonstrationszwecken nummerieren wir die Einträge sichtbar
@item_count+=1
end
def on_rem_clicked
puts "Removing item"
#In cpp könten wir die items deleten
#Aber in ruby loopen wir über die markierten indizes
@ui.listWidget.selectedIndexes.each do |i|
#und nehmen sie aus der Liste
@ui.listWidget.takeItem i.row
#da wir keine Referenz speichern löscht sie der GC
end
end
end
#Wir erstellen eine Instanz unseres Verhaltens
wdg=AppCommunicate.new do |w|
#Wir müssen das Interface zeigen
#Wird auch alle child-widgets zeigen
w.show
end
#Hier wird die GUI-Schleife gestartet:
app.exec
#TADA!
Wer das ganze ausprobieren will, kann sich die Beispieldateien hier herunterladen:
Ich hoffe das war hilfreich, ich finde es doch hin und wieder ganz nett ein Interface zu haben, vor allem für Scripte, die länger laufen und interaktiv sein sollen.
Symmetrisch Zeichnen
Neben Symmetrie in der Natur bin ich auch begeistert von den Symmetrien, die der Computer erstellen kann. Und was wäre diese Symmetrie ohne die, für den Computer typische, Interaktivität? Also habe ich (zunächst mit Processing aber dann mit) HTML5-Canvas eine kleine Javascript-Sache gebastelt, mit der man direkt im Browser symmetrisch zeichnen kann.
Irgendwie macht das Spaß und, naja, es sieht auch oft erstaunlich gut aus.
Zum Zeichenbrett. Tipp: Man kann in der URL die Anzahl der Punkte verändern.
Und hier noch ein Video:
Drawing Symmetry (6)
Viel Spaß beim Malen!
XMPP (Jabber) mit Ruby am Beispiel FelicianXMPPBot

FelicianXMPPBot in action
Das Protokoll XMPP für den (Nahezu-)Echtzeitaustausch von XML-Nachrichten (meist verwendet für IM, als „Jabber“) steht in Konkurrenz und Verbindung mit einigen aktuell mehr oder weniger neuen Technologien, die mit XML und realtime zu tun haben, wie RSS/Atom pings, realtime web oder AJAX. Und ein paar Spielereien auf diesem Gebiet können sicher nicht schaden, also habe ich mit XMPP etwas herumgebastelt.
Weil dies mit PHP irgendwie seltsam wäre und David Strohmayers Text und Präsentation über XMPP mit Java noch nicht existierte, habe ich das ganze mit Ruby gebastelt, da gibt es nämlich den Gem xmpp4r, der mit vielen Beispielen kommt. So konnte ich mal ein bisschem mit Ruby herumspielen. (Zwei Fliegen mit einer Klappe usw.)
Aus den Experimenten ist ein kleiner Server geworden, der einen Jabber-Bot betreibt und über ein einfaches TCP-Protokoll erreicht werden kann, sodass aus allen TCP-Fähigen Skripten (bash mit netcat, PHP…) einfach Nachrichten an einen Jabber-Endpunkt versendet werden können.
Code und Funktionalität bestehen aus drei Teilen:
Die Klasse Netx kümmert sich um den TCP-Server und parst das einfache Protokoll: Man schickt Zeilen und beendet einzelne Nachrichten mit einem Punkt, und die Verbindung (und damit auch die aktuelle Nachricht) mit zwei Punkten. So lassen sich die TCP-Clients leicht implementieren.
Die Klasse XmppRoute bietet nur ein wenig Grundfunktion für den Jabber-Bot. Sie vereinfacht Verbinden und Senden noch weiter, zudem extrahiert sie beim Empfang einer Nachricht einen Befehlsteil.
Der Rest kümmert sich um die Verbindung der beiden Komponenten und um das Parsen von Startup-Parametern.
Aber genug der vielen Worte, jetzt folgt der Code:
jabot.rb
#!/usr/bin/ruby
# Felician 0.9 - XMPP Wrapper
# (c) 2009 by Bernhard Häussner
# Licence: GPLv2+ http://www.gnu.org/licenses/gpl-2.0.txt
#
# This jabber wrapper will recieve messages via simple tcp.
#
# Quit by sending "exit" via jabber.
# Send "info" via jabber to get running parameters.
# Send "feedback [msg]" via jabber to post from jabber.
# Connect to specified port and send messages terminated by lone "." in a line to post via TCP.
# Send a line with ".." to quit connection.
#
# Based on xmpp4r-0.5/data/doc/xmpp4r/examples/basic
#
require 'optparse'
require 'XmppRoute'
require 'Netx'
class FelicianXMPPBot
def start(his_JID,my_txt_JID,my_password,listen_port)
puts "FELC: Started. Sending to #{his_JID} from #{my_txt_JID} listening to #{listen_port}."
my_JID=JID.new(my_txt_JID)
netx=Netx.new
XmppRoute.connect(my_JID,my_password) do
on_recieve do |from,cmd,param|
if from.strip.to_s.eql?his_JID then
case cmd.downcase
when 'exit' then
send(from,"-> I've got to go!")
puts "FELC: Got shutdown signal, waiting for children to terminate..."
netx.halt
when 'feedback' then send(from,param)
when 'info'then send(from,"-> Felician sending to #{his_JID} listening to #{listen_port}. ")
else send(from,"-> I don't know: #{cmd} #{param}")
end
else
puts "XMPP: Ignored a message. "
send(from,"Hi, #{from.strip.to_s}. Sorry, could not be deliverd. Try again later! ")
end
end
netx.on_sended do |msg|
send(his_JID,msg.strip)
puts "XMPP: Client message sent. "
end
netx.listen(listen_port)
end
puts "FELC: Shutting down. "
end
end
if $0 == __FILE__
#defaults:
listen_port=2000
his_JID = "bot_admin@gmx.de"
my_txt_JID = "i_am_a_bot@jabber.ccc.de/felician"
my_password = "top_secret"
# cli settings
OptionParser.new do |opts|
opts.banner = 'Usage: ruby jabot.rb -j jid/ressource -p password -t reciever_jid -l port'
opts.separator ''
opts.on('-j', '--jid JID', 'sets the sender jid') { |j| my_txt_JID = j }
opts.on('-p', '--password PASSWORD', 'sets the sender password') { |p| my_password = p }
opts.on('-t', '--to-jid JID', 'sets the message reciever') { |t| his_JID = t }
opts.on('-l', '--listen PORT', 'sets the server listen port') { |l| listen_port = l }
opts.on_tail('-h', '--help', 'Show this message') {
puts opts
exit
}
opts.parse!(ARGV)
end
FelicianXMPPBot.new.start(his_JID,my_txt_JID,my_password,listen_port)
end
XmppRoute.rb
require 'rubygems'
require 'xmpp4r/client'
include Jabber
class XmppRoute
def initialize(jid,pwd)
@cmd=Proc.new { |a,b,c| puts "XMPP: No reciever. " }
@cl = Client.new(jid)
@cl.connect
@cl.auth(pwd)
@cl.send(Presence.new)
puts "XMPP: Connected! send messages to #{jid.strip.to_s}."
@cl.add_message_callback { |m| process m }
end
def close
@cl.close
end
def on_recieve(&cb)
@cmd=cb
end
def send(to,mes)
ms = Message.new(to,mes) # [_CY4_L8-R_4LLY-G4T3-R_]
ms.type = :chat
@cl.send(ms)
end
private
def process(m)
puts "XMPP: Got msg of type #{m.type} / #{m.name} with -#{m.body}- "
if m.type == :chat && ! m.body.nil?
index=(m.body.index(" ") || 0)-1
com=m.body[0..index]
param=(index==-1?"":m.body[index+2..-1])
puts "XMPP: Call #{com} with --#{param}-- (caused from #{m.from})"
@cmd.call(m.from,com,param)
end
end
def self.connect(jid,pwd,&block)
bot=XmppRoute.new(jid,pwd)
bot.instance_eval(&block)
bot.close
end
end
Netx.rb
require 'socket' # Get sockets from stdlib
class Netx
def initialize; @run=true; end
def listen(port)
puts "NETX: Bind to Port #{port}"
#server = TCPServer.open(port)
#only local:
server = TCPServer.open("127.0.0.1",port) # Socket to listen
while @run
# this timeout allows us to kill this lop every few seconds...
begin
session = Timeout::timeout(10) { server.accept }
Thread.start(session) { |c| connection c }
rescue TimeoutError
#puts "NETX: Refreshing TCPServer."
end
end
end
def on_sended(&cb); @client_cb=cb; end
def halt; @run=false; end
private
def connection (client)
puts "NETX: Client conntected..."
client.puts("-- Hello on Felician at #{Time.now.ctime}. ") # Send the helo & time to the client
conn_open=true;
msg_buffer="";
while conn_open do
l = client.gets
if (l.strip.eql?'..') || (l.strip.eql?'.') then
puts "NETX: Client issued a message..."
client.puts("-- accepted. ")
@client_cb.call(msg_buffer)
msg_buffer="";
conn_open=false if l.strip.eql?'..'
else
msg_buffer << l
end
end
ensure
client.puts "-- Closing the connection. Bye!"
puts "NETX: Client disconnect. "
client.close # Disconnect from the client
end
end
Erwartet nicht zu viel von dem Code, ist schließlich mein erster Ruby-Code, abgesehen von einigen Hello-World-Sachen. Funktioniert dafür allerdings erstaunlich gut und könnte sich schon fast eigenen, um z.B. einen Systemadministrator über wichtige Aktivitäten und Warnungen aus den verschiedensten Programmen und Wartungsscripten schnell zu informieren.
Man beachte vielleicht noch das alles in dem Code, was in anderen Programmiersprachen als schlechter Stil gälte, hier eher „the ruby way“ ist ;).
Benutzung
Eine Nachricht von der Shell schicken:
09:15 burny@home:~> echo -e "Hallo Welt\n.." | netcat localhost 2000 -- Hello on Felician at Tue Dec 15 21:16:02 2009. -- accepted. -- Closing the connection. Bye!
Mal sehen, ob ich das Ganze noch weiter entwickle, meistens ist doch das Senden einer ganz normalen eMail einfacher.
Javascript Library Builder

JS-Build
Es gibt einige Methoden Javascript auf HTML-Seiten einzubinden. Ein Block im <body>, in onclick-Attributen und ähnlichem, oder als Verknüpfungen im <head> aber am besten in einer externen Datei, die nach dem HTML-Dokument geladen wird. Nur will man beim Entwickeln die einzelnen Javascript-Teile meist in getrennte Dateien legen und auf der Seite dann möglichst viel in eine (am besten möglichst kleine) Datei packen, um Requests zu sparen. Dieses Problem kann der Javascript Library Builder lösen, ein recht kurzes Shell-Script, welches eine Sammlung von .js-Dateien in wenige Dateien minimiert.
Man nehme zum Beispiel eine solche Dateistruktur:
lib/
php/...
js_frontend/
00_jQuery.js
01_jQ_plugin.js
02_effekte.js
licence.txt
js_backend/
03_ajaxCalls.js
Der Scriptaufruf wäre so einfach wie:
jslibbuild.sh -o build lib/js*
Ich habe auf dieser Seite 27 einzelne Dateien, die ich in zwei Javascript Dateien packe, nämlich für die Seite und für das CMS. Diese Beispiel-Dateistruktur würde jetzt in den zwei Dateien js_frontend.min.js und js_backend.min.js im Ordner build resultieren. Der Datei js_frontend.min.js würde zusätzlich nach dem minimieren mit jsmin die Datei licence.txt vorgehängt, sodass z.B. in Kommentaren (die von jsmin geschluckt werden) vermerkte Autorenhinweise erhalten bleiben, was unter anderem bei den CC-Lizenzen nötig ist.
Dazu akzeptiert das Script die optionale Option -l nach der der Name der Lizenz-Dateien angegeben wird. Eine weitere optionale Option ist -c, um das build-Verzeichnis vor dem Anlegen der neuen Dateien zu löschen. Das ist nötig, wenn ein ganzer source-Ordner gelöscht wird, aber dringend zu vermeiden, wenn weitere Dateien im build-Ordner liegen. Hier noch ein Beispiel:
jslibbuild.sh -c -l gpl.txt -o /srv/www/htdocs/js ~/web/lib/js/*
Das Script benötigt jsmin, steht unter GPLv2+ und kann hier heruntergeladen werden:
Zum „installieren“ einfach in den Ordner ~/bin kopieren. Das Script ist eigentlich ziemlich einfach, kann aber doch einiges an Arbeit ersparen.
Twitter Bookmarklet III
For twitter users: Here's an easy-to-use toolbar button for your browser that substitutes the URL shortening and copy-pasting for you. There's no installation, I don't want to know your twitter login or password, and it will shorten the URL using bit.ly.
The bookmarklet will:
- Receive a short URL from the bit.ly API
- Open up your twitter homepage in a new tab (Firefox) or in a pop up with the short URL and the page title included in the textarea
- (Or take you to the twitter login page, which will then redirect)
To install just drag this link/button into your browser's bookmarks toolbar:
The bookmarklet is even supporting flickr-Photos (using their short URL like http://flic.kr/p/6qxGR2) and other web sites (Ars technica, PHP-Manual, this blog...) if they provide own shortening services.
The code is a bit inspired by John Resig's „retweet“ button but it's not on the page you are viewing, but in your browser's toolbar, so you don't rely on webmasters cluttering their designs with social bookmarking services' buttons.
For IE-Users: You will have to right-click on the link and choose save bookmark. After that, you will be warned, because it's not a simple link, but a bookmarklet.




