Nada

Föreläsning 22 - Mer grafik i Java

Rita bilder

Den här raden av lampor ritas av följande program.
import java.applet.*                                        ;
import java.awt.*                                           ;
                                                             
class Lampa extends Canvas                                  {
  Color färg                                                ;
  Lampa(Color c)                                            {
    setBackground(Color.black)                              ;
    färg=c                                                  ;}
  public void tänd()                                        {
    setForeground(färg); repaint()                          ;}
  public void släck()                                       {
    setForeground(Color.black); repaint()                   ;}
  public void paint(Graphics g)                             {
    g.fillOval(0,0,60,60)                                   ;}}
                                                             
public class Lamprad extends Applet                         { 
  Lampa[] lampor = new Lampa[4]                             ;
  Button[] on = new Button[4]                               ;
  Button[] off= new Button[4]                               ;
  
  public void init()                                        {
    setLayout(new GridLayout(3,4))                          ;
    lampor[0] = new Lampa(Color.green)                      ;
    lampor[1] = new Lampa(Color.red)                        ; 
    lampor[2] = new Lampa(Color.yellow)                     ;
    lampor[3] = new Lampa(Color.blue)                       ;
    for (int i=0; i<4; i++)                                 {
      on[i] = new Button("ON")                              ;
      off[i]= new Button("OFF")                             ;
      on[i].addActionListener(this)                         ;
      off[i].addActionListener(this)                        ;}
    for (int i=0; i<4; i++) add(on[i])                      ;
    for (int i=0; i<4; i++) add(lampor[i])                  ;
    for (int i=0; i<4; i++) add(off[i])                     ;}
  public void actionPerformed(ActionEvent e)                {
    for(int i=0;i<4;i++)                                    {
      if(e.getSource()==on[i])  lampor[i].tänd()            ;
      if(e.getSource()==off[i]) lampor[i].släck()           ;}}}

Visa bilder

Bilder i GIF-format eller JPG-format kan man rita i paint-metoden med anropet g.drawImage(bild,x,y,bredd,höjd,this), där bild är av typen Image och knyts till ett filnamn som följande exempel visar. Den sista parametern talar om vilket objekt som ska övervaka bilden och this betyder appleten själv.
import java.applet.*                                        ;
import java.awt.*                                           ;
                                                             
public class Bilder extends Applet implements ActionListener{
  Button knapp  = new Button("Nästa bild")                  ;
  Image[] bild = new Image[3]                               ;
  int nr=0                                                  ;
  
  public void init()                                        {
    setBackground(Color.yellow)                             ;
    bild[0] = getImage(getCodeBase(),"forelasn.gif")        ;
    bild[1] = getImage(getCodeBase(),"venus.gif")           ;
    bild[2] = getImage(getCodeBase(),"viggo.gif")           ;
    add(knapp)                                              ;}

  public void paint(Graphics g)                             {
    g.drawImage(bild[nr],50,50,212,282,this)                ;}

  public void actionPerformed(ActionEvent e)                {
    nr=++nr%3                                               ;
    repaint()                                               ;}}
En rörlig bild på webbsidan är oftast inte en applet utan en gifbild som växlar mellan två eller flera utseenden. T-banetåg

Rörliga appletar

Det här trafikljuset ritas av följande program.
import java.applet.*                                        ;
import java.awt.*                                           ;
                                                             
class Lampa    - - - som ovan - - -
                                                             
public class Ljus extends Applet implements Runnable        { 
  int rödtid=3000, rödgultid=2000, gröntid=3000, gultid=1000;
  Lampa röd  = new Lampa(Color.red)                         ; 
  Lampa gul  = new Lampa(Color.yellow)                      ;
  Lampa grön = new Lampa(Color.green)                       ;
  Thread tid = new Thread(this)                             ;
  public void init()                                        {
    setLayout(new GridLayout(3,1))                          ;
    add(röd); add(gul); add(grön)                           ;
    tid.start()                                             ;}                                               
  public void run()                                         {
    while (true)                                            {
      try                                                   {
	röd.tänd()                                          ;
	tid.sleep(rödtid)                                   ;
	gul.tänd()                                          ;
        tid.sleep(rödgultid)                                ;
	gul.släck()                                         ;
	röd.släck()                                         ;
	grön.tänd()                                         ;
        tid.sleep(gröntid)                                  ;
	grön.släck()                                        ;
	gul.tänd()                                          ;
	tid.sleep(gultid)                                   ;
        gul.släck()                                         ;}
      catch (InterruptedException e)                        {
        break                                               ;}}}}

Ett typiskt GUI

Grafiska användargränssnitt är vad Java använts mest till och alla pruttlabbar ska ha GUI (graphical user interface). I appletar använder man helst gamla komponenter ur java.awt.* (Button, Label etc) men annars är det komponenter ur javax.swing.* (JButton, JLabel etc) som gäller. Det är ganska enkelt att få ett swing-GUI att se ganska bra ut men det kan vara mycket tidskrävande att få exakt det utseende man är ute efter. Det bästa är om man kan förmå sej att gilla läget och inte söka efter perfektion.

Här följer ett typexempel. Synliga komponenter läggs först i osynliga containrar som sedan placeras ut i olika väderstreck.

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

public class GUI extends JFrame implements ActionListener           {
    JPanel buttons  = new JPanel()                                  ;
    JButton skicka  = new JButton("Skicka")                         ;
    JButton sudda   = new JButton("Återställ")                      ;
    JButton avsluta = new JButton("Avsluta")                        ;
    JPanel botten   = new JPanel()                                  ;
    JLabel önskade  = new JLabel(" Önskade ")                       ;
    JLabel måltider = new JLabel(" måltider ")                      ;
    String[] meny={"Frukost","Lunch","Middag"}                      ;
    JList list = new JList(meny)                                    ;
    Box vänster = Box.createVerticalBox()                           ;
    JTextArea placering= new JTextArea("Vill sitta ihop med\n")     ;
    JTextField name = new JTextField("Förnamn Efternamn")           ;
    JTextField email = new JTextField("Snabeladress")               ; 
    JRadioButton veg = new JRadioButton( "Vegetarisk", false )      ;
    Font f = new Font("Dialog",Font.BOLD,12 )                       ;

    public GUI()                                                    {
        super("Denna text hamnar på ramen")                         ;
        Container pane = getContentPane()                           ;
        pane.add(buttons, BorderLayout.NORTH)                       ;
        pane.add(placering, BorderLayout.CENTER)                    ;
        pane.add(vänster, BorderLayout.WEST)                        ;
        pane.add(botten, BorderLayout.SOUTH)                        ;
        buttons.setBackground(Color.yellow)                         ;
        buttons.add(skicka)                                         ;
        buttons.add(sudda)                                          ;
        buttons.add(avsluta)                                        ;
        skicka.addActionListener(this)                              ;
        sudda.addActionListener(this)                               ;
        avsluta.addActionListener(this)                             ;
        önskade.setAlignmentX(CENTER_ALIGNMENT)                     ;
        måltider.setAlignmentX(CENTER_ALIGNMENT)                    ;
        vänster.add(önskade)                                        ;
        vänster.add(måltider)                                       ;
        vänster.add(list)                                           ;
        name.setFont(f)                                             ;
        email.setFont(f)                                            ;
        placering.setFont(f)                                        ;
        botten.add(name)                                            ;   
        botten.add(email)                                           ; 
        botten.add(veg)                                             ;
        list.setFont(f)                                             ;
        list.setBackground(Color.cyan)                              ;
        pack()                                                      ;
        setVisible(true)                                            ;}

    public void actionPerformed(ActionEvent e)                      {
        if (e.getSource()==skicka) submitForm()                     ;
        if (e.getSource()==sudda)  clearForm()                      ;
        if (e.getSource()==avsluta) System.exit(0)                  ;}

    private void submitForm()                                       {
        Object[] t =list.getSelectedValues()                        ;
        for (int i=0;i<t.length;i++)                                { 
            if(veg.isSelected()) System.out.print("Vegetarisk ")    ;
            System.out.println(t[i])                                ;
            System.out.println(name.getText()+" "+ email.getText()) ;
            System.out.println(placering.getText())                 ;}}

    private void clearForm()                                        {
        placering.setText("Vill sitta ihop med\n")                  ;
        name.setText("Förnamn Efternamn")                           ;
        email.setText("Snabeladress")                               ;
        veg.setSelected(false)                                      ;
        list.clearSelection()                                       ;}

    public static void main(String[] args)                          {
        new GUI()                                                   ;}}
Metoden submitForm skulle egentligen skriva till en databas eller snabla meddelandet till en mottagare. Metoden main används vid uttestningen men varje program kan förstås göra new GUI().

Internet

När ett program som kör på en dator via Internet skickar ett meddelande till ett annat program på en annan dator är det mycket som händer på vägen med meddelandet. Det ska kodas, krypteras, delas upp i numrerade TCP-paket, packas in i IP-paket, göras om till bitföljder, skickas iväg som ljuspulser i en optisk fiber och sedan packas upp och skalas av skikt för skikt när det når mottagardatorn. Man brukar kalla detta standardiserade förfarande i sju nivåer för protokollstacken.

Datorerna på Internet har adresser av typen 130.237.222.163 där 130 står för Sverige, 237 för KTH, 222 för Nada och 163 för Henriks dator. Oftare skrivs adressen nada10.nada.kth.se, med namn i stället för nummer. Det är ganska dumt att ordningsföljden då är omvänd! Namnen efter datornamnet kallas domäner och toppdomänen är antingen ett tvåbokstavsland som .se eller en trebokstavskategori som .com.

Serverprogram

En server är ett program som alltid körs och ligger och väntar på att bli kontaktat från något annat program, klienten. För varje domän finns det minst en namnserver (eller domännamnsserver, DNS) som kan översätta namnadresser till numeriska internetadresser. När filtransportprogrammet FTP ska ta kontakt med en annan internetdator anropar den först namnserverns resolver som antingen redan vet IP-adressen eller frågar en annan namnserver.

En server behöver inte ha med internet att göra. Fönsterhanterare är serverprogram som nyttoprogrammen är klienter till. Filservrar lagrar användarens filer på centrala skivminnen osv. Server kallas också en dator som bara kör serverprogram.

Det vanligaste arbetssättet för en server är att den lyssnar på ett visst portnummer. En port är då inte ett fysiskt kontaktdon utan bara ett logiskt nummer för en internetanslutning. Det finns portnummer från 0 upp till 65535 men upp till 1024 är dom reserverade för systemprogram. Här är några exempel.

 Port      Serverprogram
   7           echo 
  13           daytime
  21           ftp
  23           telnet
  25           smtp (e-post)
  53           dns 
  79           finger
  80           http (webben)
Anslutning till en port kallas socket och ett serverprogram tillverkar först en ServerSocket på önskat portnummer. Serversocketobjektets accept-metod ligger och väntar på att en ny klient ska ansluta sej till porten med ett socketobjekt. Då skapar servern ett eget socketobjekt som i fortsättningen sköter kontakten med klientsocketen, allt medan serversocketobjektet ligger och väntar på nya klienter.

Stensaxpåseservern

Den här servern går på datorn shell.e.kth.se för att serva klientprogrammet som skrivs i kursen 2D1385 Programutvecklingsteknik.
import java.net.*                                         ;
import java.io.*                                          ;
import java.util.*                                        ;
public class StenSaxPåseServer                            { 
    public static void main(String[] args)                {
        try                                               {
            ServerSocket sock = new ServerSocket(4712)    ;
            while (true) new Tråd(sock.accept()).start()  ;}
        catch(IOException e) {System.err.println(e);}     ;}} 

class Tråd extends Thread                                 {
    static int antaltrådar=0                              ; 
    BufferedReader in                                     ;
    PrintWriter ut                                        ;
    public Tråd(Socket socket)                            {
        try                                               { 
            in = new BufferedReader( 
            new InputStreamReader(socket.getInputStream()));
            ut= new PrintWriter(socket.getOutputStream()) ;}
        catch(IOException e) {System.err.println(e);}     }
    
    public void run()                                     {
        Random random=new Random()                        ;
        String[] hand={"STEN","SAX","PÅSE"}               ;
        try                                               {
            String namn=in.readLine()                     ;
            System.out.println((++antaltrådar)+": "+namn) ;
            ut.println("Hej, "+namn)                      ;
            ut.flush()                                    ;
            while(true)                                   {
                if(in.readLine()==null) break             ;
                ut.println(hand[random.nextInt(3)])       ;
                ut.flush()                                ;}
            System.out.println("Nu slutade "+namn)        ;
            antaltrådar--                                 ;}
        catch(Exception e) {System.err.println(e);}       ;}}
Klientprogrammet anropar servern och skapar socketförbindelsen.
import java.net.*                                           ;
import java.io.*                                            ;
public class Klient                                         {
  Socket socket                                             ;
  BufferedReader in                                         ;
  PrintWriter ut                                            ;

  public Klient(String dator, int port)                     {
    try                                                     {
      socket=new Socket(dator,port)                         ;
      in=new BufferedReader(new InputStreamReader(
                                   socket.getInputStream()));
      ut=new PrintWriter(socket.getOutputStream())          ;}
    catch(Exception e)                                      {
      System.err.println(e)                                 ;}}

  public String answer(String fråga)                        {
    String svaret="Fel i kommunikationen"                   ;
    try                                                     {
      ut.println(fråga); ut.flush()                         ;
      svaret= in.readLine()                                 ;}
    catch(Exception e)                                      {
      System.err.println(e)                                 ;}              
    return svaret                                           ;}              

  public static void main(String args)                    {
    Klient klient=new Klient("shell.e.kth.se",4712)         ;
    System.out.print("Ditt namn: ")                         ;
    System.out.println(klient.answer(Mio.getLine()))        ;}}


Sidansvarig: <vahid@nada.kth.se>
Senast ändrad 9 september 2004
Tekniskt stöd: <webmaster@nada.kth.se>