/* Applet.java Created on 25. Dezember 2004, 22:02 * @author pascal * * der client randomiziert die abfolge der antwort-wavs und setzt die reihenfolge am ende wieder zurück, damit * die ergebnisse verglichen werden können. richtig schön ist das applet nicht programmiert: das ding ist zu * monolithisch. es lässt sich aber recht einfach z.b. über die änderung des html-parameters "Fragenanzahl" * an eigene bedürfnisse anpassen. Ansonsten bleibt das vorhaben: eine woche zeit * würde wohl benötigt, um ein kleines layout-wysiwyg zu basteln, mit dem sich online-experimente, die so * ähnlich sind wie das gerade besprochene, auch von einem laien erstellt werden könnten. */ import java.applet.AudioClip; import java.awt.Button; import java.awt.Checkbox; import java.awt.Color; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Panel; import java.awt.TextArea; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.security.AccessControlException; public class AbfrageClient extends java.applet.Applet implements ActionListener { // werte werden in der init vom html-dok () bezogen private int anzahlFragen,anzahlAntworten,serverport; String hostname; int fragenNummer; // aktuelle frage int antwortNummer; // aktuelle antwort // die ergebnis-matrix. // in [0][][] stehn die randomisierten sounds, in [1][][] die ergebnisse int[][][] ergebnisse;// = new int[2][anzahlFragen][anzahlAntworten]; Color[] c = new Color[5];//degree of evaluation Checkbox checkbox[][]; //= new Checkbox[anzahlAntworten][c.length]; // das datenfeld für den fragebogen String fragebogen; // erster Text, vor dem drücken des "persönl. daten senden"-knopfes String fragebogenTexte = new String( "Name: \nGeschlecht(w/m): \nAlter: \nIst Deutsch Deine Muttersprache(j/n): \nWenn ja, in welcher Region Deutschlands bist du aufgewachsen ?: \nKlick auf 'Persönliche Daten senden' wenn Du alles beantwortet hast."); // hilfstext während des experiments String iniText = new String( " Willkommen zum Intonationsexperiment v2.3 ! \nKlicke auf die aktuelle Frage, um die Frage zu hören.\nBewerte jede der 5 Antworten: wie hört sich die Betonung\nder jeweiligen Antwort auf die Frage an?\nDrücke die Knöpfe neben den Antworten:\nVon dunkelrot='passt überhaupt nicht' bis dunkelgrün='passt sehr gut'.\n\nIst alles zu Deiner Zufriedenheit bewertet, drücke den 'senden'-Knopf."); // hilfstext beim Probedurchlauf String probeText = new String( "Bevor das Experiment beginnt, erfolgt ein Probedurchlauf,\num Dich mit der Bedienung des Programms vertraut zu machen.\nSchritt 1: Höre dir die Probefrage an: klicke auf 'Probefrage'.\nSchritt 2: Höre Dir die Antwort1 an: klicke den Knopf 'Antwort1'.\nBewerte sie durch Anklicken der farbigen Felder:\nRot=passt überhaupt nicht bis Dunkelgrün=passt sehr gut.\nSchritt 3: Höre Dir Antwort2 an und bewerte sie usw... \nWenn Du alle 5 Antworten bewertet hast beginnt das Experiment.\nKlicke 'weiter'.\nWenn Du Dir Deine vorigen Bewertungen nochmal anschauen und ggf.\nändern willst, verwende den Knopf 'zurück'."); // sound handling AudioClip audioClipAntworten[]; //= new AudioClip[anzahlAntworten]; AudioClip audioClipFragen[];// = new AudioClip[anzahlFragen]; static GridBagConstraints gridBagConstraints = new GridBagConstraints(); Panel interactionPanel = new Panel(); Panel navigationPanel = new Panel(); TextArea textPanel = new TextArea(); Panel abfragePanel = new Panel(); Panel fragePanel = new Panel(); Panel antwortPanel = new Panel(); Panel checkPanel = new Panel(); Button zurück = new Button("<< zurück"); // frage-- Button weiter = new Button("weiter >>"); // frage ++ Button pdatenSenden = new Button("Persönliche Daten senden"); Button senden = new Button("senden"); // für auswertung Button frage[];// = new Button[anzahlFragen]; Button antwort[];// = new Button[anzahlAntworten]; Frame buttonFrame = new Frame(); /** * Initialization method that will be called after the applet is loaded into the browser. */ public void init() { // werte werden aus dem html-dok geladen () hostname =getParameter("Hostname"); serverport=Integer.valueOf(getParameter("Serverport")).intValue(); anzahlFragen = Integer.valueOf(getParameter("Fragenanzahl")).intValue()+1; anzahlAntworten = Integer.valueOf(getParameter("Antwortanzahl")).intValue(); ergebnisse = new int[2][anzahlFragen][anzahlAntworten]; checkbox = new Checkbox[anzahlAntworten][c.length]; audioClipAntworten = new AudioClip[anzahlAntworten]; audioClipFragen = new AudioClip[anzahlFragen]; frage = new Button[anzahlFragen]; antwort = new Button[anzahlAntworten]; // farben der 5 checkboxen c[0] = new Color(255, 0, 0); c[1] = new Color(255, 127, 0); c[2] = new Color(255, 255, 0); c[3] = new Color(0, 255, 0); c[4] = new Color(0, 210, 0); fragenNummer = 0; // aktuelle frage antwortNummer = 0;// aktuelle antwort // verschachteltes layout: erstmal 2 zeilen in einer spalte setLayout(new GridLayout(2, 1)); // interactionPanel: 2 zeilen in einer spalte: buttons und textarea interactionPanel.setLayout(new GridBagLayout()); interactionPanel.setBackground(Color.orange); // das frage-antwort-Panel: eine Zeile mit drei spalten abfragePanel.setLayout(new GridLayout(1, 3)); abfragePanel.setBackground(Color.orange); // das antwortPanel bekommt das layout: maxZeilen, 1 spalte fragePanel.setLayout(new GridLayout(anzahlFragen, 1)); // das antwortPanel bekommt das layout: antwortZeilen, 1 spalten antwortPanel.setLayout(new GridLayout(anzahlAntworten, 1)); // das antwortPanel bekommt das layout: antworten, degreeZeilen checkPanel.setLayout(new GridLayout(anzahlAntworten, c.length)); // die panels werden sequentiell in das übergeorndete layout gelegt // setze das panel auf den container gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.weighty = 1.0; gridBagConstraints.fill = GridBagConstraints.NORTH; interactionPanel.add(navigationPanel, gridBagConstraints); interactionPanel.add(navigationPanel); textPanel.setBounds(10, 10, 300, 300); gridBagConstraints.gridy = 3; gridBagConstraints.fill = GridBagConstraints.BOTH; interactionPanel.add(textPanel, gridBagConstraints); // interactionPanel.add(textPanel); add(interactionPanel); add(abfragePanel); abfragePanel.add(fragePanel); abfragePanel.add(antwortPanel); abfragePanel.add(checkPanel); // setzen der buttons auf die panels navigationPanel.add(weiter); navigationPanel.add(zurück); navigationPanel.add(senden); navigationPanel.add(pdatenSenden); //erstmal disable, wegen datenerhebung // erst fragebogen ausfüllen ! zurück.setEnabled(false); weiter.setEnabled(false); senden.setEnabled(false); for (int i = 0; i < anzahlFragen; i++) { if (i == 0) {// ermöglicht Probe-Knopf frage[i] = new Button("Probefrage"); audioClipFragen[i] = getAudioClip(getDocumentBase(), "f1.wav"); } else { frage[i] = new Button("Frage " + (i)); audioClipFragen[i] = getAudioClip(getDocumentBase(), "f" + (i) + ".wav"); } frage[i].addActionListener(this); frage[i].setEnabled(false); frage[i].setBackground(Color.cyan); fragePanel.add(frage[i]); // ergebnisse werden auf default gesetzt // der max+1 wert ist default => wenn gesetzt, zeigt nichts an for (int k = 0; k < anzahlAntworten; k++) { ergebnisse[1][i][k] = c.length + 1; ergebnisse[0][i][k] = k; } randomizeErgebnisse(i); } for (int i = 0; i < anzahlAntworten; i++) { antwort[i] = new Button("Antwort " + (i + 1)); antwort[i].setBounds(0, 0, 100, 50); antwort[i].addActionListener(this); antwort[i].setEnabled(true); antwort[i].setBackground(Color.orange); antwortPanel.add(antwort[i]); audioClipAntworten[i] = getAudioClip(getDocumentBase(), "a" + (i + 1) + ".wav"); for (int k = 0; k < c.length; k++) { checkbox[i][k] = new Checkbox(); checkbox[i][k].setState(false); checkbox[i][k].setBackground(c[k]); checkPanel.add(checkbox[i][k]); } } // setzen der actionListener pdatenSenden.addActionListener(this); weiter.addActionListener(this); senden.addActionListener(this); zurück.addActionListener(this); // ein paar einstellungen //hintergrund weiss zeichnen setBackground(Color.white); textPanel.setText(fragebogenTexte); } public void actionPerformed(ActionEvent ae) { // ae ist variable typs ActionEvent // abspielen der wavs. assoziert mit den 2 knopf-arten. for (int i = 0; i < anzahlAntworten; i++) { if (ae.getSource() == antwort[i]) { // [0] speichert die randomisierte reihenfolge der antwortsounds audioClipAntworten[ergebnisse[0][fragenNummer][i]].play(); } } for (int i = 0; i < anzahlFragen; i++) { if (ae.getSource() == frage[i]) { audioClipFragen[i].play(); } } // knopf "weiter" gedrückt if ((ae.getSource() == weiter) && (fragenNummer < anzahlFragen)) { // es darf nur ein checkbox getickt sein ! if (vieleKreuze()) return; speicherErgebnisse();// auswertungen speichern // checkBoxen();//reconstruct // zur näxten frage, wenn alle antworten bewertet wurden ... // ... UND nicht letzte frage ! if (fragenNummer < anzahlFragen - 1) { //check it out ... vollständig ? for (int k = 0; k < anzahlAntworten; k++) { // k= antwort if (ergebnisse[1][fragenNummer][k] > c.length) { textPanel.setText("Bewerte bitte die Antwort " + (k + 1) + "..."); antwortNummer = k; return; } } // wenn also vollständig: speicherErgebnisse();// auswertungen speichern setAllCheckboxenFalse(); // setze die checkboxen zurück frage[fragenNummer].setEnabled(false); fragenNummer = fragenNummer + 1; frage[fragenNummer].setEnabled(true); antwortNummer = 0; checkBoxen(); // checkboxenrekonstruktion textPanel.setText(iniText); return; } if (fragenNummer == 0) textPanel.setText(probeText); else textPanel.setText(iniText); } //knopf "persönliche daten senden" gedrückt (Anfangs soll der Fragebogen beantwortet werden...) if ((ae.getSource() == pdatenSenden)) { fragebogen = new String(textPanel.getText()); frage[0].setEnabled(true); // die ersten knöpfe freischalten weiter.setEnabled(true); zurück.setEnabled(true); senden.setEnabled(true); pdatenSenden.setEnabled(false); textPanel.setEditable(false); // ab jetzt nicht mehr editierbar textPanel.setText(probeText); } // knopf "zurück" gedrückt if ((ae.getSource() == zurück)) { // es darf nur ein checkbox getickt sein ! if (vieleKreuze()) return; // auswertungen speichern & zurücksetzen der checkboxen if (fragenNummer > 0) { // pass auf die arraygröße auf! speicherErgebnisse(); setAllCheckboxenFalse(); frage[fragenNummer].setEnabled(false); fragenNummer = fragenNummer - 1; frage[fragenNummer].setEnabled(true); antwortNummer = anzahlAntworten - 1; // höchster array-eintrag checkBoxen(); textPanel.setText(iniText); return; } checkBoxen(); if (fragenNummer == 0) textPanel.setText(probeText); else textPanel.setText(iniText); } // knopf "senden" gedrückt if (ae.getSource() == senden) { if (vieleKreuze()) return; speicherErgebnisse(); // checken , ob alle fragen schon beantowrtet for (int i = 1; i < anzahlFragen; i++) { // i = frage // ist eine frage noch unbeantwortet ? 0 ist Probe, deshalb i=1 for (int k = 0; k < anzahlAntworten; k++) { // k= antwort if (ergebnisse[1][i][k] > c.length) { textPanel .setText("Bewerte bitte erst alle 5 Antworten zur Frage " + (i)); checkBoxen(); return; } } } // erleichert hinterher das parsen. ist so ein tag... StringBuffer sendeDaten = new StringBuffer(fragebogen + "\n"); // dekodieren // => reihenfolge der antworten in dem array passen zu dem des wav-arrays int[][][] tmpArray = new int[2][anzahlFragen][anzahlAntworten]; for (int i = 1; i < anzahlFragen; i++) { // alle fragen . 0 ist Probe, deshalb i=1 sendeDaten.append("\n"); for (int k = 0; k < anzahlAntworten; k++) { // simpler algorithmus zum... for (int h = 0; h < anzahlAntworten; h++) { if (ergebnisse[0][i][h] == k) { // ...reihenfolge finden: 0,1,2... tmpArray[1][i][k] = ergebnisse[1][i][h] + 1; //...kopieren // das "+1" ist intuitiver zu lesen (arrays fangen eben bei 0 an) sendeDaten.append(tmpArray[1][i][k]); } } } sendeDaten.append(""); // zeilenumbruch nach jeder datenreihe } sendeDaten.append("\n"); try { // senden der daten Socket socket = new Socket(hostname, serverport); // Socket socket = new Socket("127.0.0.1", 7893); senden.setEnabled(false); textPanel.setText("Habe bitte etwas Geduld: Daten werden gesendet..."); socket.getOutputStream().write((sendeDaten.toString()).getBytes()); socket.close(); textPanel .setText("Danke, dass Du am Intonationsexperiment teilgenommen hast. \nDie Daten wurden gesendet.\nWenn Du noch einen Intonationstest machen willst,\ndann drücke den 'reload' Knopf Deines Browsers\n(das grüne recycling-zeichen)"); } catch (UnknownHostException e) { textPanel .setText("Fehler: \nServer down ? \n sorry, die ergebnisse konnten nicht gesendet werden ...\nunsere schuld..." + e.getMessage() + "\n\nDamit Deine Daten nicht verloren gehen, sende sie uns per email.\n Hier die Daten:" + sendeDaten + "\nemail an: pascal.christop hweb.de"); } catch (IOException e) { textPanel .setText("IO-Fehler: \nsorry, die ergebnisse konnten nicht gesendet werden ...\nunsere schuld..." + e.getMessage() + "\n\nDamit Deine Daten nicht verloren gehen, sende sie uns doch bitte per email.\n Hier die Daten:" + sendeDaten + "\nemail an: pascal.christoph web.de"); } catch (AccessControlException e) { textPanel .setText("AccessControlException: \nsorry, die ergebnisse konnten nicht gesendet werden ...\nunsere schuld..." + e.getMessage() + "\n\nDamit Deine Daten nicht verloren gehen, sende sie uns doch bitte per email.\n Hier die Daten:" + sendeDaten + "\nSchicke die Daten an: pascal.christoph web.de"); } senden.setEnabled(false); } } // schon mal hier gewesen => rekonstruiere checkbox // default (also "ungecheckt") war der Wert fragenMax+1 (der ja nie // vorkommen kann) // fragenNummer = y = aktuelle zeile // fragenMax = x Max = spalten MAx void checkBoxen() { for (int i = 0; i < anzahlAntworten; i++) { // antworten if (ergebnisse[1][fragenNummer][i] < c.length + 1) { checkbox[i][ergebnisse[1][fragenNummer][i]].setState(true); } } } // die ergbenisse werden im ergebnis-array gespeichert void speicherErgebnisse() { // fragenNumnmer = globale, aktuelle frage for (int k = 0; k < anzahlAntworten; k++) { // zeilen=antworten ergebnisse[1][fragenNummer][k] = c.length + 1;//alles default setzten for (int i = 0; i < c.length; i++) { // spalten=chekcboxenNr. if (checkbox[k][i].getState()) { // zur aktuellen frage die antwort speichern // z.B. Antwort k hat 3. checkbox => speichere 3 ergebnisse[1][fragenNummer][k] = i; } } } return; } // rücksetzen der getickten checkboxen void setAllCheckboxenFalse() { for (int k = 0; k < anzahlAntworten; k++) { // zeilen=antworten for (int i = 0; i < c.length; i++) { // spalten=chekcboxenNr. if (checkbox[k][i].getState()) { //löschen der ticks checkbox[k][i].setState(false); } } } } // es darf nur ein checkbox getickt sein ! boolean vieleKreuze() { // äußere schleife: alle Fragen for (int i = 0; i < anzahlAntworten; i++) { // innere schleife: alle checkboxen einer Antwort for (int k = 0; k < c.length; k++) { if (checkbox[i][k].getState()) { // vorgucken und vergelichen: nur eine checkbox getickt? for (int j = k + 1; j < c.length; j++) { // wenn mehrere, alle löschen if (checkbox[i][j].getState()) { // checkboxen sind temporär gültig for (int p = 0; p < c.length; p++) { checkbox[i][p].setState(false); } ergebnisse[1][fragenNummer][k] = anzahlAntworten + 1; // alle auf default textPanel.setText("JedeR nur EIN Kreuz !"); return true; } } } } } return false; } // zufallswert "vonZelle" und "nachZelle" für das arraycopy void randomizeErgebnisse(int fragenNr) { // p ist probability-variable int p = anzahlAntworten + 1; int vonZelle, nachZelle, tmp; for (int i = 0; i < anzahlAntworten; i++) { while (p >= anzahlAntworten) p = (int) (Math.random() * 10); vonZelle = p; p = anzahlAntworten + 1; while (p >= anzahlAntworten) p = (int) (Math.random() * 10); nachZelle = p; tmp = ergebnisse[0][fragenNr][nachZelle]; ergebnisse[0][fragenNr][nachZelle] = ergebnisse[0][fragenNr][vonZelle]; ergebnisse[0][fragenNr][vonZelle] = tmp; } } }