Lab5 för prgmedcl04 Grafik Viktigt läs detta först:den här labblydelsen är ganska lång, detta betyder inte att labben tar lång tid.en hel del av lydelsen är anvisning om hur man går tillväga för att kunna klara labben. Om känner dig hemma i grafik behöver du inte följa anvisningarna punkt för punkt. Men om du inte har hållit på med grafik rekommenderar vi att du läser genom hela lydelsen först och sedan sätter igång med att göra laborationen. Dessutom kommer att finnas enkla exempel på kursens hemsida under senaste nytt som du kanske kommer att ha nytta av. I den här laborationen ska vi skriva ett enkelt ritprogram. Användaren ska inte kunna dra musen för att rita utan ritningen sker med hjälp av knapptryckningar. Därför ska programmet ha 5 knappar (klassen Button) som har olika funktioner. Vi kan kalla knapparna Up, Down, Right, Left och till slut Clear. Teckningen kommer att hamna på en duk (klassen Canvas). Vi antar att det finns en penna i programmet som har till uppgift att rita på duken. När programmet startas har pennan en startposition (x och y koordinat) på duken (gärna mitten av duken). När man klickar på knappen Left så styrs pennan en enhet (en pixel eller en punkt) åt vänster och därmed ritas en horisontell linje som består av två enheter (alltså två pixlar eller två punkter). Samma princip gäller för knapparna Up, Down och Right. En tryckning på knappen Clear leder till att allt man ritat på duken suddas bort. Grafiskt användargränssnitt Placering av komponenter Användargränssnittet på ditt program ska se ut som nedan:
Bilden visar att duken (Canvas) täcker övre halvan av fönstret och resten av komponenterna alltså knapparna (Button) täcker nedre halvan av fönstret. Det innebär att vi måste dela upp fönstret till 2 lika stora delar. Detta kan vi göra med hjälp av en LayoutManager som heter GridLayout. En Layoutmanager ska bara ordna till placering av komponenterna. I det här fallet eftersom att vi har bestämt att fönstret ska delas i två delar så kommer fönstret endast kunna innehålla två komponenter. Detta skapar inga problem för övre delen. Däremot för nedre delen av fönstret där vi vill ha fem knappar (Button) kommer vi att få ett problem, detta eftersom att det finns plats bara för en komponent. Vad ska vi göra med de andra 4 knapparna? Vi har ju lärt oss om att komponenter är av två slag de som är behållare (Container) och de som inte är behållare. En komponent som är behållare kan inneehålla andra komponenter. Bland alla behållare kan vi nämna komponenterna Frame, Panel, ScrollPane. Button och Canvas kan vi ge som exempel på en sådan som inte är behållare. Kortfattad: i en Panel kan man lägga till en Button eller en annan Panel men i en Button kan man inte lägga till någon annan komponent. Med hela ovanstående förklaring kommer vi fram till att om vi lägger en Panel i nedre delen först då kan vi sedan lägga flera komponenter där, alltså vi kommer att få plats med alla 5 knappar i panelen. Som bilden visar påminner knapparnas placering om layoutmanagern BorderLayout. Det vill säga att om vi vill ha den placeringen så måste vi använda BorderLayout för Panelen. Nu har vi klart för oss att för placering av knapparna och duken så behöver vi använda oss av: en GridLayout, en Panel och en BorderLayout. Uppgift1: Utseende men ingen funktionalitet. 1. Skapa en fil med namnet RitTavla.java. 2. Deklarera en klass också med namnet RitTavla i filen. 3. Se till att klassen RitTavla ärver (extends) från klassen Frame. (se exemplen på kursens hemsida). 4. Deklarera 5 instansvariabler för knapparna (Button). 5. Deklarera 1 instansvariabel för duken (Canvas). 6. Deklarera en konstruktor-metod för klassen. Följande ska gälla: 1. Instansvariablerna ska initieras. i. Knapparna ska skapas med en text på som bilden visar. ii. Canvasen skapas och sedan får storleken lika bredd som fönstret men ländgen ska vara hälften av fönstrets längs. 2. 3 st. formella parametrar deklareras: i. En parameter för fönstrets titel ii. iii. En parameter för bredden av fönstret och duken En parameter för längden av fönstret och vilket kan halveras och användas för att bestämma längden av duken.
iv. Metoden som ordnar layouten ska anropas här (kolla punkten 7). 7. Deklarera en instansmetod som ska ordna layouten: 1. Deklarera en instansmetod som heter fixalayout(), sedan skriv kod för följande saker i metoden. 2. Skapa en instans av GridLayout. 3. Sätt fönstrets layout till GridLayout-objektet som du skapade nyss. 4. Lägg Canvas-objektet i fönstret. 5. Skapa en instans av Panel. 6. Skapa en instans av BorderLayout 7. Sätt panelens layout till BorderLayout-objektet som du skapade nyss. 8. Lägg alla knapparna i Panel-objektet. 9. Lägg Panel-objektet i fönstret. 8. Se till att metoden du deklarerade i punkt 7 (fixalayout()) anropas i konstruktoren. 9. Skapa nu en fil med namnet Lab5.java. 10. I Labb5.java deklarera en klass med namnet Labb5. 11. Deklarera main-metoden i klassen Labb5: 1. Först skapas en instans av klassen RitTavla. Storlek på fönstret kan ni välja 300 x 300 pixlar. Välj en titel till ditt program. 2. Instansmetoden show() som finns i objektet av RitTavla ska anropas för att fönstret ska visas. Kompilera filen Lab5.java och kör programmet. Kontrollera att ett fönster med alla komponenter visas. Inga knapptryckningar fungerar nu men det ska vi se till att de gör i nästa avsnitt. Uppgift2: Ge knapparna värdelösa funktioner 1. Låt klassen implementera (implements) ActionListener. Titta på exemplen på kursens hemsida. 2. Då måste vi deklarera metoden actionperformed, som ser exakt ut som nedan: public void actionperformed(actionevent event){ //HÄR LÄGGS DEN KOD SOM BESKRIVS I PUNKTER 3,4 3. Vi ska nu skriva kod som gör att programmet skriver ut textsträngen knappen left på terminalfönstret när användaren klickar på knappen Left. a. Variabeln event (kolla metoden actionperformed) kommer att vara ett objekt som bär med sig information om vilken händelse har påträffats, därför ska vi använda event för att ta reda på vilken knapp som var nedtryckt. I klassen ActionEvent finns en instansmetod som returnerar en referens till knappen, metoden heter
getsource(), eftersom att metoden är en instansmetod så ska vi anropa den via referensvariabeln event. Ett anrop till metoden ser alltså ut på följande sätt: event.getsource() b. Anta att den variabeln som du använder för knappen Left heter v då kan vi kontrollera om den referens som returneras från anropet till getsource() refererar till samma knapp som v refererar till. Detta gör vi med en enkel if-sats, if(event.getsource = = v){ c. Om if-satsen ger sant ska programmet skriva ut textsträngen knappen left på terminalfönstret, alltså utskrift-satsen System.out.println( knappen left ). 4. Vi ska göra samma sak som vi gjorde i punkt 3 fast för andra knappar d.v.s. Up, Down, Right och Clear. Alltså när man trycker på knappen Up så ska det skrivas ut knappen up på terminalfönstret o.s.v. 5. Deklarera en metod som lägger till lyssnare till alla knappar en efter en. Anta att vi vill ge knappen v actionlistener, då skriver vi på följande sätt: v.addactionlistener(this); 6. Se till sedan att metoden anropas t.ex. i konstruktorn, för annars kommer inte knapparna reagera när man klickar på dem. Nu är det dags att kompilera om programmet, fixa eventuella kompilerings fel och till slut njuta av knapptryckningar när man kör programmet. Innan vi börjar med nästa uppgift vilket är att ge knapparna betydelsefulla funktioner så måste vi göra klart för oss om vad som ska egentligen hända när man t.ex. klickar på knappen Left två gånger i följd. Vi vet att det ska ritas en horisontell linje på duken. Men frågan är: var ska linjen hamna på duken? Längs upp? Längs ner? Mer åt vänster? Svar på frågan är egentligen en smaksak men vi antar att pennan finns exakt i mitten av duken. Så trycker man två gånger på vänster knappen så ritas en linje som består av två punkter ena punkten finns i mitten och den andra är grannpunkten till vänster av första punkten. Om vi trycker på Up knappen 3 efterföljande gånger så ritas en vertikal linje. Båda linjerna kommer att se ut som tecknet L fast storleken är väldigt liten. Av detta framgår att varje gång en linje ska ritas så är startpunkten för den nya linjen alltid slutpunkt för den föregående linjen. Detta kan vi lösa genom att låta pennan ha en aktuell punkt med x och y koordinat. Sedan behöver vi ha ytterliggare en punkt som anger nästa punkt som ska ritas. Anta att pennan har aktuella punkten med penx=20 och peny=43 och den andra punkten har samma värde som pennans aktuella punkt alltså lastx=20 och lasty=43. Om man klickar på Left så ska endast värdet på lastx minska med 1. För höger ska värdet på lastx ökas med 1, samma princip gäller för Up och Down. Nu när vi har två olika punkter så kan vi låta metoden Paint rita en linje med de koordinaterna. Men efter att linjen har ritats ut så ska vi låta pennans aktuella punkt få samma värde som sista punkten, detta är för att vi vill förbereda till nästa klickning.
Uppgift3: Ge knapparna en meningsfull funktion. 1. Deklarera fyra nya instansvariabler av typen int variablerna kan heta penx, peny, lastx, lasty. 1. eftersom att det har tillkommit fler instansvariabler så ska vi initiera de i konstruktoren. 2. låt penx och lastx tilldelas halva värdet av fönstrets bredd. 3. låt peny och lasty tilldelas en fjärde del av värdet på fönstrets längd. 2. Ersätt utskrift satserna i alla if-satser med följande: 1. För vänster knappen ska lastx minskas med 1. 2. För höger kna ppen ska lastx ökas med 1. 3. För uppåt knappen ska lasty minskas med 1. 4. För neråt knappen ska lasty ökas med 1. 5. Vi väntar med sudd knappen så länge. 3. Låt metodanropet repaint() vara den sista sats i deklarationen av metoden actionperformed() som vi deklarerade tidigare. 4. Skriv följande metoddeklaration: public void paint(graphics g){ Graphics gduk = duk.getgraphics(); gduk.setcolor(color.white); gduk.drawline(penx, peny, lastx, lasty); penx=lastx; peny=lasty; 5. Nu ska vi se till att knappen sudda ska verkligen sudda allt: 1. Deklarera en instansmetod som ser ut som nedan: public void sudda(){ Graphics gduk = duk.getgraphics(); gduk.setcolor(color.black); int width=duk.getwidth(); int height=duk.getheight(); gduk.fillrect(0,0,width, height); 2. Sedan måste vi se till att metoden sudda anropas när man klickar på knappen Clear. Observera att när metoden sudda anropas så ska inte repaint() anropas, detta fixar du med en if-sats. 6. Viktigt: Variabeln duk (i duk.getgraphics()) måste vara den instansvariabeln som du deklarerade för att hålla reda på Canvas. Lycka till