본문 바로가기

C#/WinForm

[C# WinForm] 실시간 편의점 물품 가격변동에 따른 그래프 그리기 (Client)_(1) - 짱우의 코딩일기 - 티스토리

반응형

  우선 이 글은 제목 그대로 타이머를 이용해 실시간으로 DB에 있는 데이터를 가져와 그래프를 그리는 것에 대한 글이다. 하지만 간단한 예제를 이용한게 아니라 개인 프로젝트를 진행했던 코드를 바탕으로 사용했기 때문에 밑의 링크에서 어떤 프로젝트인지 확인하고 글을 읽는 것을 추천한다.


2020/01/09 - [개인 프로젝트] C# WinForm을 이용한 실시간 편의점 물품 가격변동에 따른 그래프 그리기 - 짱우의 코딩일기 - 티스토리

 

[개인 프로젝트] C# WinForm을 이용한 실시간 편의점 물품 가격변동에 따른 그래프 그리기 - 짱우의 코딩일기 - 티스토리

물론 지금도 인턴이지만 회사에서 인턴기간동안 만든 과제중 하나에 대한 글을 써보려 한다. 우선 제목대로 프로젝트에서 사용한 데이터는 실제 편의점 물품의 가격 변동 데이터를 사용하지는 않았다. 서버에서..

zzangwoo.tistory.com


Client 기능

< Client Form >

  위의 < Client Form > 화면에서도 보이다시피 크게 5가지의 기능을 구현해놓았다. 이는 모두 타이머를 이용하여 5초에 한 번씩 DB에 접근하여 실시간으로 변동하는 편의점 물품의 가격에 대한 데이터를 가져와 기능이 구현되는 프로젝트다.

0. Client Form 처음 실행

a. Form Class

private void Form1_Load(object sender, EventArgs e)
{
  // Column 초기화 메서드 호출
  SetupDataGridView();

  // 핸들러 묶어주기
  DAO dao = new DAO();
  dao.UpdateProdPrice += new DAO.UpdateProdPriceHandler(UpdateProdPrice);
  dao.RowChartClear += new DAO.RowClearHandler(RowChartClear);
  dao.UpdateChart += new DAO.UpdateChartHandler(UpdateChart);

  RowChartClear(); // DataGridView, Chart 모두 초기화
  dao.GetProdPrice(isType); // DB에서 값 가져오는 메서드 호출
}

  < Client Form >이 처음 로드 될 때 실행되는 메서드다. 제일 먼저 DataGridView의 Column을 초기화시켜준다. 처음에는 CheckBox가 모두 체크되어있기 때문에 DB의 테이블에 있는 모든 컬럼들로 초기화시켜준다.

  그리고 DB에 접속해주기 위해서 DAO 클래스를 생성했는데 DAO 클래스의 메서드를 불러오기 전에 핸들러로 묶어주는 과정을 먼저 해줘야 한다. 그 이유는 DAO에서 DB 값을 가져오고 그 값을 UI에 뿌려줘야 하는데 DAO 클래스는 Form의 Control에 접근할 수 있는 권한이 없기 때문이다. DAO에서 가져온 값을 Form에 반환시켜주는 방법도 있지만 그렇게 하기위해서는 DB에서 읽어온 데이터들을 다시 재가공해줘야 하는 번거로움이 있기 때문에 Delegate를 이용했다.

b. DAO Class

class DAO
{
  #region Form1에 있는 컨트롤에 접근하기 위한 Delegate
  // DataGridView에 날짜별 물품 가격 업데이트
  public delegate void UpdateProdPriceHandler(DateTime updatedDate, long[] prodArr);
  public event UpdateProdPriceHandler UpdateProdPrice;

  // Chart에 날짜별 물품 가격 업데이트
  public delegate void UpdateChartHandler(DateTime updatedDate, long A1, long A2, long A3, long B1, long B2, long B3,
  long C1, long C2, long C3);
  public event UpdateChartHandler UpdateChart;
  
  ...... 생략 ......

  Client Form에 있는 메서드와 DAO 클래스와 연동시키기 위해 위와 같은 코드를 사용했다.

/// <summary>
/// DB에서 갱신날짜 별 물품들의 가격을 불러오기 위한 메서드
/// </summary>
public void GetProdPrice (Dictionary<string, bool> isType)
{
  string connectionString =
  	ConfigurationManager.ConnectionStrings["StatisticsDB"].ConnectionString;
  SqlDataReader reader;

  // 선택된 CheckBox만 검색할 수 있게
  // 물품 Type명 typeName 배열에 집어넣기
  string[] typeName = new string[3];
  int count = 0;

  foreach (var data in isType)
  {
    if (data.Value)
    	typeName[count] = data.Key;
    else
    	typeName[count] = "없음";
    count++;
  }

  using (SqlConnection sqlCon = new SqlConnection())
  {
    sqlCon.ConnectionString = connectionString;
    sqlCon.Open();

    SqlCommand cmd = new SqlCommand("usp_showProdPrice", sqlCon);
    cmd.CommandType = CommandType.StoredProcedure;

    SqlParameter param = cmd.Parameters.Add("@beer", SqlDbType.NVarChar, 2);
    param.Value = typeName[0];

    param = cmd.Parameters.Add("@snack", SqlDbType.NVarChar, 2);
    param.Value = typeName[1];

    param = cmd.Parameters.Add("@ramen", SqlDbType.NVarChar, 2);
    param.Value = typeName[2];

    reader = cmd.ExecuteReader();

    while (reader.Read())
    {
      // 물품 컬럼수에 따른 배열 동적할당 (updateDate 개수는 생략)
      long[] prodArr = new long[reader.FieldCount - 1]; 
      for (int i = 0; i < prodArr.Length; i++)
      {
     	 prodArr[i] = reader.GetInt64(i+1);
      }

      // DAO 클래스에서는 폼에 있는 컨트롤에 접근할 수 없기 때문에 메서드 불러오기
      UpdateProdPrice(reader.GetDateTime(0), prodArr);

      // Chart 업데이트
      UpdateChart(reader.GetDateTime(0), reader.GetInt64(1), reader.GetInt64(2),
      reader.GetInt64(3), reader.GetInt64(4), reader.GetInt64(5), reader.GetInt64(6), reader.GetInt64(7),
      reader.GetInt64(8), reader.GetInt64(9));
    }

  }

}

  위의 메서드는 처음 Client Form이 로드될 때만 사용되는게 아니라 나중에 실시간으로 DB에서 데이터를 가져올 때도 사용되게 하기 위해서 코드를 좀 길게 짜두었다. 

  먼저 매개변수로 받아오는 Dictionary 같은 경우에는 Key 값으로 '맥주', '과자', '라면' 이렇게 세 개의 값이 들어있고 CheckBox가 체크되어 있는지에 대한 여부가 bool 값으로 Value에 저장되어 있다. foreach문을 통해서 string 배열에 체크되어 있는 물품 타입을 저장시켜서 프로시저에서 체크되어 있는 물품만 SELECT 할 수 있게 코드를 구성했다. 물론 체크되어 있지 않은 물품에는 '없음'이 들어가기 때문에 SELECT 문에서 CheckBox에서 체크가 풀린 물품은 출력하지 않는다.

  그리고 SqlCommand에 호출할 프로시저를 등록 시키고 Parameter 변수를 통해 프로시저에 있는 매개변수에 값을 집어넣어준다. 그리고 ExecuteReader 메서드를 실행시키면 프로시저에서 SELECT 한 데이터들이 reader 변수에 모두 들어가게 된다.

  while문을 통해 데이터들을 한 줄씩 받아와 Client Form Class에서 DataGridView와 Chart에 데이터들을 반영시키는 메서드에 넣어주고 호출시킨다.

c. 다시 Form Class

/// <summary>
/// DataGridView 레코드 값 업데이트 해주는 메서드
/// DataGridView에 접근하기 위해서 DAO와 Delegate로 묶어주었다
/// </summary>
private void UpdateProdPrice(DateTime updatedDate, long[] prodArr)
{
  // 컬럼명과 물품 가격을 동적으로 업데이트해주기위한 for문
  // prodArr (물품 가격)에 0값이 있으면 List에 저장해주지 않는다
  List<string> prodPriceList = new List<string>();
  for (int i = 0; i < prodArr.Length; i++)
  {
    if (prodArr[i] != 0)
   	 prodPriceList.Add(prodArr[i].ToString());
  }

  // DataGridView의 Row에 값 집어넣기 위한 string 배열 생성
  string[] rowData = new string[prodPriceList.Count + 1];
  rowData[0] = string.Format("{0:yyyy-MM-dd}", updatedDate);

  for (int i = 0; i < prodPriceList.Count; i++)
  {
  	rowData[i + 1] = prodPriceList[i];
  }

  SetupDataGridView(); // 컬럼 값 업데이트
  prodPriceDataGridView.Rows.Add(rowData);
}

  위의 메서드는 DataGridView에 DB에서 가져온 데이터를 뿌려주기 위해 만들어 놓은 메서드다. 'prodPriceList'는 CheckBox에 체크되어 있는 물품의 가격만 가져오고 저장시키기 위해 만들어놓은 변수다. 처음 Client Form을 실행시킬 때는 모든 품목에 대해서 데이터를 가져와서 저 코드가 필요없지만 나중에 실시간으로 데이터를 가져오면서 CheckBox에 체크되어 있지 않은 품목은 0으로 찍혀서 들어오기 때문에 분류를 시켜줘야 한다.

  DataGridView의 Row에 넣을 데이터들은 rowData 배열에 모두 집어넣도록 한다. 그리고 SetupDataGridView 메서드를 이용해서 DataGridView에 보여줄 컬럼을 설정해주고 아까 데이터들을 넣어준 rowData를 DataGridView에 넣어준다. 

  지금 글을 쓰면서 코드를 다시 보는데 SetupDataGridView 메서드를 데이터 한 줄씩 가져올때마다 호출할 필요는 없을 것 같다. 


2020/01/12 - [C# WinForm] 실시간 편의점 물품 가격변동에 따른 그래프 그리기 (Client)_(2) - 짱우의 코딩일기 - 티스토리

 

[C# WinForm] 실시간 편의점 물품 가격변동에 따른 그래프 그리기 (Client)_(2) - 짱우의 코딩일기 - 티스토리

우선 이 글은 제목 그대로 타이머를 이용해 실시간으로 DB에 있는 데이터를 가져와 그래프를 그리는 것에 대한 글이다. 하지만 간단한 예제를 이용한게 아니라 개인 프로젝트를 진행했던 코드를 바탕으로 사용했기..

zzangwoo.tistory.com

 

반응형