Android Studio를 활용한 안드로이드 프로그래밍 P364 직접 풀어보기 9-2


아래의 결과 화면 처럼 메뉴를 이용해 도형을 그리고 서브메뉴를 이용해 도형의 색깔을 선택되게 한다.


























<MainActivity 코드>

1. 도형을 그릴 때 초기 시작 값(도형)은 라인긋기로 되어있기 때문에 이를 이용해서 기본 색깔도 별도의 변수로 지정해줍니다.

2. onOptionsItemSelected 메소드 내부의 switch case문에 4~6번 case(색깔 선택)문을 추가해줍니다.

3. onDraw메소드에서 두개의 switch ~case문을 작성합니다. 하나는 도형, 나머지는 색깔에 관한 switch문입니다.

이 때 색깔선택switch문을 도형선택switch문 전에 작성해야합니다.

두 문장의 순서가 바뀔 시 paint 변수 선언(색깔 디폴트 값 :검정)-> 도형 그리기-> 색깔 선택-> paint변수 선언..........

식으로 이어지기 때문에 선택한 색깔로 바뀌지않고 검정색만 사용됩니다. 

즉, 색깔 선택-> 도형 선택으로 이어지게끔 색깔 선택 swith문을 먼저 수행하게 해야합니다.

package com.example.p364;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;

public class MainActivity extends AppCompatActivity {

final static int LINE=1, CIRCLE=2,RECT=3,color_RED=4,color_GREEN=5,color_BLUE=6;
//final => 상수의 의미
//static=> 전역의 의미
// final static => 전역 상수
int current_shape=LINE;//기본 값
int current_color=color_RED;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0,1,0,"선 그리기");
menu.add(0,2,0,"원 그리기");
menu.add(0,3,0,"사각형 그리기");

SubMenu sub=menu.addSubMenu("색상 변경");
sub.add(0,4,0,"빨간색");
sub.add(0,5,0,"초록색");
sub.add(0,6,0,"파란색");
return true;
}

@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {

switch(item.getItemId())
{
case 1:
current_shape=LINE;
break;
case 2:
current_shape=CIRCLE;
break;
case 3:
current_shape=RECT;
break;
case 4:
current_color=color_RED;
break;
case 5:
current_color=color_GREEN;
break;
case 6:
current_color=color_BLUE;
break;
}
return true;
}

private class MyGraphicView extends View {
int startX=-1,startY=-1,stopX=-1,stopY=-1;
public MyGraphicView(Context context) {
super(context);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
startX=(int)event.getX();
startY=(int)event.getY();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
stopX=(int)event.getX();
stopY=(int)event.getY();
this.invalidate();
break;
}

return true;
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint=new Paint();
paint.setStrokeWidth(10);
paint.setStyle(Paint.Style.STROKE);

switch(current_shape)
{
case LINE:
canvas.drawLine(startX,startY,stopX,stopY,paint);
break;
case CIRCLE:
int radius=(int)Math.sqrt(Math.pow(stopX-startX,2)+Math.pow(stopY-startY,2));
canvas.drawCircle(startX,startY,radius,paint);
break;
case RECT:
canvas.drawRect(new Rect(startX,startY,stopX,stopY),paint);
break;

}
switch(current_color)
{
case color_RED:
paint.setColor(Color.RED);
break;
case color_GREEN:
paint.setColor(Color.GREEN);
break;
case color_BLUE:
paint.setColor(Color.BLUE);
break;
}
}
}
}















'Android Studio를 활용한 안드로이드 프로그래밍' 카테고리의 다른 글

직접 풀어보기 9-3  (2) 2020.06.08
직접 풀어보기 9-1  (0) 2020.06.07
직접 풀어보기 8-2  (15) 2020.05.20
직접 풀어보기 8-1  (0) 2020.05.20
직접 풀어보기 7-3  (0) 2020.05.19


Android Studio를 활용한 안드로이드 프로그래밍 P358 직접 풀어보기 9-1


그림과 같은 화면을 출력하도록 다음 메소드를 사용하여 JAVA를 코딩하라.

1. Paint.setStrokeCap()

2. Canvas.drawOval()

3. Paint.setColor(Color.argb())


<결과 화면>



<MainActivity 코드>

1. 첫 번째, 두 번째 사각형 모두 사각형이 아닌 선으로 그리고, 선의 두께를 50으로 설정하여 사각형처럼 보이게 그려봤습니다.

2. 두 번 째 사각형의 경우 Paint. setStrokeCap()함수의 옵션 내부에 인자로 Paint.Cap.Round로 하여 모서리를 둥글게 표현했습니다.

3. 타원의 경우 drawOval 함수로 좌표를 설정하여 그리면 됩니다.

4. 부채꼴(호)의 경우 전체 좌표를 지정하고(사각형 처럼 4가지) 시작 지점(startAngle)과 깎을 지점(sweepAngle)을 설정하여 부채꼴 모양을 형성합니다. 깎는 좌표에 따라 원, 반원, 등 다양한 모양이 생성될 수 있습니다.

5. 부분 투명 사각형은 빨간 사각형이 반투명하기 때문에 빨간 사각형의 투명도를 조정해야합니다.  Paint.setColor(Color.argb())함수 안의 인자는 각각 투명도, R,G,B색을 의미하므로 투명도를 0~255값의 중간인120을 넣어주고 R좌표값을 255로 채웠습니다.

package com.example.p358;

import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyGraphicView(this));
}

private class MyGraphicView extends View {

public MyGraphicView(Context context) {
super(context);
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint=new Paint();
paint.setColor(Color.BLACK);
paint.setStrokeWidth(50);

canvas.drawLine(70,70,370,70,paint);

paint.setStrokeCap(Paint.Cap.ROUND);
Rect f=new Rect(70,140,370,140);


canvas.drawOval(new RectF(70, 210, 70 + 300, 210 + 140), paint);

canvas.drawArc(new RectF(70,280,70+300,280+210),35,100,true,paint);

Rect rect1=new Rect(100,600,100+200,600+200);
paint.setColor(Color.BLUE);
canvas.drawRect(rect1,paint);

Rect rect2=new Rect(100+60,600+60,100+60+200,600+60+200);
paint.setColor(Color.argb(120,255,0,0));
canvas.drawRect(rect2,paint);

}
}
}




'Android Studio를 활용한 안드로이드 프로그래밍' 카테고리의 다른 글

직접 풀어보기 9-3  (2) 2020.06.08
직접 풀어보기 9-2  (0) 2020.06.08
직접 풀어보기 8-2  (15) 2020.05.20
직접 풀어보기 8-1  (0) 2020.05.20
직접 풀어보기 7-3  (0) 2020.05.19


문제

이진 탐색트리의 삽입, 삭제, 탐색, 순회 및 출력 기능을 바탕으로 학생의 이름과 전화번호를 관리하는 이진탐색트리를 구현하라.


풀이

각 기능을 수행하는 함수는 책에서 학습 할 수 있지만 삭제 함수의 경우, 제가 갖고있는 2권의 자료구조책에는 삭제함수를 반복문으로 구현했는데, 물론 기능적인 면에서 순환방식보다 빠르고 효율적이지만 코드가 복잡하고, 혼자서 머릿속으로 구현하기가 힘든 것 같아 순환방법의 구현을 공부했습니다.

구현 면에서는 반복문보다 순환호출이 더 이해와 구현이 쉬운 것 같습니다.

주의할 것은 삭제함수에 if문이 많은데 각 경우를 if로 표현하면 학생 정보를 삭제하고 출력 시 원하지 않는 결과가 나올 수 있습니다. 

반드시 if~ else if ~ else 문으로 함수를 작성해야합니다. 



그리고 가끔 이런 학생정보 관리 프로그램이나 사전 프로그램 등을 구현하다보면 꼭 공백이나 엔터키가 말썽을 부렸는데

다행히 아래 코드처럼 작성하니 엔터키 관련해서는 오류가 뜨지않았습니다.

133~134행을 주석 처리 후 135~136행을 작성 후 실행 하면 원하는 기능의 알파벳 입력 시 한글을 입력하면 엔터키 오류가 뜹니다.



코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// 이진 탐색 트리를 사용한 영어 사전
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
 
#define MAX_WORD_SIZE     100
#define MAX_MEANING_SIZE 200
 
// 데이터 형식
typedef struct {
    char name[MAX_WORD_SIZE];        // 키필드
    char number[MAX_MEANING_SIZE];
} element;
// 노드의 구조
typedef struct TreeNode {
    element key;
    TreeNode* left, * right;
} TreeNode;
 
// 만약 e1 < e2 이면 -1 반환
// 만약 e1 == e2 이면 0 반환
// 만약 e1 > e2 이면 1 반환
int compare(element e1, element e2)
{
    return strcmp(e1.name, e2.name);
}
// 이진 탐색 트리 출력 함수
void display(TreeNode* p)
{
    if (p != NULL) {
        //printf("(");
        display(p->left);
        printf("이름:%s\n전화번호%s\n", p->key.name, p->key.number);
        display(p->right);
        //printf(")");
    }
}
// 이진 탐색 트리 탐색 함수
TreeNode* search(TreeNode* root, element key)
{
    TreeNode* p = root;
    while (p != NULL) {
        if (compare(key, p->key) == 0)
            return p;
        else if (compare(key, p->key) < 0)
            p = p->left;
        else if (compare(key, p->key) > 0)
            p = p->right;
    }
    return p;     // 탐색에 실패했을 경우 NULL 반환
}
TreeNode* new_node(element item)
{
    TreeNode* temp = (TreeNode*)malloc(sizeof(TreeNode));
    temp->key = item;
    temp->left = temp->right = NULL;
    return temp;
}
TreeNode* insert_node(TreeNode* node, element key)
{
    // 트리가 공백이면 새로운 노드를 반환한다. 
    if (node == NULLreturn new_node(key);
 
    // 그렇지 않으면 순환적으로 트리를 내려간다. 
    if (compare(key, node->key) < 0)
        node->left = insert_node(node->left, key);
    else if (compare(key, node->key) > 0)
        node->right = insert_node(node->right, key);
    // 루트 포인터를 반환한다. 
    return node;
}
TreeNode* min_value_node(TreeNode* node)
{
    TreeNode* current = node;
    // 맨 왼쪽 단말 노드를 찾으러 내려감
    while (current->left != NULL)
        current = current->left;
    return current;
}
// 이진 탐색 트리와 키가 주어지면 키가 저장된 노드를 삭제하고 
// 새로운 루트 노드를 반환한다. 
TreeNode* delete_node(TreeNode* root, element key)
{
    if (root == NULLreturn root;
 
    // 만약 키가 루트보다 작으면 왼쪽 서브 트리에 있는 것임
    if (compare(key, root->key) < 0)
        root->left = delete_node(root->left, key);
    // 만약 키가 루트보다 크면 오른쪽 서브 트리에 있는 것임
    else if (compare(key, root->key) > 0)
        root->right = delete_node(root->right, key);
    // 키가 루트와 같으면 이 노드를 삭제하면 됨
    else {
        // 첫 번째나 두 번째 경우
        if (root->left == NULL) {
            TreeNode* temp = root->right;
            free(root);
            return temp;
        }
        else if (root->right == NULL) {
            TreeNode* temp = root->left;
            free(root);
            return temp;
        }
        // 세 번째 경우
        TreeNode* temp = min_value_node(root->right);
 
        // 중외 순회시 후계 노드를 복사한다. 
        root->key = temp->key;
        // 중외 순회시 후계 노드를 삭제한다. 
        root->right = delete_node(root->right, temp->key);
    }
    return root;
}
 
//
void help()
{
    printf("삽입(i), 탐색(s),프린트(p), 삭제(d): ");
}
// 이진 탐색 트리를 사용하는 영어 사전 프로그램 
int main(void)
{
    char command;
    element e;
    TreeNode* root = NULL;
    TreeNode* tmp;
 
    while(1){
        help();
        //command = getchar();
        //getchar();        // 엔터키 제거
        scanf(" %c"&command);
        getchar();
        switch (command) {
        case 'i':
            printf("친구의 이름: ");
            scanf(" %s", e.name);
            getchar();
            printf("친구의 전화번호: ");
            scanf(" %s", e.number);
            getchar();
            root = insert_node(root, e);
            break;
        case 'd':
            printf("이름:");
            scanf(" %s", e.name);
            getchar();
            root = delete_node(root, e);
            break;
        case 'p':
            display(root);
            printf("\n");
            break;
        case 's':
            printf("친구의 이름:");
            scanf(" %s", e.name);
            getchar();
            tmp = search(root, e);
            if (tmp != NULL)
                printf("%s의 전화번호:%s\n",tmp->key.name, tmp->key.number);
            else
                printf("데이터가 존재하지 않습니다.\n");
            break;
        case 'q':return 0;
        default
            printf("잘못입력습니다.재입력하세요\n");
 
        }
 
    }/* while (command != 'q');*/
    return 0;
}
cs


결과






기존의 트리 순회 알고리즘(중위, 전위, 후위) 은 모두 순환호출(=스택)을 이용한 알고리즘이었습니다.

순환의 특성 상 트리의 높이가 커질수록 순환의 깊이가 깊어져서 상당히 비효율적일 수 있습니다.

쓰레드 이진트리는 노드의 NULL링크를 활용하여 순환 호출없이, 즉 반복문으로 순회할 수 있는 방법입니다.


선행 노드인 중위 선행자나 중위 순회 시 후속노드인 중위 후속자를 저장 시켜놓은 트리가 쓰레드 이진트리입니다.


중위 순회를 한다고 가정하여 중위 후속자를 저장한 쓰레드 이진트리를 구현해 보겠습니다.

일단 treeNode구조체에 쓰레드 정보를 가질 is_thread변수를 추가합니다. 값이 1이면 쓰레드를 가지고, 0이면 일반적인 트리입니다.


구현 함수는 2가지가 있습니다.

1. 쓰레드 중위순회 함수

후속자를 찾아 순서대로 출력합니다.


2. 중위 후속자를 찾는 함수( 중위 후속자를 반환)

=> 노드가 쓰레드를 가지면(is_thread==1) 오른쪽 자식을 반환합니다.

위 트리를 구성하는 과정에서 A와 C, B와G, D와F를 연결시켜놨기 때문에 쓰레드를 갖는 노드의 오른쪽 자식은 후속자가 됩니다.

현재 노드의 오른쪽자식 노드가 NULL이거나 p가 쓰레드를 가지면 q를 반환합니다.

(NULL일경우 1번함수에서 걸러지고, p가 쓰레드를 가지면 오른쪽 자식노드가 있음을 알기 때문)

그리고 G나 F같은 일반 노드 같은경우, 중위순회를 위해 서브 트리의 가장 왼쪽으로 가는 연산식이 필요합니다.


순회 순서는 순환방법과 똑같기 때문에 후속자를 찾는 포인트만 알고 있으면 구현이 어렵지 않습니다.


코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<stdio.h>
#include<string.h>
#define TRUE 1
#define FALSE 0
#define size 10
typedef struct treeNode
{
    int data;
    struct treeNode* left, * right;
    int is_thread;
}treeNode;
 
treeNode n1 = { 'A',NULL,NULL,1 };
treeNode n2 = { 'B',NULL,NULL,1 };
treeNode n3 = { 'C',&n1,&n2,0 };
treeNode n4 = { 'D',NULL,NULL,1 };
treeNode n5 = { 'E',NULL,NULL,0 };
treeNode n6 = { 'F',&n4,&n5,0 };
treeNode n7 = { 'G',&n3,&n6,0 };
treeNode* exp = &n7;
void thread_inorder(treeNode* t);
treeNode* find_successor(treeNode* p);
int main()
{
    //쓰레드를 설정한다.
    n1.right = &n3;
    n2.right = &n7;
    n4.right = &n6;
    thread_inorder(exp);
}
void thread_inorder(treeNode* t)
{
    treeNode* q;
    q = t;
    while (q->left)q = q->left;
    do {
        printf("%c ", q->data);
        q = find_successor(q);
    } while (q);
    puts("");
}
treeNode* find_successor(treeNode* p)
{
    treeNode* q = p->right;
    //q가 NULL일 때도 반환(어짜피 중위순회 함수에서 NULL을 받아 걸러짐
    //p가 (q의 오른쪽자식이) 쓰레드면 바로 반환
 
    if (q == NULL || p->is_thread == TRUE)
        return q;
    //G, F 같은 일반 노드의 경우 중위순회를 위해 맨 왼쪽노드를 찾음
    while (q->left != NULL)q = q->left;
    return q;
}
cs


결과





Android Studio를 활용한 안드로이드 프로그래밍 P349 직접 풀어보기 8-2


실습 8-2 를 다음과 같이 수정하라.

1. "이전 그림" 버튼과 "다음 그림" 버튼 사이에 "현재번호/전체 그림 갯수"를 의미하는 텍스트뷰 표시하기

2. 토스트 메시지를 없애고, 첫 번 째 그림에서 "이전그림"클릭 시 마지막 그림을,

마지막 그림에서 "다음 그림" 클릭 시 첫 번 째 그림을 나오게하기. (텍스트뷰도 갱신되어야함)



*한번 실행 후 프로젝트를 다시 실행할 때 화면이 꺼지거나 오류가 발생하면 AVD를 재부팅 하여 실행해야합니다.


<출력화면>

저는 sd카드의 Pictrues폴더에 그림파일을 7개 넣어두고 시작했습니다.


1. 최초 실행 화면


2. 첫 번째 그림화면에서 "이전 그림" 버튼 출력 후 


3. 맨 마지막 그림화면에서 "다음 그림" 버튼 클릭 후



<activity_main.xml 코드>

사용한 이미지가 총7개이므로 최초의 텍스트뷰의 텍스트를 "1/7"로 설정했습니다.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnPrev"
android:text="이전그림"
android:layout_weight="1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1/7"
android:textSize="20sp"
android:id="@+id/textview1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnNext"
android:text="다음그림"
android:layout_weight="1"/>
</LinearLayout>
<com.example.a8_2practice.myPictrueView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/myPictureView1"/>
</LinearLayout>


<MainActivity 코드>

문제에서 "현재번호/전체 그림 갯수"를 나타내는 위젯을 텍스트뷰로 나타나게 하라고 한 것을 주의하셔야합니다.

즉, 숫자를 어떻게 텍스트뷰로 표현할까? 


방법1. 계산기 프로그램과 비슷하게 Integer와 toString()함수를 이용한다.

간단하게 TextView형 변수.setText(Integer.toString(int형변수)); 로 작성할 수 있는데

구글링으로 다른 방법을 찾아보다가 아래 방법으로 풀어봤습니다.

일단 정수 CurNum을 Integer 타입으로 캐스팅 해야합니다. (integer와 int 는 다름. integer는 객체)

int CurNum=0;

Integer num=new Integer(CurNum);

이렇게 작성 후 텍스트뷰로 출력할 때 num을 toString()함수로 문자열로 변환 후 출력하면 됩니다.


방법2. int형 변수를 String으로 출력한다.(이 방법 사용)

숫자를 문자열로 변환하고 싶으면 아래와 같이 작성하면 됩니다.

String.valueOf(int형 변수명)


*방법1, 방법2 모두 자바의 문법입니다. (캐스팅 방법)


주의할 것은 배열의 인덱스입니다. 텍스트뷰의 시작은 1부터 시작하지만 배열은 0부터 시작하기 때문입니다.

나머지 코드는 전체코드를 읽어보시면 이해가 쉬울 것 같습니다. 

package com.example.a8_2practice;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;

public class MainActivity extends AppCompatActivity {
Button btnPrev,btnNext;
myPictrueView mypicture;
int curNum=1;
File[] imageFiles;
String imageFname;
TextView textView1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("간단 이미지뷰어");
ActivityCompat.requestPermissions(this,new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE},MODE_PRIVATE);
btnPrev=(Button)findViewById(R.id.btnPrev);
btnNext=(Button)findViewById(R.id.btnNext);
textView1=(TextView)findViewById(R.id.textview1);
mypicture=(myPictrueView)findViewById(R.id.myPictureView1);
imageFiles= new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pictures").listFiles();
imageFname=imageFiles[0].toString();
mypicture.imagePath=imageFname;
btnPrev.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(curNum<=1)
{
curNum=imageFiles.length;
imageFname=imageFiles[curNum-1].toString();
mypicture.imagePath=imageFname;
mypicture.invalidate();
textView1.setText(String.valueOf(curNum)+"/"+String.valueOf(imageFiles.length));
//Toast.makeText(getApplicationContext(),"첫번쨰 그립입니다.",Toast.LENGTH_SHORT).show();
}
else
{
curNum--;
imageFname=imageFiles[curNum-1].toString();
mypicture.imagePath=imageFname;
mypicture.invalidate();
textView1.setText(String.valueOf(curNum)+"/"+String.valueOf(imageFiles.length));
}
}
});
btnNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(curNum>=imageFiles.length)
{
curNum=1;
imageFname=imageFiles[curNum-1].toString();
mypicture.imagePath=imageFname;
mypicture.invalidate();
textView1.setText(String.valueOf(curNum)+"/"+String.valueOf(imageFiles.length));
//Toast.makeText(getApplicationContext(),"마지막 그림입니다.",Toast.LENGTH_SHORT).show();
}
else {curNum++;
imageFname=imageFiles[curNum-1].toString();
mypicture.imagePath=imageFname;
mypicture.invalidate();}
textView1.setText(String.valueOf(curNum)+"/"+String.valueOf(imageFiles.length));
}
});
}
}







'Android Studio를 활용한 안드로이드 프로그래밍' 카테고리의 다른 글

직접 풀어보기 9-2  (0) 2020.06.08
직접 풀어보기 9-1  (0) 2020.06.07
직접 풀어보기 8-1  (0) 2020.05.20
직접 풀어보기 7-3  (0) 2020.05.19
직접 풀어보기 7-2  (4) 2020.05.19


Android Studio를 활용한 안드로이드 프로그래밍 P335 직접 풀어보기 8-1


실습 8-1을 처음 실행하면 데이트피커의 초기날짜(2020-5-19)에 텍스트파일이 있을 경우 

그날의 일기가 뜨지않고 아래와 같은 화면이 뜨는데, 초기날짜의 텍스트파일이 있을 경우 에디드텍스트에

일기를 출력하고, 일기가없을 시 "일기 없음" 힌트가 나오고 버튼은 <새로 저장> 이 되게 수정하라.


<수정 전 화면(실습 8-1)>



<수정 후 화면>

1. 최초 실행 시 데이트피커에 설정 된 날짜(2020-5-19)에 텍스트가 없을 때 


2. 최초의 데이트피커 날짜값의 파일(2020_5_19.txt)이 있을 경우

(실행 전 2020_5_19에 해당하는 텍스트파일을 만들고 내용 작성 후 내장 메모리에 저장해야합니다.)



activity_main.xml 코드

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<DatePicker
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/datePicker"
android:datePickerMode="spinner"
android:calendarViewShown="false"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edtDiary"
android:background="#00ff00"
android:lines="8"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="BUTTON"
android:enabled="false"
android:id="@+id/btnWrite"/>

</LinearLayout>



MainActivity 코드

우선, pc바탕화면에서 초기의 데이트피커에 설정된 날짜에 해당하는 메모장파일을 만들어 내용을 입력 후 저장 한 다음, 

안드로이드 스튜디오의 해당 응용프로그램(진행 중인 프로젝트)의 내장 메모리(data/data/패키지명/files)에 만들어둔 파일을 업로드합니다.


코드를 보면, 실습 코드의 init메소드는 데이트 피커의 초기값을 설정해주고 날짜 변경리스너를 포함하기 때문에

초기화 메소드전에 아래와 같은 코드를 작성하여 최초 실행 시 기본으로 설정되어있는 데이트피커의 날짜 값에 해당하는 

메모장이 있을 경우 에디트텍스트로 출력할 수 있게 합니다.

String filename1= Integer.toString(cYear)+"_"+Integer.toString(cMonth+1)+"_"+Integer.toString(cday)+".txt";
String str1=readDiary(filename1);
edtDiary.setText(str1);
btnWrite.setEnabled(true);

전체코드는 아래와 같습니다.

package com.example.p327test;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.zip.Inflater;

public class MainActivity extends AppCompatActivity {
String filename;
DatePicker dp;
Button btnWrite;
EditText edtDiary;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dp=(DatePicker)findViewById(R.id.datePicker);
btnWrite=(Button)findViewById(R.id.btnWrite);
edtDiary=(EditText)findViewById(R.id.edtDiary);
setTitle("간단 일기장");
Calendar cal=Calendar.getInstance();
int cYear=cal.get(Calendar.YEAR);
int cMonth=cal.get(Calendar.MONTH);
int cday=cal.get(Calendar.DAY_OF_MONTH);
String filename1= Integer.toString(cYear)+"_"+Integer.toString(cMonth+1)+"_"+Integer.toString(cday)+".txt";
String str1=readDiary(filename1);
edtDiary.setText(str1);
btnWrite.setEnabled(true);

dp.init(cYear,cMonth,cday, new DatePicker.OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker datePicker, int i, int i1, int i2) {
filename=Integer.toString(i)+"_"+ Integer.toString(i1+1)+"_"+Integer.toString(i2)+".txt";
String str=readDiary(filename);
edtDiary.setText(str);
btnWrite.setEnabled(true);
}
});
btnWrite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
FileOutputStream outfs=openFileOutput(filename, Context.MODE_PRIVATE);
String str=edtDiary.getText().toString();
outfs.write(str.getBytes());
outfs.close();
Toast.makeText(getApplicationContext(),filename+"이 저장됨",Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}

String readDiary(String filename) {
String diaryStr=null;
FileInputStream infs;
try {
infs=openFileInput(filename);
byte txt[]=new byte[500];
infs.read(txt);
infs.close();
diaryStr=(new String(txt)).trim();
btnWrite.setText("수정하기");
} catch (FileNotFoundException e) {
edtDiary.setHint("일기없음");
btnWrite.setText("새로 저장");
} catch (IOException e) {
e.printStackTrace();
}
return diaryStr;
}
}








'Android Studio를 활용한 안드로이드 프로그래밍' 카테고리의 다른 글

직접 풀어보기 9-1  (0) 2020.06.07
직접 풀어보기 8-2  (15) 2020.05.20
직접 풀어보기 7-3  (0) 2020.05.19
직접 풀어보기 7-2  (4) 2020.05.19
직접 풀어보기 7-1  (0) 2020.05.18


Android Studio를 활용한 안드로이드 프로그래밍 P317 직접 풀어보기 7-3


실습7-3을 다음과 같이 수정하라.

(일단 7-3실습 코딩을 해보시면 쉽게 수정 할 수 있습니다.)


1. Activity Main.xml의 텍스트뷰를 에디트 텍스트로 변경


2. <여기를 클릭> 클릭 시 Activity Main.xml의 에디트텍스트 내용이 대화 상자의 에디트텍스트에 나타남


3. 대화상자에서 <확인> 클릭 시 대화상자의 에디트텍스트 내용이 Activity main.xml의 에디트텍스트 내용으로 변경되게 한다.

(즉, 열려진 대화상자에서 정보 수정 후 '확인'을 누르면 main의 에디트텍스트가 수정됨)


4. 대화상자에서 <취소> 클릭 시 토스트가 화면의 임의 위치에 나타나게 함



결과 화면

1. 바깥의 EditText에 이름, 이메일 작성



2. <여기를 클릭> 클릭 후 대화상자화면



3. 대화상자에서 정보 수정 후 <확인> 버튼 클릭 후


4. <취소>버튼 누를 시 랜덤위치에 토스트 출력



dialog1.xml 코드(대화 상자)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="사용자 이름"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edit1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="이메일"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edit2"/>

</LinearLayout>


toast1.xml (토스트 뷰)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff0000"
android:gravity="center">
<ImageView
android:layout_width="10dp"
android:layout_height="10dp"
android:src="@drawable/pic01"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:textSize="20sp"
android:text="textview"/>
<ImageView
android:layout_width="10dp"
android:layout_height="10dp"
android:src="@drawable/pic01"/>

</LinearLayout>


activity_main.xml 코드

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal">

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tvName"
android:hint="사용자 이름"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tvEmail"
android:hint="이메일"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="여기를 클릭"/>

</LinearLayout>



MainActivity 코드

토스트뷰를 랜덤위치에 출력해주는 함수들만 조심하면 될 것 같습니다. 

random함수가 0~1의 임의의 수를 구해주는데 거기에 랜덤 좌표를곱하기때문에 토스트가 랜덤위치에 찍히게 됩니다.

그리고 EditText -> TextView의 경우, 읽어들인 EditText값을 문자열로 변환한 후 TextView에 저장해야하지만

이 문제는 EditeText->EditText의 경우이므로 굳이 문자열변환함수 toString()을 쓰지 않아도됩니다.

package com.example.a7_3;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
EditText tvName,tvEmail;
EditText dlgEdtName,dlgEdtEmail;
TextView toastText;
View dialogView, toastView;
Button btn1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("사용자 정보 입력");
tvName=(EditText) findViewById(R.id.tvName);
tvEmail=(EditText) findViewById(R.id.tvEmail);
btn1=(Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dialogView=(View)View.inflate(MainActivity.this,R.layout.dialog1,null);
AlertDialog.Builder dlg=new AlertDialog.Builder(MainActivity.this);
dlg.setTitle("사용자 정보 입력");
dlg.setIcon(R.mipmap.ic_launcher);
dlg.setView(dialogView);
dlgEdtName=(EditText)dialogView.findViewById(R.id.edit1);
dlgEdtEmail=(EditText)dialogView.findViewById(R.id.edit2);

//에딧텍스트의 문구를 에딧텍스트에 복사하므로 .toString()함수 필요x
dlgEdtName.setText(tvName.getText());
dlgEdtEmail.setText(tvEmail.getText());
dlg.setPositiveButton("확인", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
tvName.setText(dlgEdtName.getText());
tvEmail.setText(dlgEdtEmail.getText());
}
});

dlg.setNegativeButton("취소", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
Toast toast=new Toast(MainActivity.this);
toastView=(View)View.inflate(MainActivity.this,R.layout.toast1,null);
toastText=(TextView)toastView.findViewById(R.id.textView);
toastText.setText("취소했습니다.");
toast.setView(toastView) ;
Display display=((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int xoffset=(int)(Math.random()*display.getWidth());
int yoffset=(int)(Math.random()*display.getHeight());
toast.setGravity(Gravity.TOP | Gravity.LEFT,xoffset,yoffset);
toast.show();
}
});
dlg.show();
}
});
}
}











'Android Studio를 활용한 안드로이드 프로그래밍' 카테고리의 다른 글

직접 풀어보기 8-2  (15) 2020.05.20
직접 풀어보기 8-1  (0) 2020.05.20
직접 풀어보기 7-2  (4) 2020.05.19
직접 풀어보기 7-1  (0) 2020.05.18
직접 풀어보기 6-3  (5) 2020.05.11


Android Studio를 활용한 안드로이드 프로그래밍 P301 직접 풀어보기 7-2


ContextMenu를 이용해 아래의 앱을 만드는데, 컨텍스트 메뉴XML파일 없이 JAVA코드로만 완성하시오.




XML코드

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:id="@+id/baseLayout">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"
android:text="배경색 변경"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"
android:text="버튼변경"/>



</LinearLayout>


MainActivity 코드

위젯별로 컨텍스트 메뉴가 나타나야 하므로, 메뉴파일 등록클래스(onCreateContextMenu)내부에

위젯별 컨텍스트 메뉴를 if문으로 등록합니다.

package com.example.a7_2test;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Color;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {
Button button1,button2;
LinearLayout baseLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("배경색 바꾸기(컨텍스트)");
baseLayout=(LinearLayout)findViewById(R.id.baseLayout);
button1=(Button)findViewById(R.id.button1);
registerForContextMenu(button1);
button2=(Button)findViewById(R.id.button2);
registerForContextMenu(button2);
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
if(v==button1){
menu.add(0,1,0,"배경색(빨강)");
menu.add(0,2,0,"배경색(초록)");
menu.add(0,3,0,"배경색(파랑)");}
if(v==button2){
menu.add(0,4,0,"버튼45도회전");
menu.add(0,5,0,"버튼 2배확대");}
}

@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
switch(item.getItemId())
{
case 1:
baseLayout.setBackgroundColor(Color.RED);
break;
case 2:
baseLayout.setBackgroundColor(Color.GREEN);
break;
case 3:
baseLayout.setBackgroundColor(Color.BLUE);
break;
case 4:
button1.setRotation(45);
break;
case 5:
button1.setScaleX(2);
break;
}
return true;
}
}



'Android Studio를 활용한 안드로이드 프로그래밍' 카테고리의 다른 글

직접 풀어보기 8-1  (0) 2020.05.20
직접 풀어보기 7-3  (0) 2020.05.19
직접 풀어보기 7-1  (0) 2020.05.18
직접 풀어보기 6-3  (5) 2020.05.11
직접 풀어보기 6-2  (2) 2020.05.04

+ Recent posts