IT/C#

[C#] 가계부 프로그램 만들기 DAY2. 프로그램 UI 생성 및 가계부 기본 설정하기

Ella.J 2020. 2. 29. 16:45
728x90
반응형

DAY2 포스팅으로 돌아온 Ella 입니다!

이번 포스팅에서는 가계부 UI 만들고 기본적인 가계부 설정을 위한 파트입니다. 

사실 설정은   등록해놓고 거의  바뀌기 때문에 중요한 파트는 아닌데, 그래도 여기서 DB 설정을 직접 쿼리작성해주고 다음부터는 사용하지 않게 하기 위해서  필요한 부분이라고   있습니다.


첫 번째. UI 만들기

 

DAY1에서도 말했듯이, UI는 각자 취향에 맞게 만들어 주시면 됩니다!

저는 TabPage를 생성해서 각각의 HOME, Account Book, Setting 3개의 Tab을 만들었습니다.

기본적으로 들어갈 기능에 필요한 UI는 다음과 같습니다.

Home 탭에서는 누적 수입 / 지출 현황, 통장 잔액, 이번 달 수입 / 지출에 필요한 Label 6개와 DataGridView 3개입니다. 

Account Book 탭에서는 상세내역 입력을 위한 DateTimePicker, ComboBox 4개, TextBox 2개와 입력 Button, 그리고 가계부 내역을 보여줄 DataGridView가 필요합니다.

Setting 탭에 이번 시간에 할 가계부 설정을 위해서 DataGridView 3개와 Setting을 저장할 Button 하나를 생성해주었습니다.


두 번째. DataGridView에 DataSource 바인딩하기

 

저는 Config 각각의 변수들을 미리 선언해두고 관리하기 편하게 했습니다.

이전 시간에 사용한 Database name, Server, UserID, UserPassword 등 Table 이름도 enum으로 등록하여 사용하도록 했습니다.

그리고 각각의 설정에 필요한 변수들을 등록했는데, 아래의 코드에 사용된 config 값들은 아래의 코드를 참고하시면 되겠습니다.

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
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace AccountBook
{
    public static class Config
    {
        public static string Database = "account_db";
        public static string Server = "localhost";
        public static string UserID = "user1";
        public static string UserPassword = "user1234";
 
        public static string[] Tables = { "setting_info""account_info""credit_info""account_book" };
        public enum eTName : int { _setting, _account, _credit, _book }
 
        public static string[] UseType = { "수입""지출""계좌이동" };
        public static string[] AccountI = { "현금""계좌입금" };
        public static string[] AccountE = { "현금""체크카드""신용카드""타인계좌이체"};
        public static string[] Cash = { "내지갑" };
        public static string[] BankName = { "국민은행","우리은행","신한은행","기업은행","KEB하나은행","한국씨티은행","SC(제일)은행","산업은행","상호저축은행","새마을금고은행",
                                            "우체국은행","농협은행","수협은행","신협은행","산림조합은행","경남은행","광주은행","대구은행","부산은행","제주은행",
                                            "전북은행","카카오뱅크은행","K뱅크은행","TOSS은행" };
        public static string[] CreditBankName = { "KB국민","우리","신한","현대","삼성","롯데","하나","NH농협","씨티","SC",
                                                  "수협","MG","우체국","K뱅크","카카오" };
        public static string[] AccountName = null;
        public static string[] ConnectCard = null;
        public static string[] CardName = null;
        public static string[] ImportInfo = null;
        public static string[] ExportInfo = null;
        
        public static DataSet settingds = null;
        public static DataSet accountds = null;
        public static DataSet creditds = null;
        public static DataSet books = null;
        public static DataTable importdt = null;
        public static DataTable exportdt = null;
        public static DataTable totaldt = null;
        public static int CreditDate = 0;
        public static int[] CreditTerm = { 00 };
    }
}
 
cs

 

먼저, DataGridView에 각각의 설정 Table을 DataSource로 바인딩해주는 파트입니다.

위의 각각의 DataGridView(dvSettingInfo, dvAccountInfo, dvCreditInfo) setting_info, account_info, credit_info 테이블을 DataSource 등록해줍니다.

저는 Form_Load 이벤트 initSetting() 함수를 호출하여 프로그램 시작시에 DataGridView 3개에 각각의 DataSource 바인딩 하도록 코딩했습니다.

아래 함수에서 사용하도록 전역변수로

public static int cnt = 0; 구문을 선언해주어야합니다.

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
public void InitSetting()
{
    Config.settingds = _db.SelectDetail(Config.Tables[(int)Config.eTName._setting], "import_info as '수입계정', export_info as '지출계정'");
    dvSettingInfo.DataSource = Config.settingds.Tables[0];
    cnt = 0;
    Config.ImportInfo = new string[Config.settingds.Tables[0].Rows.Count];
    Config.ExportInfo = new string[Config.settingds.Tables[0].Rows.Count];
    foreach (DataRow r in Config.settingds.Tables[0].Rows)
    {
        if (r["수입계정"!= DBNull.Value)
        {
            Config.ImportInfo[cnt] = r["수입계정"].ToString();
        }
        if (r["지출계정"!= DBNull.Value)
        {
            Config.ExportInfo[cnt] = r["지출계정"].ToString();
        }
        cnt++;
    }
    Config.ImportInfo = Config.ImportInfo.Where(c => c != null).ToArray();
    Config.ExportInfo = Config.ExportInfo.Where(c => c != null).ToArray();
 
    cnt = 0;
    string AccStr = "bank_name as '은행명', account_name as '계좌명', connect_card as '연결체크카드', first_balance as '최초잔액', memo as '메모'";
    Config.accountds = _db.SelectDetail(Config.Tables[(int)Config.eTName._account], AccStr);
    dvAccountInfo.DataSource = Config.accountds.Tables[0];
    dvAccountInfo.Columns[3].DefaultCellStyle.Format = "###,##0";
    dvAccountInfo.Columns[3].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight;
    Config.AccountName = new string[Config.accountds.Tables[0].Rows.Count];
    Config.ConnectCard = new string[Config.accountds.Tables[0].Rows.Count];
    foreach (DataRow r in Config.accountds.Tables[0].Rows)
    {
        Config.AccountName[cnt] = r["계좌명"].ToString();
        Config.ConnectCard[cnt] = r["연결체크카드"].ToString();
        cnt++;
    }
 
    cnt = 0;
    string CreditStr = "credit_bank as '신용카드사', card_name as '카드명', withdraw_account as '출금계좌', bank_name as '은행명', withdraw_date as '출금일', use_term as '사용실적기간'";
    Config.creditds = _db.SelectDetail(Config.Tables[(int)Config.eTName._credit], CreditStr);
    dvCreditInfo.DataSource = Config.creditds.Tables[0];
    Config.CardName = new string[Config.creditds.Tables[0].Rows.Count];
    foreach (DataRow r in Config.creditds.Tables[0].Rows)
    {
        Config.CardName[cnt] = r["카드명"].ToString();
        cnt++;
    }
}
cs

[ 코드 시퀀스 ]

1) 데이터베이스에서 각 Table을 Select 쿼리로 가져옵니다.

2) 가져온 테이블을 Config에 선언해놓은 DataSet에 저장합니다.

3) 가져온 DataSet의 테이블을 DataGridView에 DataSource로 바인딩합니다.

4) 필요한 String Array에도 각각 데이터들을 넣어줍니다.

5) DataGridView에서 최초 잔액과 같은 컬럼에 Format을 지정해줍니다.

 

++ Array Null 값 체크해서 제외하기

Config.ImportInfo = Config.ImportInfo.Where(c => c != null).ToArray();
Config.ExportInfo = Config.ExportInfo.Where(c => c != null).ToArray();

위는 String배열 Config.ImportInfod에서 Where(c => c!=null) 배열 값이 null이 아닌 것만 가져와서 다시 ToArray() 배열로 만드는 코드입니다. 위 코드가 없다면 다음 배열 사용 시에 null 값을 참조하여 null 에러가 발생할 수도 있습니다!


세 번째. DataGridView에서 설정 입력값 DB에 Insert, Update 하기

프로그램에서 가계부 계정을 입력하기 위해서 가계부 계정 항목의 DataGridView CellValueChanged 이벤트 등록해 줍니다.

각각의 Cell값이 변경될때마다 DB Table 값을 입력해주도록 다음과 같이 코딩합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void dvSettingInfo_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    int row = e.RowIndex;
    int col = e.ColumnIndex;
 
    if (Config.settingds.Tables[0].Rows.Count == row) {
        if (col == 0) _db.Insert(Config.Tables[(int)Config.eTName._setting] + "(import_info)"
            $"'{dvSettingInfo.Rows[row].Cells[col].Value.ToString()}'");
        else _db.Insert(Config.Tables[(int)Config.eTName._setting] + "(export_info)"
            $"'{dvSettingInfo.Rows[row].Cells[col].Value.ToString()}'");
    } else
    {
        if (col == 0) _db.Update(Config.Tables[(int)Config.eTName._setting], 
            $"import_info='{dvSettingInfo.Rows[row].Cells[col].Value.ToString()}'"
            $"(@rownum:=0)=0 and (@rownum:=@rownum+1)={row + 1}");
        else _db.Update(Config.Tables[(int)Config.eTName._setting], 
            $"export_info='{dvSettingInfo.Rows[row].Cells[col].Value.ToString()}'"
            $"(@rownum:=0)=0 and (@rownum:=@rownum+1)={row + 1}");
    }
}
cs

 

2020.10.15 추가내용

Cell 내용 변경 시 Conig.settingds 데이터셋도 같이 업데이트를 해주기 위해서 이벤트 하단에

Config.settingds = _db.SelectDetail(Config.Tables[(int)Config.eTName._setting], "import_info as '수입계정', export_info as '지출계정');

한 줄을 추가해주어야합니다.


선택된 Cell의 row값과 column 값은 위와 같이 e.RowIndex, e.ColumnIndex로 알 수 있습니다.

테이블의 값을 Insert 할지 Update 할지 알기 위해서는 현재 Table Row.Count 값과 Cell 변경된 위치의 row값을 비교하여 값이 같으면 새로 입력하기 위해 Insert 해주고, 아니면 Update 해줍니다.

그리고 Column 값을 비교하여 import_info(수입계정)에 넣을지 export_info(지출계정)에 넣을지 판단합니다.


++  rownum 사용하기

테이블에 계정 정보만 넣고, 따로 다른 컬럼은 추가하지 않았기 때문에 n번째 row 값을 update 하기 위해서 rownum 사용합니다. 사용방식은 위의 where 구문과 같이 WHERE (@rownum:=0)=0 and (@rownum:=@rownum+1)=n 으로 사용하며, 위에서는 row+1 사용하였습니다. C#에서와는 다르게 0부터 시작하는 것이 아닌 1부터 시작이기 때문에 row +1 해주어야 제대로 row값이 업데이트됩니다.

주의!) 추가로 @rownum 사용하기 위해서는

DB 연결시 Connection String Allow User Variables=True 옵션을 추가해줘야합니다!

MySqlConnection conn = new MySqlConnection($"server={Config.Server};uid={Config.UserID};pwd={Config.UserPassword};database={Config.Database};pooling=false;allow user variables=true");

안 그러면 rownum을없다는 에러가 뜨기 때문에 이전 포스팅에서 만들었던 DBMysql 클래스 변경하여야 에러가 발생하지 않습니다.


위는 입력화면 예시이며, 데이터베이스에 입력된 값은 다음과 같습니다.

다음으로, Setting 버튼 하나 만들어서 버튼 입력시에 계좌정보와 신용카드 정보를 입력하도록 했습니다. 

한 번에 입력만 기존 데이터는 삭제하고 입력하도록 했으며 DataGridView 값을 가져와서 테이블에 입력하는 코드를 아래에 첨부하였습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private void btnSettingSave_Click(object sender, EventArgs e)
{
    _db.DeleteAll(Config.Tables[(int)Config.eTName._account]);
    for (int i = 0; i < dvAccountInfo.RowCount - 1; i++)
    {
        _db.Insert(Config.Tables[(int)Config.eTName._account], $"'{dvAccountInfo.Rows[i].Cells[0].Value.ToString()}'," +
            $"'{dvAccountInfo.Rows[i].Cells[1].Value.ToString()}', '{dvAccountInfo.Rows[i].Cells[2].Value.ToString()}'," +
            $"'{dvAccountInfo.Rows[i].Cells[3].Value.ToString()}', '{dvAccountInfo.Rows[i].Cells[4].Value.ToString()}'");
    }
    _db.DeleteAll(Config.Tables[(int)Config.eTName._credit]);
    for (int i = 0; i < dvCreditInfo.RowCount - 1; i++)
    {
        _db.Insert(Config.Tables[(int)Config.eTName._credit], $"'{dvCreditInfo.Rows[i].Cells[0].Value.ToString()}'," +
            $"'{dvCreditInfo.Rows[i].Cells[1].Value.ToString()}', '{dvCreditInfo.Rows[i].Cells[2].Value.ToString()}'," +
            $"'{dvCreditInfo.Rows[i].Cells[3].Value.ToString()}', '{dvCreditInfo.Rows[i].Cells[4].Value.ToString()}'," +
            $"'{dvCreditInfo.Rows[i].Cells[5].Value.ToString()}'");
    }
}
cs

 

 

위는 입력화면 예시이며, 데이터베이스에 입력된 값은 다음과 같습니다.


그럼 여기까지 가계부 기본 설정이 끝났습니다!

주요 내용으로는 DataGridView에 DataSource 바인딩하기, DataSet 이용하기, DB에서 Select, Insert 하기, rownum 사용하기, 배열 null 값 제외하기 등이 있습니다. 설명이 부족하거나 이해가 안 된다 하시는 분들은 언제든지 댓글 남겨주시면 감사하겠습니다 ^^

다음 시간에는 본격적인 가계부 입력 파트로 돌아오겠습니다~!

BYE!

728x90
반응형