LogicGate cz5

Ciąg dalszy implementacji klas.

Implementacja klasy Wire

package com.adam_mistal.logicgateapp;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

public class Wire {
	//Pin wysyłający sygnał i odbierający
	private Pin pin_one;
	private Pin pin_two;
	private Paint wireBrush = null;
	private int WireWidth=10;
	private float[] pts;
	public Wire(Pin pin1,Pin pin2){
		pin_one=pin1;
		pin_two=pin2;

		if(pin_one.isMaster){
			//pin pierwszy  podaje sygnał
			pin_one.refPin=pin_two;

		};
		if(pin_two.isMaster){
			//pin drugi podaje sygnał
			pin_two.refPin=pin_one;
		};
		wireBrush = new Paint();
		wireBrush.setColor(Color.RED);
		wireBrush.setDither(true);
		wireBrush.setAlpha(150);
		wireBrush.setStrokeWidth(WireWidth);
		parse(pin_one.getPoint(), pin_two.getPoint());

	}
	/**
	 * rysuje przewód
	 * @param canvas
	 */
	public void draw(Canvas canvas){
		canvas.drawLines(pts, wireBrush);
	}
	/**
	 * rysuje linie miedzy pinami w ten sposób aby załąmanie lini było prostopadłe
	 * @param p1
	 * @param p2
	 */
	private void parse(Point p1,Point p2){
		Point n;
		if(p1.x!=p2.x){
			n=new Point(p2.x, p1.y);
			pts=new float[8];
			pts[0]=p1.x;
			pts[1]=p1.y;
			pts[2]=n.x;
			pts[3]=n.y;
			pts[4]=n.x;
			pts[5]=n.y;
			pts[6]=p2.x;
			pts[7]=p2.y;

		}else{
			pts=new float[4];
			pts[0]=p1.x;
			pts[1]=p1.y;
			pts[2]=p2.x;
			pts[3]=p2.y;

		}

	}

}

Implementacja klasy OnOffButton

package com.adam_mistal.logicgateapp;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;

public class OnOffButton {
	public static  int Width = 80;
	public  int Height = 80;
	private  String Text = "Off";
	private int TextSize=50;
	private int colorOn=Color.GREEN;
	private int colorOff=Color.GRAY;
	private int Left = 0;
	private int Top = 0;
	private int Right=0;
	private int Bootom=0;
	private int textX,textY;
	private boolean isOn=false;
	private Paint paintBrush = null;
	private Paint textBrush = null;
	private Pin pin=null;
	public OnOffButton() {
		paintBrush = new Paint();
		paintBrush.setColor(colorOff);	
		paintBrush.setAntiAlias(true);
		paintBrush.setDither(true);	
		
		textBrush = new Paint();
		textBrush.setColor(Color.BLACK);	
		textBrush.setAntiAlias(true);
		textBrush.setDither(true);
		textBrush.setTextSize(TextSize);
		setTopPin();
		
		
	}

	public void draw(Canvas canvas)
	   {	
		canvas.drawRect(Left, Top, Right, Bootom, paintBrush);	
		canvas.drawText(Text, textX, textY, textBrush);
		pin.draw(canvas);
	   }
   /*
    * usatwiam pin na górze elementu
    */
	public void setTopPin(){
		pin =new Pin(true);
		pin.setCenter(Left+Width/2, Top-Pin.Height);
	}
	
	
	
	public void checkIfClicked(Point clickPoint){
		//sprawdzam czy kliknięto przycisk
		if(Tools.checkIfClickedInRect(clickPoint, Left, Right, Bootom, Top)){
			onTouch();	
		}
				
	}

	private void onTouch() {
		//usatwieni pinów
		if(isOn){
			
			paintBrush.setColor(colorOff);
			pin.setValue(false);
			pin.refPin.setValue(false);
			Text = "Off";
			isOn=false;
			
		}else{
			paintBrush.setColor(colorOn);
			pin.setValue(true);
			pin.refPin.setValue(true);
			Text = "On";
			isOn=true;
		}
		
		Log.i("OnOffButton", "ison?"+isOn);
	
		
	}

	public void setRight(int r) {
		Right=r;
		Left=r-Width;
		textX=Left+5;
		setTopPin();
		
	}
	public void setLeft(int l) {	
		Left=l;	
		Right=l+Width;
		textX=Left+5;
		setTopPin();
		
	}

	public void setTop(int t) {
		Top=t;
		Bootom=t+Height;
		textY=Top+Width/2;
		setTopPin();
		
	}

	public Pin getPin() {
		
		return pin;
	}

}



Implementacja klasy Tools


package com.adam_mistal.logicgateapp;

public class Tools {
	//zwraca długość pomiędzy punktami
	public static double getLength2D(Point p1,Point p2){
		double sdx=p2.x-p1.x;
		double sdy=p2.y-p1.y;
		double slength2D=Math.sqrt(Math.pow(sdx, 2)+Math.pow(sdy, 2));
		
		return slength2D;
				
	}
	//zwraca true jeśli kliknięto w podany region
	public static boolean checkIfClickedInRect(Point p,int left,int right,int bootom,int top){
		double testX=p.x;
		double testY=p.y;
		if(testX>left&&testX<right)
			if(testY>top&&testY<bootom){
				return true;
			}
	
	
		
		return false;
				
	}

}


	

Implementacja klasy Lamp

package com.adam_mistal.logicgateapp;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

public class Lamp {
	private int centerW=0;
	private int centerH=0;
	private int radius=40;
	private Paint paintBrush = null;
	private Pin pin=null;
	public Lamp(){
		pin=new Pin(false);
		paintBrush = new Paint();
		paintBrush.setColor(Color.GREEN);
		paintBrush.setAntiAlias(true);
		paintBrush.setDither(true);		
	}
 
	public void draw(Canvas canvas) {
		updatePin();
		canvas.drawCircle(centerW, centerH, radius, paintBrush);
		pin.draw(canvas);
	}

	private void updatePin() {
		if(pin.value){
			switchOn();
		}else{
			switchOff();
		}
		
	}

	public void setCenter(int cW, int cH) {
		centerH=cH;
		centerW=cW;	
		pin.setCenter(cW, cH+radius);
	}

	public void setRadius(int i) {
		radius=i;		
	}
	private void switchOn(){
		paintBrush.setColor(Color.YELLOW);
		
		
	}
	private void switchOff(){
		paintBrush.setColor(Color.GRAY);
		
	}

	public Point getCenter() {
		
		return new Point(centerW, centerH);
	}

	public Pin getPin() {
		
		return pin;
	}

}


	

Utworzenie klasy Gate będącej klasą bazową dla szczególnych bramek logicznych

package com.adam_mistal.logicgateapp;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;

public abstract class Gate{
	protected int center_Y;
	protected int center_X;
	protected int left;
	protected int right;
	protected int top;
	protected int bottom;
	private Paint paintBrush = null;
	private Paint textBrush = null;
	protected Pin[] in_pins;
	protected int in_pin_count=0;
	private int pins=0;
	protected Pin outPin=null;
	protected Path path;
	private int TextSize;
	private int textX;
	private int textY;
	protected String gate_name="Gate";

	public Gate() {
		paintBrush = new Paint();
		setColor(Color.BLUE, 150);
		setTextColor(Color.YELLOW);
		setTextSize(40);		
		path=new Path();
		outPin=new Pin(true);
		
	}
	protected void setText(String t){
		gate_name=t;
	}
	
	public void setTextSize(int i) {
		TextSize=i;
		textBrush.setTextSize(TextSize);
		
		
	}
	public void setTextColor(int col) {
		textBrush = new Paint();
		textBrush.setColor(col);	
		textBrush.setAntiAlias(true);
		textBrush.setDither(true);
		
		
	}
	public void setColor(int color,int alfa){
		paintBrush.setColor(color);
		paintBrush.setAlpha(alfa);
		paintBrush.setStyle(Paint.Style.FILL_AND_STROKE);
		paintBrush.setStrokeWidth(2);
	}

	public void draw(Canvas canvas) {
		updateOutPin();
		canvas.drawPath(path, paintBrush);	
		draw_in_pins(canvas);
		outPin.draw(canvas);
		drawGateNAme(canvas);
	}
	
	private void drawGateNAme(Canvas canvas) {
		canvas.drawText(gate_name, textX, textY, textBrush);
		
	}
	private void draw_in_pins(Canvas canvas) {
		for(Pin p:in_pins){
			p.draw(canvas);
		}
		
	}
	/**
	 * W tej metodzie musimy zaimplementować rysowanie naszych bramek logicznych
	 * @param c_x
	 * @param c_y
	 */
	abstract protected void makeUI(int c_x,int c_y);
	/**
	 * W tej metodzie zaimplementujemy obliczenia które ma realizować bramka
	 */
	abstract protected void updateOutPin();
	/**
	 * Ustawienie bramki tak by miała dwa wejścia
	 */
	protected void setTwoInputGate(){
		in_pin_count=2;
		in_pins=new Pin[in_pin_count];
		addPin(new Pin(false));
		addPin(new Pin(false));
	}
	/**
	 * Ustawienie bramki tak by miała jedno wejście
	 */
	protected void setOneInputGate(){
		in_pin_count=1;
		in_pins=new Pin[in_pin_count];
		addPin(new Pin(false));
	}
	/**
	 * dodanie pinu
	 * @param p
	 */
	private void  addPin(Pin p) {
		if(pins<in_pin_count){
			in_pins[pins++]=p;
		}
	}

	public void setCenter(int x, int y) {
		makeUI(x, y);
		setUpPins();
		setTextPosCenter();
		
	}

	
	public void setTextPos(int x, int y) {
		textX=x;
		textY=y;
		
	}
	public void setTextPosCenter(){
		Paint paint = new Paint();
		paint.setTextSize(TextSize);
		float w=paint.measureText(gate_name);
		textX=(int) (center_X-w/2);
		textY=center_Y;
		
		
	}
	/**
	 * Usatwienia pinów
	 */
	private void setUpPins() {
		int width = right - left - 2 * Pin.Width;
		if (in_pin_count == 2) {
			int offset = width / (in_pin_count - 1);
			int i = 0;
			int l = left + Pin.Width;
			for (Pin p : in_pins) {
				p.setCenter(l + i, bottom);
				i += offset;
			}
		}else{
			in_pins[0].setCenter(center_X, bottom);
		}

		outPin.setCenter(center_X, top - Pin.Height);

	}
	public int getTop() {
		return top;
	}
	public int getLeft() {
		return left;
	}
	public int getBottom() {
		return bottom;
	}
	public int getRight() {
		return right;
	}
	public Pin getOutPin() {
		return outPin;
	}
	public Pin getInPin(int nr) {

		return in_pins[nr];
	}
	public int getPinCount(){
		return in_pin_count;
	}

	
	

}


	

Klasa Gate jest abstrakcyjna, czyli nie można tworzyć obiektów jej klasy.Wykorzystamy ją do dziedziczenia na klasy AndGate,OrGate itd.

Klasa AndGate

package com.adam_mistal.logicgateapp;

import android.graphics.RectF;
import android.graphics.Path.Direction;

public class AndGate extends Gate {
	static public final String[] TRUE_TABLE={"X1","X2","Y",
		                                      "0","0","0",
		                                      "0","1","0",
		                                      "1","0","0",
		                                      "1","1","1",
	                                           };
	public AndGate(){
		//usawiamy jako dwuwejsciowa
		setTwoInputGate();
		setText("AND");	
		
		
	}
	
   
	@Override
	protected void makeUI(int c_x, int c_y) {		
		int radius;
		int half_width=50;
		radius=half_width;
		int half_height=50;
		this.center_Y=c_y;
		this.center_X=c_x;
		left = center_X - half_width;
		right = center_X+ half_width;
		top = center_Y -half_height-radius;
		bottom = center_Y + half_height;	
		//rysujemy nasza bramkę
		path.addRect(new RectF(left, top+radius, right, bottom),Direction.CW);
		path.moveTo(left, top+radius);
		path.lineTo(center_X, top);
		path.lineTo(right, top+radius);
		path.addArc(new RectF(left, top, right, top+2*radius), 180f, 90f);
		path.addArc(new RectF(left, top, right, top+2*radius), 270f, 90f);	
        path.close();      		
	}

	@Override
	protected void updateOutPin() {
					  //tu własnie następuje ustawienie wyjściowego pinu na podstawie wejściowych pinów  	        
				if(in_pins[0].value && in_pins[1].value){
					outPin.setValue(true);				
				}else{
					outPin.setValue(false);					
				}
	}


}



	

Klasa NandGate

package com.adam_mistal.logicgateapp;

import android.graphics.RectF;
import android.graphics.Path.Direction;

public class NandGate extends Gate {
	static public final String[] TRUE_TABLE={"X1","X2","Y",
        "0","0","1",
        "0","1","1",
        "1","0","1",
        "1","1","0",
         };
	public NandGate(){
		setTwoInputGate();
		setText("NAND");	
		
	}
	

	@Override
	protected void makeUI(int c_x, int c_y) {		
		int radius;
		int half_width=50;
		radius=half_width;
		int radius2=radius/3;
		int half_height=50;
		this.center_Y=c_y;
		this.center_X=c_x;
		left = center_X - half_width;
		right = center_X+ half_width;
		top = center_Y -half_height-radius-2*radius2;
		bottom = center_Y + half_height;		
		path.addRect(new RectF(left, top+radius+2*radius2, right, bottom),Direction.CW);
		path.moveTo(left, top+radius+2*radius2);
		path.lineTo(center_X, top+2*radius2);
		path.lineTo(right, top+radius+2*radius2);
		path.addArc(new RectF(left, top+2*radius2, right, top+2*radius+2*radius2), 180f, 90f);
		path.addArc(new RectF(left, top+2*radius2, right, top+2*radius+2*radius2), 270f, 90f);
		path.addCircle(center_X, top+radius2, radius2,Direction.CW);
        path.close();      		
	}

	@Override
	protected void updateOutPin() {
				if(in_pins[0].value && in_pins[1].value){
					outPin.setValue(false);
				}else{
					outPin.setValue(true);
				}
	}


}

	

Klasa OrGate

package com.adam_mistal.logicgateapp;
import android.graphics.RectF;
import android.graphics.Path.Direction;

public class OrGate  extends Gate {
	static public final String[] TRUE_TABLE={"X1","X2","Y",
        "0","0","0",
        "0","1","1",
        "1","0","1",
        "1","1","1",
         };

	public OrGate() {
		setTwoInputGate();
		setText("OR");	
	}

	protected void updateOutPin() {
		if(in_pins[0].value || in_pins[1].value){
			outPin.setValue(true);
		}else{
			outPin.setValue(false);
		}
		
	}


	@Override
	protected void makeUI(int c_x, int c_y) {
		int radius;
		int half_width=50;
		radius=90;
		int half_height=50;
		this.center_Y=c_y;
		this.center_X=c_x;
		left = center_X - half_width;
		right = center_X+ half_width;
		top = center_Y -half_height-radius;
		bottom = center_Y + half_height;
		
		path.addRect(new RectF(left, top+radius, right, bottom),Direction.CW);
		path.moveTo(left, top+radius);
		path.lineTo(center_X, top);
		path.lineTo(right, top+radius);
		path.addArc(new RectF(left, top, right, top+2*radius), 180f, 90f);
		path.addArc(new RectF(left, top, right, top+2*radius), 270f, 90f);	
		path.addArc(new RectF(left, top, right, top+2*radius), 270f, 90f);
        path.close();
		
	}
	
	

}

	

Klasa XorGate

package com.adam_mistal.logicgateapp;

import android.graphics.RectF;
import android.graphics.Path.Direction;

public class XorGate extends Gate {
	static public final String[] TRUE_TABLE={"X1","X2","Y",
        "0","0","0",
        "0","1","1",
        "1","0","1",
        "1","1","0",
         };
	public XorGate(){
		setTwoInputGate();
		setText("XOR");	
		
	}
	

	@Override
	protected void makeUI(int c_x, int c_y) {		
		int radius;
		int half_width=50;
		radius=half_width;
		int half_height=50;
		this.center_Y=c_y;
		this.center_X=c_x;
		left = center_X - half_width;
		right = center_X+ half_width;
		top = center_Y -half_height-radius;
		bottom = center_Y + half_height;		
		path.addRect(new RectF(left, top+radius, right, bottom),Direction.CW);
		path.moveTo(left, top+radius);
		path.lineTo(center_X, top);
		path.lineTo(right, top+radius);
		path.addArc(new RectF(left, top, right, top+2*radius), 180f, 90f);
		path.addArc(new RectF(left, top, right, top+2*radius), 270f, 90f);	
        path.close();      		
	}

	@Override
	protected void updateOutPin() {
				if(in_pins[0].value != in_pins[1].value){
					outPin.setValue(true);
				}else{
					outPin.setValue(false);
				}
	}


}

	

Klasa Grid

package com.adam_mistal.logicgateapp;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
//klasa bedzie wyswietlac linie pionowa i poziomą
public class Grid {
	   private int width=60;
	   private int height=60;
	   private Paint paintBrushBlue = null;
	   private Paint paintBrushGreen = null;

	   public Grid(int w, int h) {
		   width=w;
		   height=h;

		   
		      paintBrushBlue = new Paint();
		      paintBrushBlue.setColor(Color.BLUE);

		      paintBrushGreen = new Paint();
		      paintBrushGreen.setColor(Color.WHITE);

		      paintBrushBlue.setAntiAlias(true);
		      paintBrushBlue.setDither(true);
		      paintBrushGreen.setAntiAlias(true);
		      paintBrushGreen.setDither(true);
		
	}

	public void draw(Canvas canvas)
	   {	
		
		canvas.drawLine(width/2, 0, width/2, height, paintBrushGreen);
		canvas.drawLine(0, height/2, width, height/2, paintBrushGreen);
	    
	   }
	}



	

LogicGate cz4 -opis klas

Opis aktywności odpowiedzialnej za testowanie bramek

Aktywność testująca bramki będzie wyświetlać określony zestaw  symboli :

  • przyciski on /off
  • bramkę logiczną
  • lampka (świeci się /nie świeci)
  • połączenia przycisków z bramką

Przyciski będą podawać sygnały wejściowe na bramkę. Następnie bramka przekaże swój wynik na lampkę  która będzie gasnąć lub zapalać się.

Główne klasy potrzebne do zaimplementowania tych czynności to

  • OnOffButton – przycisk
  • Gate – bramka
  • Wire – przewód, połączenia poszczególnych elementów
  • Lamp – nasze światło które będzie wskazywać wynik operacji wykonywanych przez bramkę
  • Pin- piny będą elementami do których będzie można wpinać przewody, Przyciski , lampy , bramki będą zawierać piny.

Poza tymi klasami powstanie kilka pomocniczych , o których napisze w trakcie implementacji.

Implementacja Klasy Pin

package com.adam_mistal.logicgateapp;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

public class Pin {
//wymiary obiektu
public static final int Height = 25;
public static final int Width=20;
//ustawienie obiektu na obiekcie typu Canvas
private int left=0;
private int top=0;
private float right;
private float bottom;
private int centerV=0;
//obiekt Paint służy do wypełniania kolorem
private Paint paintBrush = null;
//gdy pin będzie zawierał stan wysoki zmieni kolor na czerwony
private int colorON=Color.RED;
//gdy stan będzie niski kolor szary
private int colorOff=Color.GRAY;
//jeśli pin nie będzie pinem podającym napięcie
public boolean isMaster=false;
//obecny stan pinu//niski
boolean value=false;
//pin przechwytujący stan pinu będącego masterem
public Pin refPin=null;

public Pin(boolean master){
//jeśli true pin podaje sygnał
isMaster=master;
//utworzenie i ustawienie pędzla do rysowania
paintBrush = new Paint();
paintBrush.setColor(colorOff);
paintBrush.setAlpha(150);
paintBrush.setAntiAlias(true);
paintBrush.setDither(true);
}
/***
* Pozycjonowanie położenia pinu na płótnie
* @param vertical
*
* @param horizontal
*/

public void setCenter(int vertical,int horizontal) {

centerV=vertical;
left=vertical-Width/2;
top=horizontal;
right=left+Width;
bottom=top+Height;

}

/**
* rysujemy pin
* @param canvas
*/
public void draw(Canvas canvas) {
//rysuj prostokąt o podanych narożach
canvas.drawRect(left, top, right, bottom, paintBrush);

}
/**
* pobieramy współrzędne x,y położenia pinu
* @return
*/
public Point getPoint() {

return new Point(centerV,top);
}

/**
* Ustawiamy wartość pinu
* @param b
*/
public void setValue(boolean b) {
value=b;
//jeśli pin jest masterem to uaktualnij pin powiązany z nim
if(isMaster)refPin.setValue(value);
if(value==true)
{

paintBrush.setColor(colorON);
}else{

paintBrush.setColor(colorOff);
}

}

}

Obiekty klasy pin będą rysowane jako prostokąty o wymiarach 20/25 .

Implementacja Klasy Point

package com.adam_mistal.logicgateapp;

public class Point {
		public float x;
		public float y;
		/**
		 * Klasa przechowująca informacje o współrzędnych na płótnie
		 * @param _x
		 * @param _y
		 */
		public Point(float _x,float _y){
			x=_x;y=_y;
		}

	}

Kolejne klasy będę implementował w następnych postach.

LogicGateApp cz.3

Omówienie treści

W tym poście zajmiemy się stworzeniem nowych aktywności, które będą mogły być włączane przez menu główne nasze aplikacji. Tworzenie aktywności składać się będzie z:

  • utworzenia klasy dziedziczącej po Activity
  • utworzenia layoutu strony
  • dodania wpisu w AndroidManifest.xml

Na końcu postu podepniemy odpalanie aktywności do aktywności stworzonej w poprzednim poście.

Tworzymy layout naszych aktywności

chose_gate_layout.xml

Tworzymy nowy plik: chose_gate_layout.xml
Katalog pliku to: res->layout
Do katalogu drawable-hdpi wklejam zdjęcie które wykorzystam w stronie o autorze :)
layout
Edytujemy zawartość pliku strings.xml dodając napisy niezbędne dla przycisków.
strings2

Edytujemy zawartość pliku tak by osiągnąć zamierzony wygląd naszej aktywności.

layoutxml

Kod xml odpowiada za taki wygląd layoutu.

layout_graphic

about_author_layout.xml

Tworzymy nowy plik: about_author_layout.xml
Katalog pliku to: res->layout

aboutAuthorxml

Dodajemy napisy do strings.xml

strings3

Dodajemy style do app_styles.xml odpowiedzialne za formatowanie tekstu w layoucie.

styles2xml

Dodatkowo tworzymy plik color.xml w katalogu res->values. Plik zawiera  definicje kolorów które możemy używać w aplikacji.

color1

Wygląd:

aboutAuthorGraphic

Tworzymy klasy

ChoseGateActivity

Dodajemy do pakietu naszej aplikacji klasę ChoseGateActivity :

package com.adam_mistal.logicgateapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

public class ChoseGateActivity extends Activity {
	 @Override
	    protected void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.chose_gate_layout);
	        initButtons();
	    }

	private void initButtons() {
		final Button andButton = (Button) findViewById(R.id.and_button);
		andButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("ChoseGateActivity", "and");
				}
				return false;
			}
		});
		final Button orButton = (Button) findViewById(R.id.or_button);
		orButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("ChoseGateActivity", "or");
				}
				return false;
			}
		});
		final Button notButton = (Button) findViewById(R.id.not_button);
		notButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("ChoseGateActivity", "not");
				}
				return false;
			}
		});
		final Button nandButton = (Button) findViewById(R.id.nand_button);
		nandButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("ChoseGateActivity", "nand");
				}
				return false;
			}
		});
		final Button xorButton = (Button) findViewById(R.id.xor_button);
		xorButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("ChoseGateActivity", "xor");
				}
				return false;
			}
		});
		final Button returnButton = (Button) findViewById(R.id.return_button);
		returnButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("ChoseGateActivity", "return");
                                        finish();
				}
				return false;
			}
		});

	}

}

Analogicznie jak w głównej aktywności w metodzie initControls() łącze kod xml z kodem java. W 81 linijce użyłem metody finish() która zgodnie z intencjią czyli po naciśnięciu przycisku “Wróć” zamknie aktywność po czym przywołana zostanie aktywność poprzednia czyli MainActivity

AboutAuthorActivity

Dodajemy do pakietu naszej aplikacji klasę AboutAuthorActivity :

package com.adam_mistal.logicgateapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

public class AboutAuthorActivity extends Activity {
	 @Override
	    protected void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.about_author);
	        initButtons();
	    }

	private void initButtons() {
		final Button backButton = (Button) findViewById(R.id.return_button);
		backButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("AboutAuthorActivity", "return");
					finish();
				}
				return false;
			}
		});
		
	}

}

Dodajemy wpisy w AndroidManifest.xml

LogicGateActivity

manifest1

AboutAuthorActivity

manifest2

Podpinamy włączenie aktywności do MainActivity

W klasie MainActivity edytujemy:

final Button startButton = (Button) findViewById(R.id.start_button);
		startButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "startButton");
					Intent intent=new Intent(getBaseContext(),ChoseGateActivity.class);
					startActivity(intent);
				}
				return false;
			}
		});

final Button authorButton = (Button) findViewById(R.id.author_button);
		authorButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "authorButton");
					Intent intent=new Intent(getBaseContext(),AboutAuthorActivity.class);
					startActivity(intent);
				}
				return false;
			}
		});
final Button closeButton = (Button) findViewById(R.id.close_button);
		closeButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "closeButton");
					finish();
				}
				return false;
			}
		});

Odpalenie nowej aktywności osiągamy poprzez wywołanie metody startActivity pobierającej jako parametr obiekt typu Intent.

Konstruktor klasy Intent pobiera jako parametry obiekt typu Context oraz klasę która ma być wykonana.

Test

Przykładowy wygląd okna LogCat

logcattest

LogicGateApp cz.2 -tworzenie głownej aktywności

Praca nad oprogramowaniem menu głównego aplikacji składać się będzie z:

  • stworzenia GUI ,czyli interfejsu graficznego aplikacji
  • programowania activity odpowiedzialnego za działanie menu

Implementacja GUI

Przystępujemy do edycji pliku activity_main.xml czyli layoutu naszego activity.

layout-w androidzie jest to plik który zawiera informacje o wyglądzie naszej aplikacji (przyciski,pola tekstowe,grafiki…), layouty zapisywane są w plikach z rozszerzeniami xml

activity- jest to klasa odpowiedzialna za interakcję z użytkownikiem. Zarządza tworzeniem się okna , komunikacją z pozostałymi  elementami sytemu .

Obecnie nasz plik activity_main.xml wygląda następująco:

  • reprezentacja tekstowa

xml

  • reprezentacja graficzna

1

Skoro mamy już wizję jak ma wyglądać nasz layout przystąpmy do dzieła. Android daje nam możliwość definiowania styli poszczególnych elementów naszego interfejsu. Wiemy że każde nasze activity będzie zawierało nagłówek ,a dwa pierwsze activity przyciski menu. Możemy zatem utworzyć style które odnosić się będą do tych elementów. Zaletą takiego rozwiązania jest oszczędność czasu związanego z powtarzaniem tego samego kodu. Tworzymy plik app_styles.xml , opiszemy w nim między innymi rozmiary naszych elementów (TextView, Button).

plik app_styles.xml  tworzymy go w katalogu res->values

strings1

Styl określony jako pierwszy style name=”headerText” będzie odpowiadał za określenie wyglądu nagłówków naszych activities. Styl style name=”menuButton” będzie odpowiadał za określenie wyglądu przycisków menu. Otwórzmy teraz plik strings.xml. Zawiera on zasoby napisów które wykorzystamy w naszej aplikacji. Do pierwszego layoutu potrzebujemy napisów “START”,”AUTOR”,”KONIEC”,”LogicAppGate”. Dodajmy te napisy właśnie w tym pliku w sposób podany poniżej. plik strings.xml  jest w katalogu res->values

Edytujmy plik AndroidManifest.xml  manifest1 Zmieniając motyw aplikacji w ten sposób sprawimy że nie będzie ona zawierać paska tytułowego oraz będzie wyświetlana na całym ekranie. W tej chwili został na do edycji layout naszego activity. plik activity_main.xml 

activity_main_xml

reprezentacja graficzna

layout_1

Programowanie Activity

Nasza główna klasa MainActivitywygląda teraz następująco:

package com.adam_mistal.logicgateapp;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
 }

}

Klasa dziedziczy po klasie Activity. Metoda onCreate jest wywoływana w momencie tworzenia aktywności. Metoda setContentView(R.layout.activity_main) powoduje że wyświetlany jest layout activity_main.xml . Klasa ta zawiera wiele bardzo użytecznych metod. Część z nich będziemy wykorzystywać w naszej aplikacji.

Musimy teraz powiązać przyciski z aktywnością oraz napisać kod wykonywany w momencie kliknięcia na dany przycisk. Stworzę metodę o nazwie initControls() w której napisze odpowiedni kod.

metoda initControls()

private void initButtons() {
		final Button startButton = (Button) findViewById(R.id.start_button);
		startButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "startButton");
				}
				return false;
			}
		});
		final Button authorButton = (Button) findViewById(R.id.author_button);
		authorButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "authorButton");
				}
				return false;
			}
		});
		final Button closeButton = (Button) findViewById(R.id.close_button);
		closeButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "closeButton");
				}
				return false;
			}
		});

	}

 

final Button startButton = (Button) findViewById(R.id.start_button);

W ten sposób tworzymy referencjie do przycisku. Następuje połączenie reprezentacji graficznej przycisku z kodem java.

startButton

Metoda findViewById zwraca obiekt klasy Viewktóry jest rzutowany na interesujący nas element GUI. Jako parametr przyjmuje identyfikator który nadaliśmy przyciskowi w pliku xml.

startButton.setOnTouchListener(new View.OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					Log.i("MainActivity", "startButton");
				}
				return false;
			}
		});

Mamy wreszcie referencje do przycisku. W tym kodzie mówimy mu co ma się wykonać w momencie kliknięcia. Jako że nie dysponujemy innymi aktywnościami które moglibyśmy “odpalić”, sprawdźmy poprzez Log.i() czy przyciski faktycznie działają. Pożądanym działaniem będzie wyświetlenie się odpowiednich komunikatów w oknie LogCat. odpalmy naszą aplikację i sprawdźmy czy działa:) Kliknijmy po jednym razie na każdy przycisk.

metoda onCreate

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initButtons();
    }

Okno LogCat powinno wyglądać podobnie:):
logcat1

Napisaliśmy menu naszej aplikacji. W tej chwili jedynie wyświetla napisy w LogCat. Celem jest włączanie nowych aktywności w zależności od wybranego przycisku. Tak więc mamy do napisania dwie aktywności:

  • aktywność w której wybierzemy interesującą nas bramkę- ChoseGateActivity
  • aktywność wyświetlającą informację o autorze :)- AboutAuthorActivity

Tworzeniem tych aktywności zajmę się w następnym wpisie.

LogicGateApp cz.1 -pierwszy projekt

Pomysł na pierwszą aplikacje – określenie funkcjonalności

W poprzednim poście uruchomiliśmy emulator android. Jesteśmy w stanie testować aplikacje. Przystępujemy do pracy :) Napiszemy aplikacje która nietypowo nie będzie wyświetlać napisu hello world. Niech nasza aplikacja będzie użyteczną.
Nazwa aplikacji: LogicGateApp
Zadania aplikacji:

  • emulowanie działania bramek logicznych
  • wyświetlanie tablicy prawdy poszczególnych bramek logicznych

Pokrótce wyjaśnię że bramki logiczne to podstawowe elementy elektroniczne służące do konstrukcji układów cyfrowych. Każda bramka implementuje podstawową funkcję logiczną. Bramki logiczne  które będą implementowane w programie to:

  • AND iloczyn logiczny
  • OR suma logiczna
  • NOT negacja
  • NAND negacja iloczynu
  • XOR bramka równoważności

Skoro mam już określone wymagania zaprojektuje wygląd poszczególnych okien  aplikacji.

activities_plan

Wiemy już jak aplikacja będzie wyglądać od strony użytkownika, wiemy też jakie funkcje ma spełniać. Przystąpmy do kodowania.

Projekt w eclipse – pierwsze Activity

Tworzymy nowy projekt w eclipse: File->New->Android Aplication Project następnie w opcjach dodawania nowego projektu wypełniamy odpowiednie pola jak na rysunku poniżej.

new_android_project

Po przejściu dalej możemy wybrać ikonę dla naszego projektu. Można wybrać z pliku lub też z przygotowanych w eclipse clipartów. Do celów tego programu wybiorę clipart.

luncher_and

Koleje okna wyboru dotyczą rodzaju tworzonego Activity czyli odpowiednika okna w systemie Windows.

create_activity1

createActivity2

Klikamy Finish .Udało się nam stworzyć pierwszy projekt w eclipse. Już na tym etapie jesteśmy w stanie uruchomić naszą aplikację. Jedyną rzeczą którą nam się ukaże będzie napis Hello World. Włączmy nasz emulator który utworzyliśmy w poprzednim poście. Następnie musiby zbudować nasz projekt możemy to zrobić klikając Project->Build All (CTR+B). Klikamy PPM na węzeł naszego pakietu i wybieramy polecenie Run As-> Android Aplication

LogicGateApp1

Po kilku chwilach aplikacja instaluje się na emulatorze który włączyliśmy uprzednio. Mamy pewność że wszystko poszło tak jak trzeba.

firstActivity

W następnym wpisie opisze strukturę projektu w środowisku eclipse.

Uruchamiamy AVD- Android na PC :)

Utworzyliśmy ostatnio emulator androida. Jest obecnie wyłączony i czeka tylko na nas byśmy mogli go odpalić :) A więc do dzieła, wybieramy nasz emulator i klikamy : Android Virtual Device Manager->Start…

avd3

W oknie Lunch Options ustawiamy odpowiednio wartości:

  • Screen Szie(in)-rozmiar do jakiego ma się skalować okno emulatora. W moim przypadku jest to 5 cali.
  • Wipe user data- zaznaczenie tego pola oznaczać będzie że jeśli mamy na urządzeniu wirtualnym nasze dane to zostaną one utracone(np. aplikacje, pliki bazy danych)

Następnie uruchamiamy emulator przyciskiem Launch . Stało się :) emulator wystartował
emulator1

emulator2

Tworzenie AVD-Android Virtual Device

Mając skonfigurowane środowisko pracy ostatnią rzeczą potrzebną nam do pracy jest możliwość testowania aplikacji. Do tego celu możemy wykorzystać fizyczne urządzenie z systemem android jak również AVD czyli android virtual device. W tym poście zajmiemy się drugim sposobem czyli utworzymy wirtualne urządzenie android na naszym komputerze. Wybieramy w eclipse Window->AVD Manager. W oknie managera wybieramy New

avd1

Wypełniamy pola w zależności od wersji systemu Android który ma emulować nasze urządzenie. W moim przypadku jest to wersja 2.3.3. Nazwa jest dowolna jej określenie ma za zadanie pomóc na przy rozróżnieniu emulatorów wybieranych przez nas do testów .Dodatkowo zaznaczyłem emulacje karty SD oraz określiłem jaka przestrzeń dyskowa zostanie jej przekazana. Jak widać można również dokonać zmian innych parametrów tworzonego emulatora. Klikamy Create AVD. Emulator został dodany do listy managera jak pokazałem na screenie poniżej.

avd2

Możemy utworzyć kilka emulatorów w celu testowania naszych aplikacji na różnych wersjach systemów czy też różnych rozdzielczościach. Udało się nam stworzyć emulator urządzenia android który możemy uruchomić na naszym komputerze.