Wenn es nicht möglich ist, Werte nach einem fortlaufendem Index (Ordinalskala) zu klassifizieren, da keine wirklich logische Reihenfolge existiert, kann man auf assoziative Array/HashMaps oder Dictionaries (synonyme Bezeichnung für nominell skalierte Merkmale) zurückgreifen. Dies ist in der Regel aussagekräftiger als ein Index. Diese Datenstruktur bietet beim Zugriff auf ein Element eine sehr hohe Performance. Bei einem Index müßte man alle Elemente der Datenstruktur durchlaufen um einen geeigneten Schlüssel zu finden.
Ansatz
Da VBA nativ keine solche Datenstruktur besítzt, wird auf Microsoft Scripting Runtime Object Library (scrrun.dll) zugegriffen.
Vorraussetzungen
Die DLL Datei hierfür wird automatisch ab Office 2000 mitinstalliert. Im VBA Editor muss unter „Tools -> Verweise/References“ die Microsoft Scripting Runtime option angehakt werden.
Lösung
Dim dictio As Object
Dim dictioItem As Variant
Set dictio = CreateObject("scripting.dictionary")
dictio.Add "key1", "value1"
dictio("key2") = "value2"
dictio("key3") = "value3"
MsgBox "-" & dictio("gibtsnich") & "-"
Dim i As Integer
i = 1
For Each dictioItem In dictio
If dictio(dictioItem) = "" Then Cells(i, 14).Value = "ich sagte das gibts nich"
Cells(i, 12).Value = dictioItem
Cells(i, 13).Value = dictio(dictioItem)
i = i + 1
Next
Von einer Office/VBA-Anwendung aus, soll auf eine Microsoft Access Datenbank (.mdb-Datei) zugegriffen werden.
Vorraussetzungen
Im VBA Editor im Menüpunkt Verweise wird die Option Microsoft ActiveX ADO Objects angehakt.
Lösung
Selektionsanweisung
Public Sub HoleDaten()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim i As Integer
' Datei liegt im aktuellen Projektverzeichnis
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & CurrentProject.Path & _
"\diedatei.mdb"
Set rs = cn.Execute("SELECT * FROM einetabelle")
i = 1
Do While Not rs.EOF
Cells(i, 1).Value = rs.Fields("Feld1")
Cells(i, 2).Value = rs.Fields("Feld2")
Cells(i, 3).Value = rs.Fields("Feld3")
Cells(i, 4).Value = rs.Fields("Feld4")
rs.MoveNext
i = i + 1
Loop
cn.Close
End Sub
Manipulationsanweisung
Public Sub SchubseInMDB()
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=unfug.mdb"
Set rs = cn.Execute("INSERT INTO einetabelle(zweck)VALUES ('Unsinn')")
cn.Close
End Sub
Meine Intention ist es ein kompaktes JQuery-Tutorial zu veröffentlichen, welches (nach diesem Abschnitt) ein Überblick über die wichtigsten JQuery-Funktionen gibt.
Warum JQuery?
JQuery ist eine Javascript-Klassenbibliothek, welche zahlreiche Funktionen für die Selektion im HTML-Baum (DOM) und dessen Manipulation (HTML-Manipulation wie z.B. das Austauschen von TABLE-Tags oder dem dynamischen Hinzufügen von TR-Tags…) enthält.
Es bietet Funktionen für…
Elementselektion im Document Object Model über die Sizzle Selector Engine, die weitgehend den XPATH/CSS-3-Selektoren entspricht
Effekte und Animationen (einblenden, ausblenden, aufklappen, zuklappen…)
Ajax-Funktionalitäten (POST/GET, JSON…)
Zahlreiche frei verfügbare Plug-ins
Wer nutzt JQuery?
Vorwiegend Web-Entwickler, die auf einer etwas niedrigeren Ebene ein Javascript-Framework benötigen. JQuery ist kein High-Level-Framework mit WYSIWYG-Editor.
Moderne AJAX/DHTML-Webanwendungen nutzen immer häufiger High-Level-Frameworks wie GWT, ASP.NET, JSF usw…
Diese Frameworks bieten UI-Komponenten (z.B. Kalender, Tabellen mit DB-Anbindung, Bäume…) an, die herkömmlichen HTML-Seiten durch simples „Draufziehen“ (in einem WYSIWYG-Editor) oder Instanzierung neuer Teile (z.B. in einem UI-Composite-Pattern) die Fähigkeit verleiht sich durch Nutzerinteraktion (z.B. Mausklicks, Tastatureingaben…) zu verändern, ohne die Seite komplett neu zu laden (AJAX/DHTML).
Hierbei findet im Hintergrund eine DOM-Manipulation statt (häufig per AJAX – hier werden z.B. asynchron Abschnitte aus der Datenbank nachgeladen). Der Browser zuckt dabei nicht/Die Seite verschwindet bei einem Klick nicht kurz. Wenn man solche Komponenten selber entwickelt, ist JQuery eine ausgezeichnete Erweiterung zu herkömmlichen Javascript-Funktionen.
Microsoft hat in seiner IDE Visual Studio JQuery integriert und verwendet es bei der Entwicklung von Drag-And-Drop-UI-Komponenten. Aus diesem Grund ist ein Zugriff in Visual Studio auf die Funktionen möglich.
Tutorial
Zu Beginn…
Man benötigt 2 Dinge um mit JQuery zu beginnen
Das Einbinden der Bibliothek (herunterladen oder wie hier googlecontent nutzen)
Die READY-Funktion welche ein Ereignis ist, das sofort auftritt wenn das HTML-Dokument (oder das DOM) zur Manipulation bereit ist
…JQuery ermöglichen…
Hierfür fügen wir zwischen die HEAD-Tags des HTML-Dokuments die folgenden Skripte hinzu:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js">// <![CDATA[
// ]]></script><script type="text/javascript">// <![CDATA[
// Hier kommt die READY-Methode (s.u.) hin
// ]]></script>Hello World
… und die Ready-Methode implementieren
Hierfür gibt es 3 Möglichkeiten
1. Vollständig:
jQuery(document).ready(function() {
// Code hier einfügen
})
2. Mit $ als Alias für die jQuery-Klasse
$(document).ready(function() {
// Code hier einfügen
})
3. Kurzform:
$(function() {
// Code hier einfügen
})
Die READY-Methode ist das erste Event, was auftreten kann. Das Ereignis tritt ein, wenn auf das DOM zugegriffen werden kann. Ein ALERT-Fenster in dieser Methode aufzurufen macht nicht viel Sinn, da es nicht notwendig ist auf das geladene DOM zugreifen zu müssen. Dies könnte auch früher passieren.
Einschub: Was ist DOM?
Beim DOM handelt es sich um ein Modell, welches den Zugriff auf Elemente, Teilbäume oder Teil-XML-Strukturen erlaubt. Grundsätzlich sieht das DOM eine HTML-Dokumentes mit einer Tabelle folgendermaßen aus:
Verwendung des Selektions-Teils für den DOM
Bei den Beispielen werde ich nur noch die Kurzform der READY-Methode nutzen.
$(function() {
// Wähle alle <a>-Tags aus und definiere ein CLICK-Ereignis
$("a").click(function(event){
// wird bei jedem klick auf einen Link aufgerufen
alert('Hello JQuery!');
// verhindert das Aufrufen des in Link-Zieles
event.preventDefault();
});
});
</a>
Wer den obigen Code bereits versteht, hat auch das Selektions-Konzept von JQuery verstanden.
Der erste Aufruf ist immer eine Selektion auf das DOM/HTML-Dokument. Mit $(„a“) (alternativ auch jQuery(„a“) ) wurden alle -Tags im gesamten HTML-Dokument ausgewählt. Das Anhängen von .click hängt dann an die Selektion (also alle Links, bzw. -Tags) ein onClick-Ereignis, welches ein ALERT-Fenster öffnet. Die Methode preventDefault() des Event-Objektes verhindert das Standardverhalten des Links, nämlich den Aufruf der Seite. Somit könnte man für alle Links die Zielseite ändern oder abfangen. Der Funktionskörper function() deklariert eine anonyme, namenlose Methode die ausgeführt wird, wenn das onClick-Ereignis des Links (also des -Tags) aufgerufen wird.
Man kann grundsätzlich alle – oder XML-Tags eines „Baumes“ (nämlich dem DOM) selektieren.
Doch was gibt es für Möglichkeiten der Selektion?
Oberflächlich gesehen gibt es 2 Möglichkeiten…
Kombination aus CSS und XPATH -> $(„div > ul a“)
Nutzung verschiedener Methoden des JQuery-Objektes (z.B. $(„a“).each mit $(this) Referenz
Selektion …
… auf eine TAG-ID
$(„#eineDivID“).addClass(„red“);
Die Raute # sagt der Selektion, das sie ein Attribut id=“..“ suchen soll. Die Selektion beinhaltet dann das Element (z.B. ein DIV). Hier wird diesem DIV die CSS-Klasse .red zugewiesen.
Beispiel:
Div-Inhalt
… auf alle Kind-Elemente aller Tabellen eines Dokumentes
$(„table > tr > td“).addClass(„blue“);Die Selektion wählt alle td-Tags aller Tabellen aus und fügt diesen die CSS-Klasse .blue hinzu. Für Kind-Elemente (Unter-Tags) wird das Ist-Größer-Als-Zeichen > verwendet.
… auf das letzte -Element aller Tabelle eines Dokumentes
Unter Verwendung vom HOVER-Event, welches 2 Parameter onMouseOver/onMouseOut als „functions“ übergeben bekommt, wird ein Mouse-Over-Event auf alle letzten Zeilen aller Tabellen gelegt. Fährt man mit der Maus drüber nimmt dieses die Farben/Styles an, die in der CSS-Klasse .green definiert wurden. Ist die Maus wieder außerhalb der Zeile wird die Klasse entfernt.
… auf alle
-Tags, die ein Class-Attribut haben
$(„p[@class]“).hide()
Selektiert alle p-Tags im Dokument, die ein Attribut für eine CSS-Klasse vorgegeben haben class=“…“ und versteckt diese.
… auf den ersten
-Tag einer Seite
$(„p:eq(0)“)…..
… auf alle sichtbaren DIVs der Seite
$(„div:visible“)…
… auf alle -Tags die unter einem -Tag sind
$(„ul > li“)…. alternativ auch $(„ul/li“)
… auf alle
-Tags mit einer CSS-Klasse „foo“, die einen Link haben
$(„p.foo[a]“)…
… auf alle -Tags mit einem Link mit dem Text „Register“
$(„li[a:contains(‚Register‘)]“)…
… auf alle -Tags mit dem Name „bar“
$(„input[@name=bar]“)…..
… auf alle angehakten/gecheckten Radio-Buttons
$(„input[@type=radio][@checked]“)….
CSS Selektoren
Selektionen nach Stylesheet folgen der Syntax
E:STYLE
wobei E ein HTML-Element/HTML-Tag bezeichnet.
… auf ein
-Element als einziges Kind-Element seines Eltern-Tags
$(„p:only-child“) …
… auf ein
-Tag als letztes Kind-Element seines Eltern-Elements
$(„p:last-child“) …
Mit regulären Vergleichsoperatoren…
… z.B. bei der Suche nach Attributen
… auf alle -Tags, in deren href-Attribut der String /content/gallery vorkommt
Es wird eine Datenstruktur benötigt, die mehrere FilterFunctions unterstützt und mit der mx:ArrayCollection kompatibel ist.
Problem
mx:ArrayCollection besitzt nur die Eigenschaft für eine einzige Filter-Funktion. Möchte man mehrere Filter setzen, muss man komplexe Funktionen mit Filter-Logik implementieren.
Ansatz
Durch die Erweiterung der mx:ArrayCollection wird eine Methode filterFunctions implementiert, welche mehrere Filter entgegennehmen kann. Die erweiterte BjoernsArrayCollection kann in ArrayCollection gecastet oder ggfs. (z.B. durch eine Schleife) befüllt werden.
Lösung
Folgende Klasse erweritert die normale ArrayCollection um mehrere Filter-Funktionen:
package components
{
import mx.collections.ArrayCollection;
public class BjoernsArrayCollection extends ArrayCollection
{
private var _filterFunctions:Array;
public function BjoernsArrayCollection( source:Array = null )
{
super(source);
}
public function set filterFunctions( filtersArray:Array ):void
{
_filterFunctions = filtersArray;
this.filterFunction = complexFilter;
}
public function get filterFunctions():Array
{
return _filterFunctions;
}
protected function complexFilter( item:Object ):Boolean
{
var filterFlag:Boolean = true;
var filter:Function;
for each(filter in filterFunctions)
{
filterFlag = filter( item );
if( !filterFlag ) break;
}
return filterFlag;
}
}
}
Der Filterfunktionen werden so deklariert:
// Result-Methode von Service liefert eine mx:ArrayCollection, die
// anhand mehrerer Kriterien gefiltert wird.
public function getResetableOrganizationsHandler(event:ResultEvent):void
{
// Instanzieren des neuen Objektes
resetableorgas = new BjoernsArrayCollection();
// Deklaration der Filter
resetableorgas.filterFunctions =
[
filterByProductGroup,
filterByCompcode,
filterBySalesdiv,
filterByMarket
];
// Umsortierung in BjoernsArrayCollection
resetableorgas.removeAll();
for each(var item:ResetableOrganizationsVO in event.result)
{
resetableorgas.addItem(item);
}
resetableorgas.refresh();
}
Der Aufbau der Filter-Funktion:
...
// Rückgabe ist true wenn der Vergleich des Eingegebenen (txtCompcode.text)
// mit einem Element der ArrayCollection (item.compcode) passt
private function filterByCompcode( item:Object ):Boolean
{
if( String(item.compcode).indexOf(txtCompcode.text)>-1 )return true;
return false;
}
...
Ggfs. (z.B. in einem mx:TextInput) die Refresh-Methode aufrufen:
Gelegentlich ist es nötig über alle Komponenten eines mx:Canvas-Elements, einem Container oder einer UIComponent zu iterieren.
Beispiele:
* Deaktivieren von allen Controls eines bestimmten Typs (alle Textfelder ausgrauen)
* Neuschriftung von allen Labels
* Deaktivieren aller Reiter
Ansatz
Durch den Typecast in einen DisplayObjectContainer lässt sich über jedes UI-Element iterieren. Eine Startmethode übergibt das Canvas, bzw. das UI-Urelement. Die Rekursionsmethode castet in den kompatiblen Supertyp DisplayObjectContainer und verfügt über Möglichkeiten der Iteration über seine Eigenschaften.
Lösung
// Startmethode übergibt Urelement der Rekursion
public function startSearch():void
{
searchRecursion(this);
}
// Rekursionsmethode ruft sich selbst auf wenn Child-Elemente v.h.
public function searchRecursion(current:DisplayObjectContainer):void
{
for ( var i:Number=0; i< current.numChildren; i++)
{
var child:DisplayObject = current.getChildAt(i);
trace(getQualifiedClassName(child));
var childContainer:DisplayObjectContainer = child as DisplayObjectContainer;
if(childContainer)
{
searchRecursion(childContainer);
}
}
}
[/javascript]
Für die Steuerung kabelloser Geräte (wie z.B. Elektromotoren) wird eine programmierbare, batteriebetriebene Lösung gesucht, die Eingabewerte von Sensoren annehmen und verarbeiten kann.
Ansatz
Durch die Verwendung des programmierbaren Arduino-Boards (arduino.cc) können Motoren mit niedriger Spannung bis zu 5 Volt betrieben werden.
Lösung
Projekt 1: Infrarotsensor
Projekt 2: Entfernungsmesser
Zusammenstellung des Roboters (Projekt 1)
Die folgenden Hardware-Komponenten werden benutzt:
Tamiya Track&Wheel Set
Tamiya Twin-Motor Gear Box (Motorkonfiguration: Type C)
Platine DFRobotShop Rover
Arduino Duemilanove; Prozessor ATMega 328
integrierter Motorcontroller (besetzt Pins 5-8)
USB Schnittstelle
Battery-Fach
Infrarotsensor: DFR0094
Zusammenstellung des Roboters (Projekt 2)
Die folgenden Hardware-Komponenten werden benutzt:
Tamiya Track&Wheel Set
Tamiya Twin-Motor Gear Box (Motorkonfiguration: Type C)
Platine DFRobotShop Rover
Arduino Duemilanove; Prozessor ATMega 328
integrierter Motorcontroller (besetzt Pins 5-8)
USB Schnittstelle
Battery-Fach
IR Range Sensor: SHARP GP2D12 IR Ranger Sensor
Verdrahtung des Roboters (Projekt 1)
Infrarotsensor:
Arduino 5V wird an VCC des Sensors angeschlossen
Arduino GND an Infrarotsensor GND
D wird (hier in meinem Code) auf Digital Pin 11 gelegt
Die folgenden Software-Komponenten werden benutzt:
IDE von Arduino CC
Infrarot-Bibliothek: IRremote.h
Verdrahtung des Roboters (Projekt 2)
Infrarotsensor:
Arduino 5V mit IR Ranger Sensor roter Draht verbinden
Arduino GND mit IR Ranger Sensor schwarzer Draht verbinden
Arduino A2 analoger Eingang mit grünem Draht verbinden
Die folgenden Software-Komponenten werden benutzt:
IDE von Arduino CC
Mein Code (Projekt 1)
#include <IRremote.h> // use the library
int E1 = 6; //M1 Speed Control
int E2 = 5; //M2 Speed Control
int M1 = 8; //M1 Direction Control
int M2 = 7; //M2 Direction Control
int receiver = 11; // pin 1 of IR receiver to Arduino digital pin 11
IRrecv irrecv(receiver); // create instance of 'irrecv'
decode_results results;
void setup()
{
int i;
for(i=5;i<=8;i++)
pinMode(i, OUTPUT);
Serial.begin(9600); // for serial monitor output
irrecv.enableIRIn(); // Start the receiver
}
void loop()
{
if (irrecv.decode(&results)) // have we received an IR signal?
{
Serial.println(results.value, HEX); // display it on serial monitor in hexadecimal
int leftspeed = 255; //255 is maximum speed
int rightspeed = 255;
switch(results.value)
{
case 0x802:
{
forward (leftspeed,rightspeed);
}
break;
case 0x804:
{
left (leftspeed,rightspeed);
}
break;
case 0x806:
{
right (leftspeed,rightspeed);
}
break;
case 0x808:
{
reverse (leftspeed,rightspeed);
}
break;
default:
stop();
break;
}
irrecv.resume(); // receive the next value
} // Your loop can do other things while waiting for an IR command
}
void stop(void) //Stop
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}
void forward(char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}
void reverse (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}
void left (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}
void right (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}
[/javascript]
<h3>Mein Code (Projekt 2)</h3>
[javascript]
// example 32.1 - IR receiver code repeater
// http://tronixstuff.com/tutorials > chapter 32
// based on code by Ken Shirriff - http://arcfn.com
int E1 = 6; //M1 Speed Control
int E2 = 5; //M2 Speed Control
int M1 = 8; //M1 Direction Control
int M2 = 7; //M2 Direction Control
int irReader = 3; // the analog input pin for the ir reader
int irVal = 0; // stores value from Ir reader
void setup()
{
int i;
for(i=5;i<=8;i++)
pinMode(i, OUTPUT);
Serial.begin(9600); // for serial monitor output
}
void loop()
{
int leftspeed = 255; //255 is maximum speed
int rightspeed = 255;
irVal = analogRead(irReader); // read the value from the ir sensor
Serial.println(irVal); // sends ir val to computer
if (irVal>210) // have we received an IR signal?
{
left (leftspeed,rightspeed);
delay(500);
}
else
{
forward (leftspeed,rightspeed);
}
}
void stop(void) //Stop
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}
void forward(char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}
void reverse (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}
void left (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}
void right (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}
Es soll nun mit einer Art Split/Explode wie in PHP die Spalte aufgesplittet werden und einzelne Werte ausgegeben werden
Ansatz
Der folgende Code erstellt eine Funktion, die für eine Datenbank gilt. Kopiert man diesen Code in das SQL Server Management Studio und führt ihn mit F5 aus, erhält die ausgewählte Datenbank die Funktion Split.
Lösung
CREATE FUNCTION [dbo].[split](@String varchar(8000), @Delimiter varchar(12),
@returnItem int)
RETURNS varchar(8000)
AS
BEGIN
DECLARE @id int
DECLARE @idx int
DECLARE @slice varchar(8000)
DECLARE @returnslice varchar(8000)
SET @id = 0
SET @idx = 1
SET @returnslice = null
WHILE @idx!= 0
BEGIN
SET @id = @id + '1'
SET @idx = charindex(@Delimiter,@String)
IF @idx!=0
SET @slice = left(@String,@idx - 1)
ELSE
SET @slice = @String
IF @id = @returnItem SET @returnslice = @slice
SET @String = SUBSTRING(right(@String,len(@String) - @idx),
len(@Delimiter), len(@String))
IF len(@String) = 0 BREAK
END
RETURN @returnslice
END
Aus einem normalen SQL Statement, welches mit EXEC ausgeführt wird, soll eine Ergebnisvariable in dem „normalen“ TSQL-Skript weiterverwendet werden.
Ansatz
Hierzu wird der Rückgabewert des EXEC Statements in eine Variable geschrieben.
Lösung
SET @sql2='SELECT COUNT(*) FROM users WHERE ['+@forsheet+']=1'
IF EXISTS(SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = 'ResultSet')
DROP TABLE ResultSet;
CREATE TABLE ResultSet (mycount int)
INSERT INTO ResultSet
EXEC sp_executesql @sql2
SELECT @isdrin=mycount FROM ResultSet