Sunteți pe pagina 1din 11

Laborator Programare Java Lucrarea nr.

LUCRAREA NR. 6
Interfețe grafice cu utilizatorul. Swing.

1. Scopul lucrării

Această lucrare de laborator prezintă modul de realizare a unei interfețe grafice utilizator folosind
pachetul java.swing. Se vor prezenta câteva programe demonstrative ce cuprind și tratarea
evenimentelor ce sunt generate de componentele grafice.

2. Crearea unei animații simple

Scopul este de a crea o animație simplă în care un cerc se mișcă pe o fereastră din colțul din
stânga-sus în colțul din dreapta-jos.
Pașii:
• Desenăm un obiect în punctul de coordonate x și y
g.fillOval (20, 50, 100, 100);
// 20 de pixeli față de marginea din stânga, 50 de pixeli față de marginea de sus
• Redesenezi obiectul într-un punct cu alte coordonate x și y
g.fillOval( 25, 55, 100, 100);
// 25 de pixeli față de marginea din stânga, 55 de pixeli față de marginea de sus
(obiectul se mișcă puțin către dreapta și în jos
• Repetăm pasul anterior, modificând valorile x și y atât timp cât trrebuie să continue
animația.

package lab6Swing;

import javax.swing.*;
import java.awt.*;

public class GUI_1 {


//coordonatele cercului
int x = 70;
int y = 70;

public static void main(String[] args) {


GUI_1 gui = new GUI_1();

1
Laborator Programare Java Lucrarea nr. 6

gui.go();
}

public void go() {


JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

MyDrawPanel drawPanel = new MyDrawPanel();

frame.getContentPane().add(drawPanel);
frame.setSize(300, 300);
frame.setVisible(true);

for (int i = 0; i < 130; i++) {


// incrementeaza coordonatele x si y
x++;
y++;
// cerem panoului sa se repicteze astfel incat sa vedem cercul in
//noua pozitie
drawPanel.repaint();
// incetineste programul ca sa putem percepe miscarea
try {
Thread.sleep(50);
} catch (Exception ex) {
}
}

class MyDrawPanel extends JPanel {

public void paintComponent(Graphics g) {


g.setColor(Color.green);

g.fillOval(x, y, 40, 40);

}
}
}

Ce observați? Modificați metoda paintComponent astfel încât să se obțină rezultatul dorit.

3. Crearea unei aplicații care desenează grafică aleatorie în ritmul muzicii.

Această aplicație reprezintă o parte dintr-o aplicație mai complexă ce va fi finalizată într-un laborator
următor. Aplicația va fi numită MașinaMuzicală ce va permite trimiterea de secvențe muzicale prin

2
Laborator Programare Java Lucrarea nr. 6

rețea, la fel ca într-o cameră de discuții (char room). Pentru început vom realiza o interfață grafică în
care se desenează aleator în ritmul muzicii.
Pentru a construi o astfel de aplicație ne sunt necesare câteva cunoștințe legate de biblioteca
JavaSound, care va fi descrisă în continuare.
Biblioteca JavaSound este o colecție de clase și interfețe adăugate începând cu versiune 1.3.
Biblioteca JavaSound este împărțită în două categorii: MIDI și Sampled. Pentru exemplu propus vom
folosi numai MIDI. MIDI este acronimul de la Musical Instrument Digital Interface și reprezintă un
protocol standard, care permite comunicarea între diferite dispozitive de sonorizare electronice. Din
punctul de vedere al aplicației MașinaMuzicală se poate considera că MIDI este un fel de partitură
muzicală pe care o introducem într-un pian electronic. Altfel spus, datele MIDI nu conțin nici un sunet,
ci doar instrucțiuni ce pot fi folosite de un instrument care recunoaște protocolul MIDI pentru redarea
unor sunete. Pentru obținerea sunetelor propriu-zise, avem nevoie de un instrument care poate să
citească și să redea fișierul MIDI. Instrumentul poate fi unul fizic sau unul software. Pentru aplicația
noastră vom folosi instrumental integrat în Java. Acesta se numește sintetizator, deoarece creează
sunete. Înainte de a putea reda vreun sunet avem nevoie de un obiect Sequencer (generator de
secvențe). Acesta este un obiect care preia datele MIDI și le trimite către instrumentele
corespunzătoare. Îl vom folosi pentru redarea muzicii. Clasa Sequencer face parte din pachetul
javax.sound.midi.
Avem nevoie de 4 lucruri:
• Dispozitivul care redă muzica
- Acesta este secvențiatorul (un obiect Sequencer)
• Muzica pe care trebuie să o redai (o melodie)
- Secvența este melodia redată de obiectul Sequencer
• Partea dintr-o secvență care conține informațiile propriu-zise
- O pistă este locul în care sunt păstrate toate datele melodiei
• Informațiile muzicale propriu-zise: notele muzicale, durata etc.
- Un eveniment MIDI este un mesaj pe care-l poate înțelege obiectul Sequencer.
Obs. Ne putem imagina că secvențiatorul este un CD palyer, secvența este un CD cu o singură
melodie ( cu o singură pistă). Informațiile despre redarea melodiei sunt stocate în pistă, iar pista face
parte dintr-o secvență.
Pașii parcurși:
• Obții un obiect Sequencer și îl deschizi

3
Laborator Programare Java Lucrarea nr. 6

Sequencer player = MidiSystem.getSequencer( );


Player.open( );
• Creezi o nouă secvență
Sequence seq = new Sequence(timing, 4);
• Obții o pistă din secvență
Track t = seq.createTrack( );
• Completezi secvența cu evenimente MIDI și o transmiți obiectului Sequencer
t.add(myMidiEvent1);
player.setSequence(seq);
• Pornim obiectul Sequencer
player.start( )
Crearea unui eveniment MIDI
Un eveniment MIDI (MidiEvent) este o instrucțiune pentru o parte a unei melodii. O serie de
evenimente MIDI este un fel de partitură muzicală. Instrucțiunea MIDI este stocată într-un obiect
Message, evenimentul MIDI este o combinație dintre un mesaj și momentul în care ar trebui să fie
declanșat mesajul. De exemplu, mesajul ar putea fi “Începe redarea unui Fa”, în timp ce evenimentul
MIDI va spune “Declanșează acest mesaj la măsura 4”
• Creezi un mesaj
ShortMessage a = new ShortMessage( ) ;
• Adaugi instrucțiunile în mesaj
a.setMessage(144, 1, 44, 100);
• Creezi un nou eveniment MIDI folosind mesajul
MidiEvent noteOn = new MidiEvent(a, 1);
• Adaugi evenimentul MIDI în obiectul Track
Track.add(noteOn);

Metoda setMessage
a.setMessage(144, 1, 44, 100);

- Primul argument: tipul mesajului (144 înseamnă NOTE ON, 128 înseamnă NOTE OFF)
- Al doilea argument: canalul (de ex, un muzician dintr-o formație, canalul 1 înseamnă
muzicianul 1 (toboșarul, de ex) etc.)

4
Laborator Programare Java Lucrarea nr. 6

- Al treilea argument: nota care trebuie redată ( un număr între 0 și 127, de la notele
joase la cele înalte)
- Al patrulea argument: viteza ( cât de repede și de tare trebuie apăsată clapa, de ex)
Programul muzical-artistic:
• Creează o serie de mesaje (evenimente MIDI) pentru redarea unor note aleatorii la pian
(sau la alt instrument ales)
• Înrregistrează un obiect Listener pentru evenimente
• Pornește redarea melodiei, cu ajutorul secvențiatorului
• De fiecare dată când este apelată metoda de tratare a evenimentului din obiectul Listener,
desenează un dreptunghi aleatoriu în panoul de desen și apelează metoda repaint( ).
Codul complet al aplicației este mai jos:

package lab6Swing;

import javax.sound.midi.*;
import java.io.*;
import javax.swing.*;
import java.awt.*;
public class MiniMusicPlayer {
static JFrame f = new JFrame("Video muzical ");
static MyDrawPanel ml;

public static void main(String[] args) {


MiniMusicPlayer mini = new MiniMusicPlayer();
mini.go();
}
public void setUpGui() {
ml = new MyDrawPanel();
f.setContentPane(ml);
f.setBounds(30,30, 300,300);
f.setVisible(true);
}

public void go() {


setUpGui();
try {
// creaza si deschide un secventiator, creaza o secventa si o pista
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
sequencer.addControllerEventListener(ml, new int[] {127});
Sequence seq = new Sequence(Sequence.PPQ, 4);
Track track = seq.createTrack();
// genereaza evenimente

5
Laborator Programare Java Lucrarea nr. 6

int r = 0;
for (int i = 0; i < 60; i+= 4) {
r = (int) ((Math.random() * 50) + 1);
track.add(makeEvent(144,1,r,100,i));
track.add(makeEvent(176,1,127,0,i));
track.add(makeEvent(128,1,r,100,i + 2));
} //sfarsit for
// adauga evenimentul la pista
sequencer.setSequence(seq);
sequencer.start();
sequencer.setTempoInBPM(120);
} catch (Exception ex) {ex.printStackTrace();}
}
public MidiEvent makeEvent(int comd, int chan, int one, int two, int tick) {
MidiEvent event = null;
try {
ShortMessage a = new ShortMessage();
a.setMessage(comd, chan, one, two);
event = new MidiEvent(a, tick);
}catch(Exception e) { }
return event;
}
class MyDrawPanel extends JPanel implements ControllerEventListener {
// initializam cu false si ii vom atribui true atunci cand primim un eveniment
boolean msg = false;

public void controlChange(ShortMessage event) {


msg = true; //am primit un eveniment deci msg primeste true si apelam
repaint()
repaint();
}
public void paintComponent(Graphics g) {
if (msg) {
Graphics2D g2 = (Graphics2D) g;
int r = (int) (Math.random() * 250);
int gr = (int) (Math.random() * 250);
int b = (int) (Math.random() * 250);
g.setColor(new Color(r,gr,b));
int ht = (int) ((Math.random() * 120) + 10);
int width = (int) ((Math.random() * 120) + 10);
int x = (int) ((Math.random() * 40) + 10);
int y = (int) ((Math.random() * 40) + 10);
g.fillRect(x,y,ht, width);
msg = false;
}
}
}
}

6
Laborator Programare Java Lucrarea nr. 6

4. Crearea aplicației MasinaMuzicala

• Construim o interfață grafică cu 256 de casete de validare (JCheckBox) care inițial sunt
neselectate, 16 etichete (JLabel) pentru numele instrumentelor și patru butoane (JButton).
• Înregistrăm un obiect ActionListener pentru fiecare dintre cele patru butoane. Așteptăm până
când utilizatorul apasă butonul Start, apoi parcurgem toate cele 256 de casete de validare, le
citim starea și construim o pistă MIDI.
• Configurăm sistemul MIDI, inclusiv obținerea unui obiect Sequencer, crearea unei secvențe și
crearea unei piste. Folosim metoda setLoopCount, adăugată în versiunea 5, această metodă
ne permite să specificăm de câte ori vrem să fie reluată o secvență. De asemenea, folosim
factorul de tempo al secvenței pentru creșterea sau scăderea ritmului de redare și pentru
păstrarea aceluiași tempo de la o iterație a ciclului la următoarea.
• După apăsarea butonului Start, metoda de tratarea a evenimentelor pentru acest buton
apelează metoda buildTrackAndStart( ). În această metodă parcurgem cele 256 de casete de
validare, le obținem starea și folosim aceste informații pentru a construe o pistă MIDI ( cu
ajutorul metodeI makeEvent( ) ) . După construirea pistei, pornim secvențiatorul, care redă
continuu melodia (deoarece parcurgem secvența cyclic) până când utilizatorul apasă butonul
Stop.
Codul aplicației este dat mai jos:

import java.awt.*;
import javax.swing.*;
import javax.sound.midi.*;
import java.util.*;
import java.awt.event.*;

public class MasinutaMuzicala {

JPanel mainPanel;
ArrayList<JCheckBox> checkboxList; // stocam casetele de validare intr-un ArrayList
Sequencer sequencer;
Sequence sequence;
Track track;
JFrame theFrame;
// numele instrumentelor, ca matrice String, pentru construirea etichetelor
String[] instrumentNames = { "Bass Drum", "Closed Hi-Hat", "Open Hi-Hat", "Acoustic
Snare", "Crash Cymbal",

7
Laborator Programare Java Lucrarea nr. 6

"Hand Clap", "High Tom", "Hi Bongo", "Maracas", "Whistle", "Low


Conga", "Cowbell", "Vibraslap",
"Low-mid Tom", "High Agogo", "Open Hi Conga" };
// cheile pentru instrumentele reale, fiecare cheie e un instrument
//de ex nr 35 inseamna Bass Drum etc

int[] instruments = { 35, 42, 46, 38, 49, 39, 50, 60, 70, 72, 64, 56, 58, 47, 67,
63 };

public static void main(String[] args) {


new MasinutaMuzicala().buildGUI();
}

public void buildGUI() {


theFrame = new JFrame("Cyber MasinutaMuzicala");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout = new BorderLayout();
JPanel background = new JPanel(layout);
//un chenar liber empty border lasa o margine intre limitele panoului si locul unde
//sunt plasate componentele.
background.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

checkboxList = new ArrayList<JCheckBox>();


Box buttonBox = new Box(BoxLayout.Y_AXIS);

JButton start = new JButton("Start");


start.addActionListener(new MyStartListener());
buttonBox.add(start);

JButton stop = new JButton("Stop");


stop.addActionListener(new MyStopListener());
buttonBox.add(stop);

JButton upTempo = new JButton("Tempo Up");


upTempo.addActionListener(new MyUpTempoListener());
buttonBox.add(upTempo);

JButton downTempo = new JButton("Tempo Down");


downTempo.addActionListener(new MyDownTempoListener());
buttonBox.add(downTempo);

Box nameBox = new Box(BoxLayout.Y_AXIS);


for (int i = 0; i < 16; i++) {
nameBox.add(new Label(instrumentNames[i]));
}

background.add(BorderLayout.EAST, buttonBox);
background.add(BorderLayout.WEST, nameBox);

theFrame.getContentPane().add(background);

GridLayout grid = new GridLayout(16, 16);

8
Laborator Programare Java Lucrarea nr. 6

grid.setVgap(1);
grid.setHgap(2);
mainPanel = new JPanel(grid);
background.add(BorderLayout.CENTER, mainPanel);
// creare casete de validare, inizializarea lor cu valoarea false (ca sa nu fie selectate)
//si adaugarea lor in lista ArrayList si panoul GUI
for (int i = 0; i < 256; i++) {
JCheckBox c = new JCheckBox();
c.setSelected(false);
checkboxList.add(c);
mainPanel.add(c);
}

setUpMidi();

theFrame.setBounds(50, 50, 300, 300);


theFrame.pack();
theFrame.setVisible(true);
}

//configurare system MIDI: obtinerea obiectului Sequencer, a secventei si a pistei


public void setUpMidi() {
try {
sequencer = MidiSystem.getSequencer();
sequencer.open();
sequence = new Sequence(Sequence.PPQ, 4);
track = sequence.createTrack();
sequencer.setTempoInBPM(120);

} catch (Exception e) {
e.printStackTrace();
}
}

public void buildTrackAndStart() {


//com crea o matrice cu 16 elemente in care vom pastra valorile pentru un instrument, cu
toate cele //16 masuri.
int[] trackList = null;
// sterge vechea pista si creeaza una noua
sequence.deleteTrack(track);
track = sequence.createTrack();

for (int i = 0; i < 16; i++) {


trackList = new int[16];
// initializeaza cheia care reprezinta instrumentul
int key = instruments[i];

for (int j = 0; j < 16; j++) {


JCheckBox jc = (JCheckBox) checkboxList.get(j + (16 * i));
//se testeaza daca caseta de validare pentru masura curenta este selectata, daca da pune
valoarea //cheii in elemental corespunzator al matricei
if (jc.isSelected()) {

9
Laborator Programare Java Lucrarea nr. 6

trackList[j] = key;
} else {
trackList[j] = 0;
}
}
// pentru acest instrument si pt toate cele 16 masuri creeaza
evenimentele si le
// adauga la pista //melodiei
makeTracks(trackList);
track.add(makeEvent(176, 1, 127, 0, 16));
}
//
track.add(makeEvent(192, 9, 1, 0, 15));
try {
sequencer.setSequence(sequence);
//specificam nr de iteratii ale ciclului, in acest caz secventa va fi rulata continuu
sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
sequencer.start();
sequencer.setTempoInBPM(120);
} catch (Exception e) {
e.printStackTrace();
}
}

// clase interne pentru butoane


public class MyStartListener implements ActionListener {
public void actionPerformed(ActionEvent a) {
buildTrackAndStart();
}
}

public class MyStopListener implements ActionListener {


public void actionPerformed(ActionEvent a) {
sequencer.stop();
}
}

public class MyUpTempoListener implements ActionListener {


public void actionPerformed(ActionEvent a) {
float tempoFactor = sequencer.getTempoFactor();
sequencer.setTempoFactor((float) (tempoFactor * 1.03));
}
}

public class MyDownTempoListener implements ActionListener {


public void actionPerformed(ActionEvent a) {
float tempoFactor = sequencer.getTempoFactor();
sequencer.setTempoFactor((float) (tempoFactor * .97));
}
}

// creeaza evenimentele pentru un instrument la un moment dat, pentru toate cele 16 masuri

10
Laborator Programare Java Lucrarea nr. 6

public void makeTracks(int[] list) {

for (int i = 0; i < 16; i++) {


int key = list[i];

if (key != 0) {
track.add(makeEvent(144, 9, key, 100, i));
track.add(makeEvent(128, 9, key, 100, i + 1));
}
}
}

public MidiEvent makeEvent(int comd, int chan, int one, int two, int tick) {
MidiEvent event = null;
try {
ShortMessage a = new ShortMessage();
a.setMessage(comd, chan, one, two);
event = new MidiEvent(a, tick);

} catch (Exception e) {
e.printStackTrace();
}
return event;
}

5. Temă pentru acasă

1. Scrieți un program care afișează într-o fereastră toate fonturile disponibile pe platforma
folosită.
2. Scrieți o aplicație care desenează un cerc care își schimbă culoarea de fiecare dată când
utilizatorul execută clic pe buton.

11

S-ar putea să vă placă și