<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>프로그래밍노리터</title>
    <link>https://plas.tistory.com/</link>
    <description>프로그래밍 언어를 가르치면서 쌓여온 콘텐츠를 모았습니다. </description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 04:14:44 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>plas</managingEditor>
    <image>
      <title>프로그래밍노리터</title>
      <url>https://tistory1.daumcdn.net/tistory/2539639/attach/d6e5a54a473c480b9bf49b02e3627317</url>
      <link>https://plas.tistory.com</link>
    </image>
    <item>
      <title>금요일 중간 실기 문제 다운로드 링크</title>
      <link>https://plas.tistory.com/166</link>
      <description>&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/bdgHTg/btsKjp8gx2Y/KvRMKV3flnDcQj3k0mV2L0/apparel%20%EC%8B%A4%EA%B8%B0%20%EB%AC%B8%EC%A0%9C.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;apparel 실기 문제.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.07MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/166</guid>
      <comments>https://plas.tistory.com/166#entry166comment</comments>
      <pubDate>Fri, 25 Oct 2024 08:49:00 +0900</pubDate>
    </item>
    <item>
      <title>Song 리스트를 표처럼 보여주기(2단계)</title>
      <link>https://plas.tistory.com/165</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앞의 글에 &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이어서 Song 리스트를 JTable로 보여주는 방법을 살펴본다. 결과는 다음과 같은 화면으로 보여진다.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2023-11-13 131543.png&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVcUi2/btsz7SgBv8M/KDikZXYkMmZmBgh7QfkNB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVcUi2/btsz7SgBv8M/KDikZXYkMmZmBgh7QfkNB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVcUi2/btsz7SgBv8M/KDikZXYkMmZmBgh7QfkNB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVcUi2%2Fbtsz7SgBv8M%2FKDikZXYkMmZmBgh7QfkNB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;794&quot; height=&quot;347&quot; data-filename=&quot;화면 캡처 2023-11-13 131543.png&quot; data-origin-width=&quot;794&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이전 버전에서 바뀌는 내용&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GUIMain의 가운데 있던 JLabel 대신에 JTable 객체가 스크롤패널에 들어가게 된다.&lt;/li&gt;
&lt;li&gt;하단의 텍스트필드가 표의 컬럼 수만큼 생기고 그것을 통해 Song의 수정과 추가가 가능해진다.&lt;/li&gt;
&lt;li&gt;한 곡의 정보를 엔진과 GUI 사이에 주고 받기 위해 String[]을 이용하게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;song_table 패키지&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GUIMain : JFrame을 상속하여 메인 윈도우의 역할을 하는 클래스다.&lt;/li&gt;
&lt;li&gt;TablePanel: 실제 보여질 화면 내용을 가지는 클래스다. 테이블 부분(tableControlloer)과 아래쪽 패널(bottom)을 포함하여 화면을 구성하는 클래스다.&lt;/li&gt;
&lt;li&gt;TableController: JTable을 구성하고 수정/추가/삭제 버튼에 대한 테이블의 처리 기능을 가지는 클래스다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;BottomPane: 하부의 텍스트 필드와 버튼들을 구성하고 그에 대한 액션리스너를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JTable은 복잡한 컴포넌트여서 다루기가 좀 어렵지만 보통 기본적인 코드를 그대로 따라하면 되기 때문에 적용하기는 크게 어렵지 않다. TableController의 JTable 초기화 부분을 살펴보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1699849410102&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TableController implements ListSelectionListener {
    SongTableMgr dataMgr;
    DefaultTableModel tableModel;
    JTable table;
    int selectedIndex = -1;
    void init() {
        dataMgr = GUIMain.engine;   // 구체 클래스 엔진 객체가 설정됨   	
    	tableModel = new DefaultTableModel(dataMgr.getColumnNames(), 0);
    	loadData(&quot;&quot;);
    	
    	table = new JTable(tableModel);
        ListSelectionModel rowSM = table.getSelectionModel();
        rowSM.addListSelectionListener(this);
        table.setPreferredScrollableViewportSize(new Dimension(500, 220));
        table.setFillsViewportHeight(true);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JTable은 표의 행렬과 항들을 채우기 위해 TableModel이라는 것을 사용한다. 여기서는 DefaultTableModel을 써서 컬럼 개수만 지정해 준 tableModel 을 생성해서 쓰고 있다. 이것으로 JTable 생성자를 호출하고 행을 클릭했을 때 동작을 수행할 리스너를 달아준다. (ListSelectionListener.valueChanged) 그리고 크기와 선택 모드를 설정하고 있다. (한 행만 선택)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행이 선택되었을 때 동작은 해당 행의 모든 셀의 데이터를 가져와 하단의 텍스트 필드에 채우는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1699849634364&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public void valueChanged(ListSelectionEvent e) {
        ListSelectionModel lsm = (ListSelectionModel)e.getSource();
        if (!lsm.isSelectionEmpty()) {
        	selectedIndex = lsm.getMinSelectionIndex();
        	String[] rowTexts = new String[tableModel.getColumnCount()];
        	for (int i = 0; i &amp;lt; rowTexts.length; i++)
        		rowTexts[i] = (String)tableModel.getValueAt(selectedIndex, i);
        	TablePanel.bottom.moveSelectedToEdits(rowTexts);
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택된 행번호로 tableModel 에게 getValueAt으로 값을 요청하면 Object 객체가 반환된다. 그것을 스트링으로 바꾸어 텍스트필드에 넣을 스트링배열을 만든다. (텍스트필드는 bottom 패널이 가지고 있음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 테이블의 행을 채워줄 데이터를 엔진에게 받아오는 부분을 loadData 메소드가 담당한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699849847450&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    void loadData(String kwd) {
    	List&amp;lt;?&amp;gt; result = dataMgr.search(kwd);
    	tableModel.setRowCount(0);
    	for (Object m : result)
    		tableModel.addRow(((Song)m).getUiTexts());
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setRowCount는 JTable이 보여주는 데이터를 리셋하는 효과를 낸다. 엔진에게 받아온 result 에서 각 행에 들어갈 데이터를 꺼내는 것이 Song의 getUiTexts() 메소드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Song 클래스의 getUIText() 메소드는 다음과 같다. 각 필드를 스트링 배열로 바꾸어 넘겨준다.&lt;/p&gt;
&lt;pre id=&quot;code_1699849963726&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	public String[] getUiTexts() {
		return new String[] {&quot;&quot;+id, name, title, &quot;&quot;+year, lyric};
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mgr 패키지 : 변동없음&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;song 패키지의 SongTableMgr&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 있던 SongMgr에 테이블 지원 기능을 추가하기 위해 다음과 같이 수정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블의 컬럼 개수와 컬럼 헤더를 정해주는 기능을 다음과 같이 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699848194012&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;public class SongTableMgr extends Manager&amp;lt;Song&amp;gt; {
	// 테이블의 헤더 데이터 제공 부분
	String[] labels = {&quot;랭킹&quot;, &quot;이름&quot;, &quot;제목&quot;, &quot;년도&quot;, &quot;가사&quot;};
	// 테이블의 열 제목을 스트링 배열로 돌려줌
	public int getColumnCount() {
		return labels.length;
	}
	public String[] getColumnNames() {		
		return labels;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가와 수정 기능에서 표에서 한 행의 여러 항목을 처리하기 위해 다음과 같이 스트링 배열을 UI로부터 넘겨받아 엔진의 데이터를 수정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699848464647&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;	public void addNewItem(String[] editTexts) {
		// TODO Auto-generated method stub
		Song s = new Song();
		s.set(editTexts);
		mList.add(s);
		System.out.println(&quot;추가: &quot;+s);
	}
	public void update(String[] editTexts) {
		// TODO Auto-generated method stub
		Song s = (Song)find(editTexts[0]);
		s.set(editTexts);
		System.out.println(&quot;수정: &quot;+s);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Song의 set 메소드는 스트링 배열을 받아 그것으로 곡의 정보를 수정할 수 있다. 이것을 이용하여 해당 곡의 정보를 추가 또는 수정한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699848608132&quot; class=&quot;bash&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;	public void set(Object[] row) {
		id = Integer.parseInt((String)row[0]);
		name = (String)row[1];
		title = (String)row[2];
		year = Integer.parseInt((String)row[3]);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한편 SongTableMgr 클래스의 remove 함수는 첫번째 항(곡번호)를 이용하여 검색하도록 수정하였다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;추가 삭제 버튼의 액션 처리&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가 버튼에 대한 액션 핸들러는 TableControlloer의 addRow 메소드를 호출한다. 이 때 다음과 같이 텍스트필드에 있던 값을 스트링 배열 매개변수로 넘긴다.&lt;/p&gt;
&lt;pre id=&quot;code_1699850126453&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	public void actionPerformed(ActionEvent e) {
		String[] editTexts = getEditTexts();
		clearEdits();
		TableController tableController = TablePanel.tableController;
		switch (e.getActionCommand()) {
		case &quot;추가&quot;:
			tableController.addRow(editTexts);
			break;
		...
		}
		tableController.table.clearSelection();
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 컨트롤러에서는 엔진에게 추가를 요청하고 tabeModel에게도 추가하게 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699850195877&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    void addRow(String[] editTexts) {
		try {
			dataMgr.addNewItem(editTexts);
		} catch (Exception ex) {  // 추가 중 오류 발생
			ex.printStackTrace();
			JOptionPane.showMessageDialog(null, &quot;추가 데이터 오류&quot;);
			return;
		}
		tableModel.addRow(editTexts);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DefaultTableModel</category>
      <category>JTable</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/165</guid>
      <comments>https://plas.tistory.com/165#entry165comment</comments>
      <pubDate>Mon, 13 Nov 2023 13:42:10 +0900</pubDate>
    </item>
    <item>
      <title>데이터 매니저에 GUI 연결하기(1단계)</title>
      <link>https://plas.tistory.com/164</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1단계: 노래 데이터를 JLabel에 보여주고 검색, 수정, 삭제 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://plas.tistory.com/165&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2단계&lt;/a&gt;: 노래 데이터를 JTable에 보여주고 검색, 수정, 추가, 삭제 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://plas.tistory.com/163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;3단계&lt;/a&gt;: 파사드 패턴을 이용해서 재사용가능한 JTable 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서 살펴본 Manager와 Manageable, 그리고 제너릭으로 구현된 SongMgr 클래스를 이용하여 다음과 같이 입력파일에서 입력 받아 Song 클래스 객체를 만들어 관리자가 관리하는 프로그램을 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 콘솔 화면에서 파일 입력과 출력을 하는 클래스를 보여준다.&lt;/p&gt;
&lt;pre id=&quot;code_1699841557449&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SongConsoleMain extends Manager&amp;lt;Song&amp;gt; {
	public SongConsoleMain() {
		readAllSongs(&quot;songs.txt&quot;);
	}
	void readAllSongs(String filename) {
		super.readAll(filename, new Factory&amp;lt;Song&amp;gt;() {
			public Song create() {
				return new Song();
			}
		});
	}
	public static void main(String[] args) {
		SongConsoleMain engine = new SongConsoleMain();
		engine.printAll();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Manager&amp;lt;Song&amp;gt;은 readAll, printAll 기능을 제공하는 제너릭 클래스를 Song으로 인스턴스화한 타입이다. &lt;a href=&quot;https://plas.tistory.com/49&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://plas.tistory.com/49&lt;/a&gt; 참고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 다음과 같이 GUI에 연결하여 화면에 보여주는 방법을 생각해 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biaExx/btsAiFzfNQl/cmpBnhc1K5SPEmv8sLLnak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biaExx/btsAiFzfNQl/cmpBnhc1K5SPEmv8sLLnak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biaExx/btsAiFzfNQl/cmpBnhc1K5SPEmv8sLLnak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiaExx%2FbtsAiFzfNQl%2FcmpBnhc1K5SPEmv8sLLnak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;528&quot; height=&quot;504&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;504&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 위와 같은 Manager&amp;lt;Song&amp;gt;이 가진 정보를 화면에 보여주고 싶다. 또한 검색이나 수정, 삭제 등의 연산이 Manager&amp;lt;Song&amp;gt; 이 가진 리스트와 화면에 보여지는 정보가 일치되기를 원한다. 이런 경우 우리는 Manager&amp;lt;Song&amp;gt;과 그것을 처리하는 콘솔 프로그램 부분을 엔진레이어라고 하고 화면에 보여주는 기능을 제공하는 부분을 GUI 레이어라고 부를 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 GUI를 제공하기 위해서는 엔진과 GUI 레이어에서 다음과 같은 기능을 제공해야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가운데 JLabel 창에 Song 리스트의 정보를 보여줄 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;검색: 키워드를 받아와서 검색된 Song만 리스트를 보여줄 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;수정, 삭제 기능을 GUI의 요청에 따라 엔진에 반영한 후 화면을 업데이트해야 한다.&lt;/li&gt;
&lt;li&gt;수정은 번호의 곡의 제목을 변경하는 것이고 삭제 버튼은 해당 번호의 곡을 삭제한다.이&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 기능을 구현하기 위해 위의 SongConsoleMain 클래스에 다음과 같은 기능이 추가되어야 한다. 이것을 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;SongMgr 클래스라고 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1699842799770&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	public List&amp;lt;Song&amp;gt; search(String kwd) {
		if (kwd == null)
			return mList;
		return findAll(kwd);
	}
	public void update(int n, String title) {
		// TODO Auto-generated method stub
		Song s = find(&quot;&quot;+n);
		s.set(title);
	}
	public void removeAt(int num) {
		// TODO Auto-generated method stub
		Song s = find(&quot;&quot;+num);
		mList.remove(s);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 findAll이나 find는 Manager&amp;lt;T&amp;gt;에서 제공하는 기능이다. mList도 Manager&amp;lt;T&amp;gt;의 필드인데 이것도 메소드를 통해 제공하면 더 좋을 것이다. Song 클래스에서 제목 수정 기능을 위해 set 메소드를&amp;nbsp; 제공해야 함을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들 메소드는 GUI 레이어에서 버튼의 액션 핸들러에서 불려질 것이다. 이제 위의 화면을 제공하는 GUI 클래스들을 살펴보자.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;GUIMain&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 클래스는 일반적인 스윙 프로그램처럼 JFrame을 상속하고 SongListPanel 클래스 객체를 이용해서 컨텐츠 페인을 채우고 있다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SongListPanel&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 클래스가 화면의 내용을 구성하게 되는데, 상부의 검색 창을 JPanel, 가운데는 JScrollPane으로 스크롤을 가지는 패널로 넣고 아래는 bottom이라는 이름의 JPanel을 상속한 BottomPane 클래스를 이용해 만들고 있다. &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;addComponentsToPane 메소드에서 구성요소를 만들어 추가하는데, 중간에 들어가는 노래의 정보를 가질 객체를&amp;nbsp; songListLabel이라고 하는 JLabel을 이용한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 클래스의 loadData 메소드가 검색 키워드에 의한 리스트를 받아와서 JLabel에 텍스트로 붙여넣는 역할을 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1699843335663&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    void loadData(String kwd) {
    	List&amp;lt;Song&amp;gt; findList = GUIMain.engine.search(kwd);
    	String text = &quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&quot;;
    	for (Song s: findList) 
    		text += s + &quot;&amp;lt;br/&amp;gt;&quot;;
    	songListLabel.setText(text);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 엔진 레이어의 search 함수를 이용하여 검색된 리스트를 받아오는 것을 알 수 있다. 그리고 각 Song 객체는 toString을 통해 제공되는 스트링으로 변환되어 songListLabel에 보여질 스트링 text에 붙여지게 된다. 마지막에&amp;nbsp; setText를 통해 해당 문자열을 JLabel에 보여준다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;BottomPane&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 BottomPane 클래스는 하단의 텍스트 필드와 버튼을 추가하여 화면을 구성하고 버튼에 대한 액션 핸들러를 제공하는 클래스다.&lt;/p&gt;
&lt;pre id=&quot;code_1699843583552&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	public void actionPerformed(ActionEvent e) {
		int n = Integer.parseInt(numField.getText());
		switch (e.getActionCommand()) {
		case &quot;수정&quot;:
			GUIMain.engine.update(n,  edit.getText());
			parent.loadData(&quot;&quot;);
			break;
		case &quot;삭제&quot;:
			GUIMain.engine.removeAt(n);
			parent.loadData(&quot;&quot;);
			break;
		default: break;
		}
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 수정과 삭제는 각각 엔진인 SongMgr 클래스의 update와 removeAt을 호출하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 코드는 아래 파일에서 찾을 수 있다. (입력파일 songs.txt 포함)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/btSDCW/btsz9x3QsgG/FiNIMNDILSOmgNqvrbQr7K/gui_songlabel.zip?attach=1&amp;amp;knm=tfile.zip&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;gui_songlabel.zip&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>자바 프로그래밍</category>
      <category>GUI 레이어</category>
      <category>GUI 연결</category>
      <category>manager</category>
      <category>스윙</category>
      <category>엔진레이어</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/164</guid>
      <comments>https://plas.tistory.com/164#entry164comment</comments>
      <pubDate>Mon, 13 Nov 2023 11:54:09 +0900</pubDate>
    </item>
    <item>
      <title>JTable을 만들어주는 제너릭 GUI(3단계)</title>
      <link>https://plas.tistory.com/163</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 파일로부터 읽어들인 매니저에서 JTable을 이용하여 GUI 화면을 구성하는 프로그램을 재사용가능하게 구현해 보고자 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 데이터 요소든 그에 맞게 테이블을 구성하고 열과 테이블 헤더를 구성할 수 있게 한다&lt;/li&gt;
&lt;li&gt;검색과 수정, 삭제, 추가 기능을 가지는 JTable과 GUI 부분을 데이터가 달라져도 재사용할 수 있게 한다&lt;/li&gt;
&lt;li&gt;데이터를 입력하고 구동하는 엔진 부분에서 GUIMain 객체를 호출하는 것으로 GUI가 시작되게 한다.&lt;/li&gt;
&lt;li&gt;한 곡의 정보가 네 개의 항으로 구성되고 이것이 String[] 배열에 의해 데이터 엔진 부분과 연결된다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 동작하도록 작성한 프로그램에서 다음과 같이 두 개의 다른 데이터 파일에 대해 같은 방식으로 화면을 구성하도록 할 수 있다. 이렇게 하기 위해서 재사용 코드를 최대화하는 방식으로 엔진 부분과 GUI 부분을 작성해 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;싫행화면.jpg&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2NxPq/btsz6dyo0xL/eo7O80873hDl20oU8GkFZ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2NxPq/btsz6dyo0xL/eo7O80873hDl20oU8GkFZ0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2NxPq/btsz6dyo0xL/eo7O80873hDl20oU8GkFZ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2NxPq%2Fbtsz6dyo0xL%2Feo7O80873hDl20oU8GkFZ0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1754&quot; height=&quot;430&quot; data-filename=&quot;싫행화면.jpg&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로그램은 다음과 같이 다섯 개의 패키지로 구성된다. 각 패키지의 역할은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;275&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Fbg4M/btsz9y9nNEg/DPK1eF6fozkKIEzDkzlyok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Fbg4M/btsz9y9nNEg/DPK1eF6fozkKIEzDkzlyok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Fbg4M/btsz9y9nNEg/DPK1eF6fozkKIEzDkzlyok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFbg4M%2Fbtsz9y9nNEg%2FDPK1eF6fozkKIEzDkzlyok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;232&quot; height=&quot;485&quot; data-origin-width=&quot;275&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;facade 패키지&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GUI 부분과 엔진 부분 사이를 연결해주는 인터페이스와 구현을 가지는 패키지다. 파사드 패턴에 의해 UI 쪽에서 실제 엔진의 클래스를 알 필요없이 인터페이스만으로 사용할 수 있게 해주는 기능을 제공한다.&lt;/li&gt;
&lt;li&gt;UIData 인터페이스: 요소 타입 클래스가 JTable에서 보여지고 수정할 수 있게 해주는 메소드 인터페이스를 제공한다. 실제 요소 데이터로 표의 한 행의 텍스트를 set/get하는 기능을 가진다.&lt;/li&gt;
&lt;li&gt;IDataEngine 인터페이스: 이 인터페이스는 JTable이 엔진으로부터 JTable을 보여주기 위해 필요한 정보를 전달받기 위한 메소드를 정의한다. 컬럼의 개수와 테이블 헤더를 가져올 수 있고 검색이나 추가/삭제/수정 기능을 엔진에 요청할 수 있다.&lt;/li&gt;
&lt;li&gt;DataEngineImple 추상 클래스: IDataEngine 인터페이스의 공통기능을 구현한 추상 클래스로 실제 구체 엔진 클래스가 상속하게 된다. 여기서는 인터페이스의 기능을 Manageable 또는 UIData 수준에서 구현한 코드를 가진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;table_demo 패키지&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GUIMain : JFrame을 상속하여 메인 윈도우의 역할을 하는 클래스다.&lt;/li&gt;
&lt;li&gt;TablePanel: 실제 보여질 화면 내용을 가지는 클래스다. 테이블 부분(tableControlloer)과 아래쪽 패널(bottom)을 포함하여 화면을 구성하는 클래스다.&lt;/li&gt;
&lt;li&gt;TableController: JTable을 구성하고 수정/추가/삭제 버튼에 대한 테이블의 처리 기능을 가지는 클래스다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;BottomPane: 하부의 텍스트 필드와 버튼들을 구성하고 그에 대한 액션리스너를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 패키지&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mgr 패키지 : 변동없음&lt;/li&gt;
&lt;li&gt;song 패키지 SongMgr&lt;/li&gt;
&lt;li&gt;student 패키지 StudentMgr&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;nbsp;공통 인터페이스 추출하기&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 구체 클래스에 의존하지 않는 요소 클래스를 사용할 수 있게 하기 위해서는&amp;nbsp; Manageable 이외에 GUI와의 인터페이스를 위한 추가적인 기능들이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1699859856499&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface UIData {
    void set(Object[] uitexts);
    String[] getUiTexts();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이들 메소드는 GUI 에서 호출하여 GUI의 테이블 행과 요소 클래스를 연결하는 기능을 제공한다. GUI의 테이블모델에서 받은 그 행의 데이터 배열을 Object[]로 받아 그것을 구체 클래스의 추가와 수정을 위해 데이터를 설정하는 함수가 set 함수다. 또한 요소 클래스의 데이터를 표에 보여주기 위해 한 행에 들어갈 스트링의 배열로 넘겨받는 함수가 getUiTexts()다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 엔진이 제공해야 하는 기능을 모은 인터페이스를 정의할 수 있다. 이것은 Manager와 같이 Manageable을 상속한 요소 타입을 매개변수로 가지는 제너릭으로 정의된다. 여기에는 테이블의 컬럼의 수와 헤더를 가져오는 부분, 그리고 검색과 추가, 수정, 삭제를 요청할 수 있는 메소드들이 제공된다. 이것들은 엔진이 제공하고 GUI 쪽에서 호출하게 되는 메소드들이다.&lt;/p&gt;
&lt;pre id=&quot;code_1699860167509&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface IDataEngine&amp;lt;T extends Manageable&amp;gt; {
	// 이 매니저가 관리하는 데이터를 테이블에 보여주기 위해 
	// 열제목의 개수와 배열을 반환. 필요한 열의 개수만큼 배열이 반환됨
	int getColumnCount();
	String[] getColumnNames();
	// 키워드에 매치되는 것을 모두 찾아 리스트로 반환
	List&amp;lt;T&amp;gt; search(String kwd);
	// UI 테이블의 행에 있는 데이터를 스트링 배열로 받아와서 새로운 객체 추가
	void addNewItem(String[] uiTexts);
	// UI 테이블의 행에 있는 데이터를 스트링 배열로 받아와서 해당 객체 수정
	void update(String[] uiTexts);
	// UI 테이블의 행의 첫번째 데이터를 키로 받아와 해당 객체를 찾아 삭제
	void remove(String kwd);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GUI는 이제 특정 요소 클래스(Song 또는 Student)나 특정 관리자 클래스(SongMgr 또는 StudentMgr)에 의존하지 않고 IDataEngine 인터페이스에만 의존하도록 작성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 GUIMain에서 정의한 engine은 IDataEngine 타입으로 정의된다. 여기서 요소의 구체 클래스를 알지 못하므로 &amp;lt;?&amp;gt;로 처리한 것을 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1699860752828&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class GUIMain {
    static IDataEngine&amp;lt;?&amp;gt; engine;
    public static void startGUI(IDataEngine&amp;lt;?&amp;gt; en) {
    	engine = en;
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 TableController에서 정의한 엔진과 요소 타입도 IDataEngine과 UIData 타입으로 바뀌게 된다.&amp;nbsp; 엔진으로부터 검색 결과를 돌려받는 리스트도 List&amp;lt;?&amp;gt;로 선언된다. 여기서 주의할 것은 List&amp;lt;Object&amp;gt;처럼 요소 타입의 슈퍼클래스를 요소로 가지는 리스트는 List&amp;lt;Song&amp;gt;의 슈퍼 타입이 될 수 없다는 점이다. 타입이 다른 경우는 &amp;lt;?&amp;gt;를 써야만 슈퍼타입으로 다형성에 의해 여러 가지 타입의 리스트를 가리키는 타입이 될 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1699860884685&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; public class TableController implements ListSelectionListener {
    IDataEngine&amp;lt;?&amp;gt; dataMgr;
    ...
	void loadData(String kwd) {
    	List&amp;lt;?&amp;gt; result = dataMgr.search(kwd);
    	tableModel.setRowCount(0);
    	for (Object m : result)
    		tableModel.addRow(((UIData)m).getUiTexts());
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 엔진 부분이 어떻게 바뀌어야 하는지 살펴보자. Song 클래스는 UIData를 구현해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1699861132895&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Song implements Manageable, UIData {
	...
    @Override
	public void set(Object[] row) {
		id = Integer.parseInt((String)row[0]);
		name = (String)row[1];
		title = (String)row[2];
		year = Integer.parseInt((String)row[3]);
	}
	@Override
	public String[] getUiTexts() {
		return new String[] {&quot;&quot;+id, name, title, &quot;&quot;+year, lyric};
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소 클래스는 이와 같이 UIData의 set과 getUiTexts 메소드를 구현해야 한다. 이것을 통해 GUI 부분에서 호출되는 메소드를 제공할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한편 SongMgr 클래스는 IDataEngine을 구현해야 하는데, 여기서 많은 기능이 구체 클래스와 상관없이 구현가능하다. 그래서 IDataEngine의 메소드들을 구현한 재사용가능한 구현 클래스를 제공한다. DataEngineImpl이라고 하는 클래스를 정의할 수 있다. 이를 위해서 구체 클래스에서 설정한 컬럼 헤더 부분을 가져올 수 있게 labels&lt;/p&gt;
&lt;pre id=&quot;code_1699861329500&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class DataEngineImpl&amp;lt;T extends Manageable&amp;gt; implements IDataEngine&amp;lt;T&amp;gt; {
	String[] headers = null;
	protected Manager&amp;lt;T&amp;gt; mgr;
	public void setManager(Manager&amp;lt;T&amp;gt; mgr) {
		this.mgr = mgr;
	}
	public void setLabels(String[] texts) {
		this.headers = texts;
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 검색, 수정, 삭제 부분은 구체 클래스가 필요하지 않으므로 이 클래스에서 구현할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1699861975316&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@Override
	public List&amp;lt;T&amp;gt; search(String kwd) {
		if (kwd == null)
			return mgr.mList;
		return mgr.findAll(kwd);
	}
	@Override
	public void update(String[] editTexts) {
		// TODO Auto-generated method stub
		Manageable s = mgr.find(editTexts[0]);
		((UIData)s).set(editTexts);
	}
	@Override
	public void remove(String kwd) {
		// TODO Auto-generated method stub
		Manageable s = mgr.find(kwd);
		mgr.mList.remove(s);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IDataEngine 중 addNewItem은 구현되지 않았는데, DataEngineImpl 클래스는 abstract로 선언된 추상클래스여서 미구현된 인터페이스 메소드가 있어도 문제가 되지 않는다.&lt;/p&gt;
&lt;pre id=&quot;code_1699862136768&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class SongMgr extends DataEngineImpl&amp;lt;Song&amp;gt; {
	// 테이블의 헤더 데이터 제공 부분
	String[] labels = {&quot;랭킹&quot;, &quot;이름&quot;, &quot;제목&quot;, &quot;년도&quot;, &quot;가사&quot;};
	public SongMgr() {
		setLabels(labels);
		setManager(new Manager&amp;lt;Song&amp;gt;());
		readAll(&quot;songs.txt&quot;);
	}
	void readAll(String filename) {
		mgr.readAll(filename, new Factory&amp;lt;Song&amp;gt;() {
			public Song create() {
				return new Song();
			}
		});
	}
	@Override
	public void addNewItem(String[] editTexts) {
		// TODO Auto-generated method stub
		Song s = new Song();
		s.set(editTexts);
		mgr.addElement(s);
	}
	...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 SongMgr는 DataEngineImpl 클래스를 상속하므로 Manager&amp;lt;Song&amp;gt;을 또 상속할 수가 없다. 그래서 mgr 참조 변수를 DataEngineImple 클래스의 필드로 선언하고 매니저 객체를 여기서 생성해서 setManager 해주는 방식을 취한다. 그 결과 Manager에서 상속받았던 메소드의 호출은 다 앞에 mgr를 붙여주어야 한다. DataEngineImple의 mgr는 protected로 선언하여 상속한 클래스에서 사용할 수 있게 하였다.&lt;/p&gt;</description>
      <category>자바 프로그래밍</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/163</guid>
      <comments>https://plas.tistory.com/163#entry163comment</comments>
      <pubDate>Mon, 13 Nov 2023 11:08:16 +0900</pubDate>
    </item>
    <item>
      <title>말로 설명하는 스윙 프로그램</title>
      <link>https://plas.tistory.com/162</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;nbsp;컨테이너 계열&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너란 다른 컴포넌트를 포함하는 영역을 나타내는 요소들이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JPanel&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPanel은 스윙 GUI에서 가장 기본이 되는 컴포넌트로 윈도우 상의 사각형 영역을 나타낸다. 위치, 크기, 배경색 등의 정보를 가지고 있으며, 다른 컴포넌트를 추가하여 배치하기 위한 기본 틀이라고 볼 수 있다. 스윙에서는 모든 요소들의 배치는 사각형 틀을 이용해야 하므로 필요할 때마다 다른 컴포넌트들을 담을 패널을 생성하여 사용하게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JFrame&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프레임은 화면 상에 독립적으로 존재하는 윈도우 부분을 나타낸다. 보통 스윙 프로그램에는 하나의 메인 프레임이 있고 그 안에서 마우스나 키보드를 처리하는 형태로 프로그램이 구성된다. 그리고 메인 클래스의 역할도 하게 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Container&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너는 다른 컴포넌트를 담을 수 있는 클래스로 JPanel이나 JFrame도 컨테이너다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;J가 붙은 이름은 스윙 라이브러리 클래스에서 추가된 것들이고 J가 붙지 않은 것은 awt 라이브러리에서부터 있었던 기본 클래스들이다.&lt;/li&gt;
&lt;li&gt;JFFrame이나 JDialog는 contentPane이라는 패널을 가진다. 이것은 그 윈도우에서 컴포넌트를 추가할 수 있는 영역(타이틀, 테두리, 스크롤 등을 제외한 영역)을 가진 패널로 우리는 getContentPane()을 통해 이 패널을 돌려받을 수 있다. 단 이것은 JPanel이 아니어서 Container 타입으로 받아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JDialog&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대화상자라고도 하는데, 팝업으로 떠서 간단한 정보 보여주기나 입력받기를 위해 사용하는 창이다. 보통으로 확인, 취소, 닫기 등의 버튼을 가지고 있어서 보여졌다가 닫으면 사라진다. (대화상자는 없애지 않고 그냥 둔 채로 감추기를 하기도 한다. 감추기란 setVisible(false)를 하면 화면에서 사라진다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 화면에서 사라지면 마우스나 키보드 입력을 받을 수 없다. 마우스나 키보드 입력은 포커스를 가진 컴포넌트만 받을 수 있다. 포커스는 화면의 영역을 차지하고 있는 컴포넌트가 가지게 되는데 보통 클릭을 하면 그 컴포넌트가 포커스를 가져가게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;nbsp;기타 JComponent&amp;nbsp; 류&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JLabel&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라벨은 화면 상의 네모 영역을 가지고 그 안에 텍스트를 보여줄 수 있는 컴포넌트다. (그 안에 뭘 넣을 수는 없음. 즉 자식 컴포넌트를 갖지는 못한다.) 텍스트 설정이나 배경색 변경, 텍스트 색깔과 폰트 변경, 텍스트 정렬 방식 설정 등이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면 상에 텍스트를 나타내기 위해서는 JLabel 컴포넌트를 이용해야 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JButton&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼은 우리가 일반적으로 알고 있는 버튼과 같다. 네모난 영역을 차지하고 클릭이나 마우스 다운에 대해 모양이 바뀌기도 하며, 버튼 이름을 텍스트로 가진다. (이미지 버튼도 가능함) 버튼을 누르게 되면 어떤 동작을 해야 하는데 이것을 담당할 핸들러를 사용하는 프로그램에서 지정해 주어야 한다. 버튼은 아무 일도 하지 않는 기본 핸들러를 가지고 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JTextField&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 필드는 한줄 텍스트 입력을 위한 컴포넌트다. 간단한 입력을 키보드로 타이핑할 수 있게 해주는데, 프로그램에서는 여기에 있는 텍스트를 가져오는 getText와 보여질 텍스트를 설정하는&amp;nbsp; setText를 할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JScrollPane&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤페인은 패널인데 상하 또는 좌우 스크롤을 만들어주는 패널이다. 여기에 포함된 컴포넌트의 크기가 이 패널보다 크면 자동으로 스크롤이 생성된다. 일반적으로 스크롤페인에는 JPanel을 하나 포함하게 되는데, JPanel의 크기에 따라 스크롤이 생성된다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;nbsp;레이아웃&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레이아웃이란 네모난 영역을 구성하는 몇가지 옵션을 나타낸다. 컨테이너에 컴포넌트를 배치하기 위해서 차례로 줄세울지(FlowLayout), 상하좌우와 센터가 있는 이클립스 같은 모양으로 할지(BorderLayout), 그리고 바둑판 모양으로 할지(GridLayout) 등을 정하게 된다. 다른 모든 GUI&amp;nbsp; 프로그래밍 방식과 마찬가지로 스윙에서도 화면을 구성하는 것이 가장 복잡하고 번거로운 작업이다. 그러나 익숙해지면 대부분 비슷비슷하게 사용되므로 적당히 코드를 가져다 약간만 수정하면 별 문제없이 원하는 모양을 만들 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;또하나 대표적인 레이아웃이 카드 레이아웃이다. 이클립스에서 여러 개 소스 파일이 열리는데 그 중 하나를 편집창에 보여주는 것이 카드레이아웃인데, 이 때는 사실 여러 개의 JPanel이 겹쳐져 있고 위쪽의 탭을 선택하면 그에 해당하는 패널이 제일 위로 올라와서 보여지게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너에 setLayout을 통해 어떤 레이아웃을 사용할 것인지 지정하게 된다. 그리고 나면 add 메소드를 통해 원하는 컴포넌트를 원하는 위치에 넣게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스윙에서는 컴포넌트들을 배치하고 나면 각 컨포넌트의 크기와 레이아웃을 고려하여 전체의 크기를 정하게 되는데 이것을 컨테이너가 가진 pack() 메소드가 한다. 그래서 보통 요소 컴포넌트들을 만들어서 추가하고 pack을 통해 전체적인 위치가 잡힌다고 볼 수 있다. (그러므로 크기나 위치는 그 전에는 올바른 값을 갖고 있지 않음)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;nbsp;이벤트 핸들러&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이벤트는 사용자가 GUI 프로그램과 상호작용하기 위해 입력한 액션(마우스, 키보드, 터치 등)을 OS가 프로그램에 전달하는 방식이다. 그러므로 스윙 프로그램은 항상 대기상태로 있다가 뭔가 입력 이벤트가 들어오면 그에 대해 대응하는 동작을 수행하게 된다. 이러한 이벤트는 해당 영역을 차지하고 있고 포커스를 가진 컴포넌트에게 전달된다. 스윙에서는 컴포넌트들이 어떤 이벤트를 받게 되면 이것에 대응해서 어떤 동작을 할지를 정하는 이벤트 핸들러를 프로그램에서 등록하게 된다. 예를 들어 카톡에서 (전송) 버튼을 누르면 메시지가 보내지게 된다. 프로그램은 전송 버튼이 눌려졌다는 이벤트가 발생할 때 어떤 일을 할지 코드로 작성해 주어야 하고 이것을 이벤트 핸들러 함수라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트에 따라 받을 수 있는 이벤트가 정해진다. 예를 들어 JButton은 버튼이 클릭되었음을 알려주는 ActionEvent라는 것을 받게 된다. 많은 컴포넌트들이 마우스가 클릭되었음을 알려주는 MouseEvent를 받게 된다. 또한 키보드가 타이핑되었음을 알려주는 KeyEvent가 있다. 또한 마우스가 움직이거나 드래그 되고 있음을 알려주는 MouseEvent도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램에 이벤트가 전달되면 스윙의 가장 핵심부에 있는 이벤트디스펜서 무한루프에 의해 해당 컴포넌트에 대해 등록해둔 이벤트 핸들러를 호출하게 된다. 카톡에서 (전송) 버튼이 눌려지면 그 버튼의 이벤트 핸들러로 등록되어 있는 메소드가 불려질 것이다. 이것은 인터페이스구현 방식에 의해 전달된 객체를 통해 등록되고 불려진다. (DIP 원칙)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;nbsp;스윙 프로그램에서 클래스 구성&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이러한 컴포넌트와 컨테이너, 이벤트 핸들러로 프로그램을 실제 구성하는 방식을 살펴보자. GUI 프로그램은 보통 JFrame을 상속하는 클래스가 메인 클래스가 되고 여기서 화면을 구성하는 코드 부분을 호출하게 된다. 버튼이나 텍스트필드, 라벨 등의 컴포넌트로 화면을 구성하고 배치를 하는 부분이 수행되는데, 여기서 컴포넌트는 생성, 설정, 추가 과정을 거치게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 필요하다면 그 컴포넌트에 이벤트 핸들러를 등록한다. 이벤트 핸들러는 필요한 경우에만 등록하는데, 그것을 위해서는 이벤트 핸들러 인터페이스를 구현한 객체를 전달하여 등록한다(addOOOListener). 예를 들어 마우스 이벤트 핸들러가 등록되면 마우스 이벤트가 그 핸들러의 해당 메소드를 호출하면서 전달된다. 컴포넌트가 제공하는 기본적인 기능(getText, setText 같은 것들)만 이용한다면 핸들러를 등록할 필요가 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 결정해야 하는 것 중에 하나가 컴포넌트를 생성해서 가지는 변수 중에서 어떤 것을 필드로 선언하고 어떤 것은 지역변수로 선언할 것인가 이다. 기본 원칙은 가능한 한 변수는 지역변수로 선언하는 것이 좋다는 것이다. 그러나 두 개 이상의 함수에서 필요로 하는 경우는 필드로 선언해야 한다. 이것은 화면을 구성하는 메소드에서 만들어진 컴포넌트가 이벤트 핸들러에서 사용되어야 하는 경우가 대표적이다. 그러나 많은 경우 이벤트 핸들러 함수가 전달해 주는 이벤트가 필요한 정보를 대부분 가지고 있어서 직접 컴포넌트 객체를 참조하는 변수를 사용하지 않아도 되는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 필요에 따라 어떤 부분을 다른 클래스로 독립하기도 한다. 화면을 구성하는 부분이 너무 복잡하고 그에 따른 이벤트 핸들러도 너무 많다면 이것을 모두 하나의 클래스에 가지고 있는 것은 어려운 일이다. 이런 경우 화면을 구성하는 부분을 그게 나누어 어느 것을 다른 클래스로 보내기도 한다. 예를 들어 테트리스 프로그램이라면 블록이 쌓이는 부분을 별도의 클래스로 빼서 키보드 이벤트에 따라 블록이 내려가는 것을 담당할 것이다. 그리고 우측의 패널에는 단계, 점수, 다음 블록 등을 보여주는 일을 담당하는 클래스가 있을 것이다. 이런 클래스는 보통 JPanel을 상속해서 그 패널에 컴포넌트를 추가하거나 구성하는 일과 그에 따른 이벤트 핸들러를 가지는 클래스가 된다. 이런 클래스 객체들을 전체 JFrame의 컨텐츠 페인이 포함하고 있을 것이다.&amp;nbsp;&lt;/p&gt;</description>
      <category>자바 프로그래밍</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/162</guid>
      <comments>https://plas.tistory.com/162#entry162comment</comments>
      <pubDate>Wed, 8 Nov 2023 12:48:39 +0900</pubDate>
    </item>
    <item>
      <title>자바 이터레이터 응용 - 경품 추첨</title>
      <link>https://plas.tistory.com/161</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 어디가나 경품이 핫하죠? 이터레이터 패턴을 응용하여 경품 추첨 프로그램을 만들어 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로그램은 경품추첨 명단과 경품의 리스트를 받아 추첨하는 과정을 수행하는 프로그램입니다. 추첨 기능은 두가지여서 경품에 따라 차례로 명단에서 이름을 뽑는 방식과 명단에 있는 사람 중에서 랜덤한 순서로 한명씩 경품을 추첨하는 형태입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 전체적인 프로그램의 실행의 전체구조를 살펴보겠습니다. 명단을 가질 mList와 입력을 받을 스캐너를 만들고 명단을 읽어들인 후 전체 출력하고 나서 추첨부를 호출합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1668305961518&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class EventMgr {
	Scanner scan = new Scanner(System.in);
	ArrayList&amp;lt;String&amp;gt; mList = new ArrayList&amp;lt;&amp;gt;();
	void run() {
		readAll();
		printAll();
		draw();
	}
	// 상품 목록
	String items[] = {&quot;아이패드프로&quot;, &quot;아이팟&quot;, &quot;웹하드10G1Y&quot;, &quot;보조밧데리&quot;, &quot;다음기회에&quot;};
	int ea[] = {1, 3, 5, 10, -1};  // 상품 개수
	void draw() {
		int menu = 0;
		System.out.print(&quot;추첨 방식 (1) 이름뽑기   (2) 선물뽑기 =&amp;gt; &quot;);
		menu = scan.nextInt();
		if (menu == 1) drawNames();
		else if (menu == 2) drawItems();
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추첨부 draw() 메소드는 이름뽑기와 선물뽑기로 나누어지는데요, 여기서 선물의 리스트와 선물의 개수를 가진 배열을 먼저 선언했습니다. 이것을 입력 받도록 고치면 더 좋겠지요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 먼저 이름을 뽑는 코드를 살펴보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1668307546357&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// 뽑을 사람의 수만큼 반복하면서 랜덤하게 상품 추첨
	void drawNames() {
		Iterator&amp;lt;String&amp;gt; it = new NameSelector(mList);
		String winner = null;
		scan.nextLine();
		for (int i = items.length - 2; i &amp;gt;= 0; i--) {
			for (int j = 0; j &amp;lt; ea[i]; j++) {
			    System.out.println(&quot;=&amp;gt;&quot; +  (i+1) + &quot;등&quot;);
			    winner = it.next();
			    System.out.println(&quot;축하합니다 &quot; + winner + &quot; : &quot; + items[i]);
			    scan.nextLine();
			}
		}
		System.out.println(&quot;감사합니다. 안녕히 가세요.&quot;);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름을 랜덤하게 뽑아주는 이터레이터를 NameSelector라는 이름의 클래스로 구현했구요, 이것으로 선물을 마지막 등수부터 1등까지 차례로 개수만큼 이름을 뽑아 결과를 보여줍니다. 경품은 보통 마지막 등수부터 뽑잖아요? 그리고 각 등수에 따라 상품의 개수가 있으니까 그만큼 반복해야 할 것입니다. 엔터 칠 때마다 다음 사람을 뽑도록 하기 위해 scan.nextLine()을 넣어주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 위너를 뽑는 부분에서 it.next()를 써서 추첨하는데요, 이때 추첨대상자가 상품보다는 많다는 가정을 하기 때문에 hasNext를 검사하지 않고 그냥 for 루프를 돌리고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 진짜 비밀이 담긴 이터레이터 코드를 한번 살펴볼까요? 이 클래스는 이터러블과 이터레이터를 둘다 구현하고 있는데요, 이터러블은 두번째 추첨 방식인 경품 뽑기에서 쓰이는데, 여기서는 일단 간단하게 코드만 보고 넘어가면 되겠습니다. 이터러블을 구현하기 위한 iterator() 메소드에서 return this; 하는 것을 볼 수 있습니다. 자기 자신이 이터레이터이자 이터러블이 되는 구조이지요.&lt;/p&gt;
&lt;pre id=&quot;code_1668307803383&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class NameSelector implements Iterator&amp;lt;String&amp;gt;, Iterable&amp;lt;String&amp;gt;
{
	ArrayList&amp;lt;String&amp;gt; candidates;
	NameSelector(ArrayList&amp;lt;String&amp;gt; candidates) {
		this.candidates = new ArrayList&amp;lt;&amp;gt;(candidates);
		Collections.shuffle(this.candidates);
	}
	@Override
	public boolean hasNext() {
		return !candidates.isEmpty();
	}
	@Override
	public String next() {
		return candidates.remove(0);
	}
	@Override
	public Iterator&amp;lt;String&amp;gt; iterator() {
		return this;
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이터레이터의 구현부를 살펴볼까요? 생성자는 랜덤하게 추첨할 이름 리스트를 받아 먼저 shuffle해서 섞어줍니다. 그리고 next할 때마다 한 개씩 이름을 돌려주는데, 리스트에서 제거하여 다시 추첨되지 않도록 하고 있습니다. hasNext()는 이 리스트에 뭐가 더 남아있으면 true이고 비어있으면 false가 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이터레이터를 이용하여 랜덤한 순서로 이름을 하나씩 뽑을 수 있겠지요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 두번째 춫첨 방식인 경품 뽑기를 살펴보겠습니다. 이번에는 후보자들 중에 랜덤하게 한명씩 나와서 경품을 추첨하는 방식으로 하고 싶은데요, 코드는 다음과 같습니다. 여기서 NameSelector가 이터러블로 쓰인 것을 볼 수 있습니다. 이터러블이니까 for-each에서 사용될 수 있는 거지요. 그리고 경품 추첨은 이터레이터인 Drawer 클래스를 이용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 주의할 점은 사람의 랜덤한 추첨 순서와 상관없이 상품이 나올 확률은 같아야 되니까 미리 전체가 몇명인지 알 수 있어야 한다는 점입니다. 그래서 경품 추첨 이터레이터를 만들 때 사람의 수 mList.size()를 매개변수로 주고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1668308111886&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// 랜덤한 순서로 사람을 추첨하고 그 사람이 경품을 다시 추첨함
	void drawItems() {
		Iterable&amp;lt;String&amp;gt; nameIt = new NameSelector(mList);
		Iterator&amp;lt;String&amp;gt; it = new Drawer(mList.size(), items, ea);
		String win;
		scan.nextLine();
		for (String name : nameIt) {
			System.out.println(&quot;=&amp;gt;&quot; + name);
			scan.nextLine();
			win = it.next();
			if (win.equals(&quot;items[items.length-1]&quot;))
				System.out.println(win);
		    System.out.println(&quot;축하합니다 &quot; + name + &quot; : &quot; + win);
		}
		System.out.println(&quot;감사합니다. 안녕히 가세요.&quot;);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름을 랜덤한 순서로 뽑는 것은 for 루프의 NameSelector가 제공하는 이터레이터로 하고 경품을 추첨하는 것은 Drawer 클래스의 next() 기능을 이용하고 있습니다. 여기서 중요한 것은 경품이 개수만큼만 추첨되어야 한다는 점인데 이것을 보장하기 위해 Drawer 클래스에서는 뽑힌 경품의 개수를 감소시켜야 합니다. 그리고 마지막 경품으로 &quot;다음기회에&quot;를 넣어서 추첨되지 않은 사람은 &quot;다음기회에&quot;가 나와야 되고 그것은 개수를 감소시킬 필요없이 얼마든지 나와도 되게 따로 처리하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1668308631360&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Drawer implements Iterator&amp;lt;String&amp;gt;
{
	static Random rand = new Random();
	int count;
	String items[];
	int ea[];
    // 생성자에서 전체 사람의 수, 경품 종류와 개수를 설정합니다.
	Drawer(int n, String[] items, int[] ea) {
		count = n;
		this.items = items.clone();
		this.ea = ea.clone();
	}
	@Override
	public boolean hasNext() {
		return true;  // 다음기회에는 계속 나올 수 있으므로 항상 true
	}
	@Override
	public String next() {
		int num = rand.nextInt(count);
		int cc = 0;
		for (int i = 0; i &amp;lt; ea.length; i++) {
			if (ea[i] == -1)  // 다음기회에는 계속 나올 수 있음
				return items[i];
			cc += ea[i];   // 등수에 따라 그 안에 들어가는 숫자인지 검사
			if (num &amp;lt; ea[i]+cc) {
				ea[i]--;   // 뽑힌 상품은 개수 차감
				return items[i];
			}    
		}
		return null;
	}
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>자바 프로그래밍</category>
      <category>경품추첨</category>
      <category>랜덤</category>
      <category>이터러블</category>
      <category>이터레이터</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/161</guid>
      <comments>https://plas.tistory.com/161#entry161comment</comments>
      <pubDate>Sun, 13 Nov 2022 12:28:33 +0900</pubDate>
    </item>
    <item>
      <title>jar 파일로 프로그램 실행시키기</title>
      <link>https://plas.tistory.com/160</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;jar 파일이란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바 프로그램을 컴파일하여 실행가능한 .class 파일을 생성하게 된다. 이 파일들을 묶어서 실행할 수 있는 파일로 만들어 놓은 것이 jar(자르) 파일이다. 이것을 다른 사람에게 주면 소스 코드 없이 프로그램을 실행시켜 볼 수 있다. 또는 라이브러리처럼 다른 사람이 만든 클래스를 이용하고자 할 때도 jar 파일을 어딘가 디렉토리에 설치하고 이클립스 같은 IDE에서 해당 경로를 설정하면 프로그램 안에서 import하여 사용할 수도 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이클립스에서 jar 파일 export 하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 만든 프로젝트를 jar 파일 형태로 다른 사람에게 제공하여 실행시켜 보게 하기 위해 Runnable JAR 파일을 export할 수 있다. 이것은 다음과 같은 순서로 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2022-09-19 180054.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMpfvD/btrMxTNtwKw/rkUlcc90d89qOKCkDDW4s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMpfvD/btrMxTNtwKw/rkUlcc90d89qOKCkDDW4s0/img.png&quot; data-alt=&quot;파일 메뉴의 export 기능을 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMpfvD/btrMxTNtwKw/rkUlcc90d89qOKCkDDW4s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMpfvD%2FbtrMxTNtwKw%2FrkUlcc90d89qOKCkDDW4s0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;269&quot; height=&quot;390&quot; data-filename=&quot;화면 캡처 2022-09-19 180054.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;파일 메뉴의 export 기능을 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2022-09-19 180142.png&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/moq22/btrMxWQYYeI/kETerhWM18fplB3oLePAF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/moq22/btrMxWQYYeI/kETerhWM18fplB3oLePAF0/img.png&quot; data-alt=&quot;export할 종류를 선택 : Runnable JAR file 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/moq22/btrMxWQYYeI/kETerhWM18fplB3oLePAF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmoq22%2FbtrMxWQYYeI%2FkETerhWM18fplB3oLePAF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;323&quot; height=&quot;341&quot; data-filename=&quot;화면 캡처 2022-09-19 180142.png&quot; data-origin-width=&quot;519&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;export할 종류를 선택 : Runnable JAR file 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;파일저장3.jpg&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;542&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMQpyX/btrMrv8c19V/kGf1RzucSQRtpTOv4GACP0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMQpyX/btrMrv8c19V/kGf1RzucSQRtpTOv4GACP0/img.jpg&quot; data-alt=&quot;jar 파일을 저장할 경로 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMQpyX/btrMrv8c19V/kGf1RzucSQRtpTOv4GACP0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMQpyX%2FbtrMrv8c19V%2FkGf1RzucSQRtpTOv4GACP0%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;328&quot; data-filename=&quot;파일저장3.jpg&quot; data-origin-width=&quot;512&quot; data-origin-height=&quot;542&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;jar 파일을 저장할 경로 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;파일저장4.jpg&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9sx45/btrMxU6EBB2/K7naiwvitIMsjIJNZCd9ck/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9sx45/btrMxU6EBB2/K7naiwvitIMsjIJNZCd9ck/img.jpg&quot; data-alt=&quot;이클립스의 프로젝트 중에서 어느 것을 export할지 선택&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9sx45/btrMxU6EBB2/K7naiwvitIMsjIJNZCd9ck/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9sx45%2FbtrMxU6EBB2%2FK7naiwvitIMsjIJNZCd9ck%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;329&quot; height=&quot;348&quot; data-filename=&quot;파일저장4.jpg&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이클립스의 프로젝트 중에서 어느 것을 export할지 선택&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 단계를 거쳐 내보낼 프로젝트와 디렉토리를 선택하면 해당 파일이 export 된다. 지정한 디렉토리에 가보면 프로젝트 이름.jar 파일이 생성되어 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JAR 파일 실행하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runnable JAR 파일을 실행하기 위해서는 명령창에서 다음과 같은 명령을 주면 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1663578963466&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -jar week1.jar&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brCa70/btrMvOlSy9o/utkIuW0dDK0lGm4FmNpLu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brCa70/btrMvOlSy9o/utkIuW0dDK0lGm4FmNpLu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brCa70/btrMvOlSy9o/utkIuW0dDK0lGm4FmNpLu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrCa70%2FbtrMvOlSy9o%2FutkIuW0dDK0lGm4FmNpLu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;662&quot; height=&quot;94&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파워쉘 창 열기는 다음과 같이 탐색기의 원하는 폴더에서 Ctrl-Shift와 마우스 오른쪽 클릭을 하면 &quot;여기에 PowerShell 창 열기&quot; 메뉴가 팝업에 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;533&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oZeBQ/btrMyfirXq0/HhOAZz3gQjY164gjpfa1Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oZeBQ/btrMyfirXq0/HhOAZz3gQjY164gjpfa1Tk/img.png&quot; data-alt=&quot;탐색기의 현재 폴더에서 파워쉘 창 열기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oZeBQ/btrMyfirXq0/HhOAZz3gQjY164gjpfa1Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoZeBQ%2FbtrMyfirXq0%2FHhOAZz3gQjY164gjpfa1Tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;417&quot; height=&quot;400&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;533&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;탐색기의 현재 폴더에서 파워쉘 창 열기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 다음 글을 참고해 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://plas.tistory.com/140?category=663337&quot;&gt;https://plas.tistory.com/140?category=663337&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;jdk 설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 jar 파일 실행하기에서 오류가 나는 경우 JDK가 설치되어 있지 않았을 가능성이 있다. 이클립스를 설치하는 것만으로 자바 환경이 설치되지 않으므로 직접 설치를 해 주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(1) 자바 JDK 다운로드 검색&amp;nbsp; &lt;a href=&quot;https://www.oracle.com/java/technologies/downloads/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.oracle.com/java/technologies/downloads/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) 아래로 스크롤해서 Java8을 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;703&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Rh1ZW/btrMp17nEN0/3Z6jVCjTPd4XyTgdCzuIcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Rh1ZW/btrMp17nEN0/3Z6jVCjTPd4XyTgdCzuIcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Rh1ZW/btrMp17nEN0/3Z6jVCjTPd4XyTgdCzuIcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRh1ZW%2FbtrMp17nEN0%2F3Z6jVCjTPd4XyTgdCzuIcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;381&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;703&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;703&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cv5jTU/btrMxTtaZD0/W6RlJVE8bVaBUnk4HcWJ0K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cv5jTU/btrMxTtaZD0/W6RlJVE8bVaBUnk4HcWJ0K/img.png&quot; data-alt=&quot;오라클 사이트에서 OS 기종에 맞는 jdk 파일을 다운로드하여 설치함&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cv5jTU/btrMxTtaZD0/W6RlJVE8bVaBUnk4HcWJ0K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcv5jTU%2FbtrMxTtaZD0%2FW6RlJVE8bVaBUnk4HcWJ0K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;569&quot; height=&quot;374&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;703&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;오라클 사이트에서 OS 기종에 맞는 jdk 파일을 다운로드하여 설치함&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;환경변수 설정하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDK를 설치한 후 C:\Program Files\java\jdk... 디렉토리를 열어보면 bin 디렉토리가 있는데, 여기에 java.exe나 javac.exe를 이용하여 파워쉘에서 자바 명령을 실행할 수 있다. 문제는 이 경로를 윈도우 환경에서 찾을 수 있게 설정해 주어야 한다는 점이다. JAVA-HOME 경로를 설정해주고 그것을 path 환경설정에 넣어주는 등의 일을 해주어야 한다. &lt;span&gt;환경변수에 자바 관련 설정을 하는 방법은 다음 블로그를 참고하기 바란다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://marobiana.tistory.com/163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://marobiana.tistory.com/163&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1663579431368&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;windows에서 JAVA 환경변수 설정하기&quot; data-og-description=&quot;이클립스 프로그램을 사용할 때(자바 개발 시) JAVA가 설치된 위치를 찾게 해주기 위해 환경변수 설정을 해야한다. 제어판 검색 제어판 &amp;gt; 시스템 및 보안&amp;nbsp;클릭 제어판 &amp;gt; 시스템 및 보안 &amp;gt; 시스템 &quot; data-og-host=&quot;marobiana.tistory.com&quot; data-og-source-url=&quot;https://marobiana.tistory.com/163&quot; data-og-url=&quot;https://marobiana.tistory.com/163&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/czqZLd/hyPQkgp4ON/kVLA6JlNCIW22B4havMGz1/img.png?width=800&amp;amp;height=719&amp;amp;face=0_0_800_719,https://scrap.kakaocdn.net/dn/mj3Hg/hyPQiiz5KV/fejKiekjTK86fHIm1DnFsK/img.png?width=800&amp;amp;height=719&amp;amp;face=0_0_800_719,https://scrap.kakaocdn.net/dn/0PSsz/hyPQdhkdgW/H2ikVfUM0KfSQ5jSq6T9kk/img.png?width=922&amp;amp;height=505&amp;amp;face=0_0_922_505&quot;&gt;&lt;a href=&quot;https://marobiana.tistory.com/163&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://marobiana.tistory.com/163&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/czqZLd/hyPQkgp4ON/kVLA6JlNCIW22B4havMGz1/img.png?width=800&amp;amp;height=719&amp;amp;face=0_0_800_719,https://scrap.kakaocdn.net/dn/mj3Hg/hyPQiiz5KV/fejKiekjTK86fHIm1DnFsK/img.png?width=800&amp;amp;height=719&amp;amp;face=0_0_800_719,https://scrap.kakaocdn.net/dn/0PSsz/hyPQdhkdgW/H2ikVfUM0KfSQ5jSq6T9kk/img.png?width=922&amp;amp;height=505&amp;amp;face=0_0_922_505');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;windows에서 JAVA 환경변수 설정하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이클립스 프로그램을 사용할 때(자바 개발 시) JAVA가 설치된 위치를 찾게 해주기 위해 환경변수 설정을 해야한다. 제어판 검색 제어판 &amp;gt; 시스템 및 보안&amp;nbsp;클릭 제어판 &amp;gt; 시스템 및 보안 &amp;gt; 시스템&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;marobiana.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경변수를 설정해 주면 위에서 설명한 것처럼 파워쉘에서 java- jar 명령을 통해 이클립스가 export한 jar 파일을 실행할 수 있다.&lt;/p&gt;</description>
      <category>자바 프로그래밍</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/160</guid>
      <comments>https://plas.tistory.com/160#entry160comment</comments>
      <pubDate>Mon, 19 Sep 2022 18:31:12 +0900</pubDate>
    </item>
    <item>
      <title>[8] 파이썬 입문 - 원하는 조건을 나타내는 조건식</title>
      <link>https://plas.tistory.com/159</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램에서 if 문은 매우 자주 쓰입니다. 그리고 원하는 조건을 잘 표현해서 if와 elif 문장을 구성하는 것이 프로그래밍에서는 절대적으로 중요한 기술입니다. 이번 회차에서는 이것을 좀더 구체적으로 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터는 0과 1을 이용해 만들어지는 기계라고 합니다. 컴퓨터는 참 거짓을 잘 이해하고 그것을 이용해서 우리는 작업지시서를 만들 수 있습니다. 이러면 이걸 하고 저러면 저렇게 하고... 참이라고 생각되는 것들이 모여서 지식이 됩니다. 그리고 그런 것들이 자율자동차가 멈출 것인지 엑셀을 밟을 것인지 판단하기 위한 상태를 표현하게 되고 로봇이 동작하기 위한 알고리즘이 됩니다. 논리는 컴퓨터가 동작하는 가장 밑바탕이 되는 원리입니다. 컴퓨터 논리는 원래 논리학 또는 수학의 영역에 있던 많은 것을 가져와 만들어졌습니다. 그래서 여기서 논리라고 하는 것을 잠시 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명제는 참거짓을 판별할 수 있는 문장 또는 값입니다. 명제에 논리 연산자를 적용하여 새로운 명제를 만들 수 있습니다. 논리 연산자는 AND, OR, NOT 같은 연산자입니다. 예를 들면 다음과 같은 명제들을 가지고 있다고 가정해 보겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 a는 50보다 크다&lt;/li&gt;
&lt;li&gt;숫자 a는 60보다 작다&lt;/li&gt;
&lt;li&gt;숫자 a는 3의 배수다&lt;/li&gt;
&lt;li&gt;숫자 a는 5의 배수가 아니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문장들은 이름 a가 가진 값과 숫자를 비교하면 참 거짓이 판별될 수 있습니다. 크거나 같고는 &amp;gt;=라는 기호로 표현됩니다. a가 숫자를 가지고 있으면 명제가 될 수 있는 것이지요. 그러면 위의 명제들을 이용해서 다음과 같은 새로운 명제를 만들수 있습니다. AND는 그리고, ~이고와 같이 동시에 만족되는 경우에 참이고 OR는 ~거나 또는 처럼 둘중의 하나가 만족되면 참이 됩니다. NOT은 참거짓을 반대로 만드는 연산이지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &quot;나는 초등학생이고 마라톤을 좋아한다&quot; 라는 문장은 두 가지 명제 &quot;나는 초등학생이다&quot; 와 &quot;나는 마라톤을 좋아한다&quot; 의 AND 입니다. 둘다 참이어야 이 문장이 참이 되지요. 한편 &quot;나는 초등학생이거나 마라톤을 좋아한다&quot;라면 둘 중의 하나만 참이어도 참이 됩니다. 또한 &quot;나는 초등학생이가 마라톤을 좋아한다는 것은 사실이 아니다&quot;라고 하면 AND 명제의 부정이 됩니다. 즉 AND 명제가 거짓이면 참이 되죠. 그러니까 &quot;나는 초등학생이 아니거나 마라톤을 좋아하지 않는다&quot;라는 뜻이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자 a에 대한 성질을 나타낸 문장을 논리식으로 표현할 수 있습니다. 다음은 몇가지 예를 보여줍니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 43.4884%;&quot;&gt;숫자 a는 50보다 크고 60보다 작다&lt;/td&gt;
&lt;td style=&quot;width: 28.3721%;&quot;&gt;(a &amp;gt; 50) AND (a &amp;lt; 60)&lt;/td&gt;
&lt;td style=&quot;width: 28.1395%;&quot;&gt;a=55면 참, a=66이면 거짓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 43.4884%;&quot;&gt;숫자 a는 50보다 크고 3의 배수다&lt;/td&gt;
&lt;td style=&quot;width: 28.3721%;&quot;&gt;(a &amp;gt; 50) AND (a % 3 == 0)&lt;/td&gt;
&lt;td style=&quot;width: 28.1395%;&quot;&gt;a=54면 참, a=55면 거짓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 43.4884%;&quot;&gt;숫자 a는 60보다 작고 5의 배수가 아니다&lt;/td&gt;
&lt;td style=&quot;width: 28.3721%;&quot;&gt;(a &amp;lt; 60) AND NOT(a % 3 == 0)&lt;/td&gt;
&lt;td style=&quot;width: 28.1395%;&quot;&gt;a=35면 참, a=61이면 거짓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 43.4884%;&quot;&gt;숫자 a는 3의 배수거나 5의 배수다&lt;/td&gt;
&lt;td style=&quot;width: 28.3721%;&quot;&gt;(a % 3 ==0) OR (a % 5 == 0)&lt;/td&gt;
&lt;td style=&quot;width: 28.1395%;&quot;&gt;a가 6이면 참, a=7이면 거짓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;그럼 이번에는 좀더 복잡한 예를 살펴보겠습니다. 여러 명제가 AND, OR, NOT으로 결합하여 하나의 긴 명제가 될 수 있습니다.&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 a는 50보다 크고 60보다 작고 또 3의 배수면서 5의 배수는 아니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문장을 논리식으로 표시해 본다면 다음과 같이 될 것입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;a &amp;gt;= 50 AND a &amp;lt; 70 AND a % 3 == 0 AND a % 5 == 0&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리식은 이름이 가진 값에 대해 조건을 표현할 수 있습니다. a는 사용자가 입력으로 준 값이거나 센서에서 읽어들인 값이거나 또는 네트워크를 통해 전달된 값이 될 수도 있습니다. 이 값에 대해 우리는 어떤 성질을 만족하는지 검사할 수 있고 그 경우에 원하는 일을 수행하도록 프로그램을 작성할 수 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 a는 50보다 크거나 같고 60보다 작으면서 3의 배수이거나 5의 배수다&lt;/li&gt;
&lt;li&gt;a &amp;gt;= 50 AND a &amp;lt; 60 AND (a % 3 == 0 OR a % 5 == 0)&lt;br /&gt;참이 되는 a의 값: 50, 51, 54, 55, 57&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 a는 50보다 크거나 같고 60보다 작으면서 3의 배수가 아니고 5의 배수도 아니다&lt;/li&gt;
&lt;li&gt;a &amp;gt;= 50 AND a &amp;lt; 60 AND NOT(a % 3 == 0) AND NOT(a % 5 == 0)&lt;br /&gt;참이 되는 a의 값: 52, 53, 56, 58, 59&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자 a는 50보다 크거나 같고 60보다 작으면서 &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2의 배수가 아니다&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;a &amp;gt;= 50 AND a &amp;lt; 60 AND NOT (a % 2 == 0)&lt;br /&gt;참이 되는 a의 값: 51, 53, 55, 57, 59&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>파이썬맛보기</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/159</guid>
      <comments>https://plas.tistory.com/159#entry159comment</comments>
      <pubDate>Mon, 27 Jun 2022 17:40:08 +0900</pubDate>
    </item>
    <item>
      <title>[7] 파이썬 입문 - if 조건문</title>
      <link>https://plas.tistory.com/157</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이제까지 이름으로 값을 기억하는 것과 연산과 수식을 계산하는 것을 살펴보았습니다. 또한 입력받은 값에 따라 동작하도록 프로그램을 작성해 보았고 결과를 사용자가 보기 좋게 출력하는 방법도 살펴보았습니다. 이번 회에는 계산을 수행할 때 값에 따라 또는 조건에 따라 다른 동작을 하도록 작성하는 법을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램은 컴퓨터에게 어떤 계산이나 작업을 수행하게 하는 작업지시서인데, 작업은 값에 따라 또는 상황에 따라 하는 일이 달라져야 하는 경우가 많습니다. 식당가에서 돌아다니는 배민 딜리버리 로봇은 자기 위치와 목적지에 따라 그리고 맵에 따라 갈림길에서 직진할지 우회전할지 좌회전할지 결정해야 합니다. 이 때 &lt;u&gt;어떤 조건을 만족하면&lt;/u&gt; 우회전하도록 프로그램이 작성되어 있을 것입니다. 이런 경우를 표현하는 것이 if 조건문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건은 &lt;u&gt;참 또는 거짓이 될 수 있는 수식&lt;/u&gt;으로 표현됩니다. 우리는 앞에서 값이나 이름으로 비교식을 만들거나 비교식을 and와 or로 연결하여 복잡한 조건을 표현하는 방법을 살펴보았습니다. 이러한 &lt;u&gt;비교 및 논리 수식&lt;/u&gt;이 바로 조건식입니다. 조건식에 따라 참이면 이쪽 길로 가고 거짓이면 저쪽 길로 가는 것이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건식에 따라 어떤 판단을 하는 예시를 같이 살펴보겠습니다. 주어진 물건이 박스 크기 20*30에 맞는지 여부를 판단하는 프로그램을 생각해 봅시다. 물건의 길이와 넓이를 입력받습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;긴 쪽을 a, 짧은 쪽을 b로 둡니다.&lt;/li&gt;
&lt;li&gt;a가 30보다 작고 b는 20보다 작으면 박스에 넣을 수 있습니다.&lt;/li&gt;
&lt;li&gt;아니면 이 박스에 넣을 수 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 프로그램으로 나타내면 어떻게 표시할 수 있을까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 프로그램이 어떻게 실행될지 생각해 보겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;gt; 넓이: 20&lt;br /&gt;&amp;gt; 높이: 15&lt;br /&gt;20*30 박스에 들어갑니다&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;gt; 넓이: 30&lt;br /&gt;&amp;gt; 높이 14&lt;br /&gt;20*30 박스에 들어갑니다&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;gt; 넓이: 30&lt;br /&gt;&amp;gt; 높이: 25&lt;br /&gt;20*30 박스에 들어가지 않습니다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 동작하도록 프로그램을 작성해 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 우리는 넓이와 높이를 입력받아야 되고 큰 값을 a, 작은 값을 b에 넣습니다.&amp;nbsp;큰 값을 a, 작은 값을 b에 넣기 위해 우리는 a와 b에 넓이와 높이를 입력받고 b가 a보다 크면 두 값을 바꾸려고 합니다. 이것을 알고리즘이라고 할 수 있습니다.&amp;nbsp; 컴퓨터에게 작업을 지시하기 위해 어떤 방식으로 입력받고 조건에 따라 바꿀지 결정하는 것이 사람이 하는 역할입니다. 컴퓨터는 시키는 그대로 작업을 수행할 뿐입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656247576864&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a = int(input('넓이 =&amp;gt; '))
b = int(input('높이 =&amp;gt; '))
if a &amp;lt; b:
    b, a = a, b&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if 조건문을 작성하는 방식은 위에서 한 것처럼 &lt;u&gt;if라는 키워드를 써주고 조건식 뒤에 콜론(:)&lt;/u&gt;을 씁니다. 그리고 다음 줄은 왼쪽에 빈칸 &lt;u&gt;네번(탭)을 들어가서&lt;/u&gt; if 조건식이 참일 때 수행할 명령을 써주게 됩니다. 여기서는 a가 b보다 작으면 두 값을 바꿉니다. if 조건식이 만족할 때만 그 다음 문장을 수행하게 됩니다. 조건식이 거짓일 때는 바꾸지 않고 그대로 다음으로 넘어갑니다. 들여쓰기 한 부분이 조건식이 만족될 때 수행되고 들여쓰기를 마치고 &lt;u&gt;다시 앞으로 내어쓰면 if 문이 끝났&lt;/u&gt;으므로 조건식과 상관없이 수행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 이 크기가 박스에 들어가는지 검사하는 코드를 생각해 보겠습니다. 크기가 맞는지 검사하여 맞으면 &quot;들어갑니다&quot;, 아니면 &quot;들어가지 않습니다&quot;를 출력합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1656247917616&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if a &amp;lt; 30 and b &amp;lt; 20:
    print('20*30 박스에 들어갑니다')
else:
    print('20*30 박스에 들어가지 않습니다')
print('감사합니다')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 if 조건식이 만족되는 경우 다음 명령문을 수행하고 그렇지 않은 경우는 else 로 다른 명령문을 수행합니다. 앞에서 본 예는 else 부분이 없었는데 여기서는 else인 경우에만 수행할 명령문이 따로 있는 경우입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 몇가지 박스가 있어서&amp;nbsp;물건의 길이와 넓이에 따라 그에 맞는 박스를 선택하는 경우를 생각해 보겠습니다. 박스는 20*30, 30*50, 50*70 이렇게 세가지가 있다고 가정해 보겠습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;1)&amp;nbsp; &amp;nbsp;가장 긴 것을 a, 그 다음 긴 것을 b로 둡니다.&lt;/li&gt;
&lt;li&gt;2)&amp;nbsp; &amp;nbsp;a가 30보다 작고 b는 20보다 작으면 1번 박스를 사용합니다.&lt;/li&gt;
&lt;li&gt;3)&amp;nbsp; &amp;nbsp;2)가 만족되지 않은 경우, a가 50보다 작고 b는 30보다 작으면 2번 박스를 사용합니다.&lt;/li&gt;
&lt;li&gt;4)&amp;nbsp; &amp;nbsp;2), 3)이 만족되지 않은 경우, a가 70보다 작고 b는 50보다 작으면 3번 박스를 사용합니다.&lt;/li&gt;
&lt;li&gt;5)&amp;nbsp; &amp;nbsp;1), 2), 3)이 만족되지 않은 경우 맞는 박스가 없다고 출력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 a와 b를 입력받아 큰 값을 a에 넣은 후 다음과 같이 여러 번의 조건식을 차례로 검사하게 됩니다. 이런 경우 if와 elif, else라는 세 개의 키워드를 사용하게 됩니다. else는 else if의 준말이어서 그게 아닌 경우에 if 조건식을 나타냅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656248886932&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if a &amp;lt; 30 and b &amp;lt; 20:
    print('1번 박스를 사용합니다')
elif a &amp;lt; 50 and b &amp;lt; 30:
    print('2번 박스를 사용합니다')
elif a &amp;lt; 70 and b &amp;lt; 50:
    print('3번 박스를 사용합니다')
else:
    print('맞는 박스가 없습니다')
print('감사합니다')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 처음 조건식이 만족되면 1번 박스를 출력하고 감사합니다를 출력하게 됩니다. 처음 조건식이 만족되지 않으면 두번째 조건식을 검사합니다. 즉 a가 30보다 크거나 b가 20보다 큰 경우는 두번째 조건식을 검사하고 그것이 만족되면 2번 박스를 출력하고 역시 감사합니다를 출력하고 마칩니다. 두번째 조건식도 만족되지 않을 때는 a가 50보다 크거나 b가 30보다 큰 경우가 됩니다. 이때는 세번째 조건식을 검사하게 되고 세번째 조건식도 만족하지 않으면 else 부분을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 여러 개의 조건문을 if와 elif, else로 연결하는 경우 앞의 조건식이 만족되지 않으면 다음 조건식을 검사하게 됩니다. 조건문은 프로그램을 작성할 때 아주 기본이 되는 기법입니다. 중요한 것은 조건식을 잘 작성하는 것입니다.&amp;nbsp;&lt;/p&gt;</description>
      <category>파이썬맛보기</category>
      <category>elif</category>
      <category>ELSE</category>
      <category>IF</category>
      <category>조건식</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/157</guid>
      <comments>https://plas.tistory.com/157#entry157comment</comments>
      <pubDate>Sun, 26 Jun 2022 22:14:15 +0900</pubDate>
    </item>
    <item>
      <title>[6] 파이썬 입문 - 입력과 출력</title>
      <link>https://plas.tistory.com/156</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램가 어떤 계산을 하도록 컴퓨터에게 작업을 지시하기 위해서는 값을 정해 주어야 합니다. 그런데 문제는 이름에 값을 지정한 후 그것을 사용하여 계산을 하면 항상 같은 값에 대해서만 계산을 할 수 있다는 점입니다. 프로그램이 어떤 일을 하도록 작성되었다면 그 일을 여러 가지 값에 대해 다 할 수 있으면 훨씬 좋을 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같은 코드를 살펴보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656233157592&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;gt; a = 15
&amp;gt; a % 2 == 0
False
&amp;gt; a % 3 == 0
True
&amp;gt; a % 5 == 0
True
&amp;gt; a % 7 == 0
False&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a가 2, 3, 5, 7의 배수인지 알고 싶은데, 이런 식으로 하게 되면 다른 수에 대해 같은 걸 알기 위해 매번 이렇게 많은 코드를 직접 써야 되고 컴퓨터가 하는 일에 비해 우리가 쳐야 하는 키보드 키가 너무 많아집니다. (우리는 컴퓨터에게 일을 시키고 싶지 우리가 노가다를 하고 싶지는 않습니다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴 때 앞에서 살펴보았던 실행환경 사이트 playground.programiz.com 의 왼쪽에 있던 편집창을 이용해서 프로그램을 작성하면 좋습니다. 왼쪽 편집창에 다음 코드를 입력하고 Run 버튼을 누르면 오른쪽 쉘창에 실행 결과를 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;287&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPrMct/btrFIdsSYBW/RlbwbDmLTt6vvDLTpDFdM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPrMct/btrFIdsSYBW/RlbwbDmLTt6vvDLTpDFdM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPrMct/btrFIdsSYBW/RlbwbDmLTt6vvDLTpDFdM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPrMct%2FbtrFIdsSYBW%2FRlbwbDmLTt6vvDLTpDFdM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1255&quot; height=&quot;287&quot; data-origin-width=&quot;1255&quot; data-origin-height=&quot;287&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 print(&amp;nbsp; &amp;nbsp;)는 괄호 안에 있는 수식을 계산해서 그 결과를 우리가 볼 수 있게 찍어달라는 명령문입니다. 이것을 출력이라고 하죠. 그럼 오른쪽처럼 차례로 출력되는 것을 볼 수 있습니다. 이걸 좀더 알아보기 좋게 출력하기 위해 다음과 같이 바꿔볼 수도 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOR9Db/btrFLBM4BSZ/XNO7wdCWpFAFEiUySK2VGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOR9Db/btrFLBM4BSZ/XNO7wdCWpFAFEiUySK2VGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOR9Db/btrFLBM4BSZ/XNO7wdCWpFAFEiUySK2VGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOR9Db%2FbtrFLBM4BSZ%2FXNO7wdCWpFAFEiUySK2VGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1249&quot; height=&quot;269&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;print 명령문은 괄호 안에 있는 것들을 차례로 계산해서 출력하고 끝에 줄바꿈을 넣어줍니다. 문자열은 그대로 쉘창에 출력되겠지요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 숫자를 바꿔보겠습니다. 만약 15가 아니라 18에 대해 알고 싶다면? 프로그램 안에 a = 15 대신 a = 18이라고 바꿔 적고 다시 실행을 해 볼 수 있습니다. 그러나 프로그램을 고쳐야만 다른 수를 실행해 볼 수 있다면 프로그램을 짠 보람이 없습니다. 우리는 어떤 숫자든 지시한 일을 할 수 있는 프로그램을 원합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우를 위해 프로그램이 사용자가 원하는 숫자를 입력받게 하는 방법이 필요합니다. 실제로 엔간한 프로그램이라면 입력을 받고 그것을 이용해서 계산하여 결과를 보여주는 것이 가장 자연스러운 일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력을 위해서는 input('=&amp;gt; ') 이라는 함수를 이용합니다. 여기서 '=&amp;gt; '는 우리 프로그램이 입력을 받을 준비가 되어 있다는 것을 나타내는 입력 커서입니다. 쉘창의 커서와는 구별되게 하는 것이 좋겠죠? 여기서는 =&amp;gt;로 표시를 했지만 다른 것도 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1243&quot; data-origin-height=&quot;164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjhxOt/btrFIdNaH9v/Mndhg4HQsxbUOUx75trfq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjhxOt/btrFIdNaH9v/Mndhg4HQsxbUOUx75trfq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjhxOt/btrFIdNaH9v/Mndhg4HQsxbUOUx75trfq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjhxOt%2FbtrFIdNaH9v%2FMndhg4HQsxbUOUx75trfq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1243&quot; height=&quot;164&quot; data-origin-width=&quot;1243&quot; data-origin-height=&quot;164&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기서 한가지 문제가 있습니다. 입력된 55는 숫자가 아니라 문자열 '55'라는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1241&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X5iQR/btrFGmiZiC5/c3uyHexjXFS64KM0lrCqu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X5iQR/btrFGmiZiC5/c3uyHexjXFS64KM0lrCqu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X5iQR/btrFGmiZiC5/c3uyHexjXFS64KM0lrCqu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX5iQR%2FbtrFGmiZiC5%2Fc3uyHexjXFS64KM0lrCqu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1241&quot; height=&quot;179&quot; data-origin-width=&quot;1241&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;input()은 사실 무슨 입력이든 받을 수 있습니다. 그러므로 문자열도 들어올 수 있고 숫자도 들어올 수 있는 것이지요. 그래서 input()은 숫자를 받아도 그것을 문자열로 인식해서 '55'를 돌려줍니다. % 연산은 숫자에 대해서만 가능하기 때문에 이 경우 a % 2를 하면 다음과 같이 오류메시지가 나오게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1245&quot; data-origin-height=&quot;231&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dk1E5J/btrFPZzruFD/wUmYjJat7XDtnZ84VglHd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dk1E5J/btrFPZzruFD/wUmYjJat7XDtnZ84VglHd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dk1E5J/btrFPZzruFD/wUmYjJat7XDtnZ84VglHd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdk1E5J%2FbtrFPZzruFD%2FwUmYjJat7XDtnZ84VglHd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1245&quot; height=&quot;231&quot; data-origin-width=&quot;1245&quot; data-origin-height=&quot;231&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 오류 메시지는 무슨 문제가 있다는 것인지 즉시 알기 어렵지만 2번 줄에서 TypeError가 발생했음을 알려줍니다. 그 이유는 A % 2가 숫자가 아닌 문자열에 % 연산을 적용했기 때문입니다. 이것은 사실 입문한 사람이 알기는 어려운 점인데요 파이썬을 배우는 첫번째 고비라고 할 수 있죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 해결하기 위해서는 int(&amp;nbsp; &amp;nbsp;)라는 것을 이용해서 문자열을 숫자로 바꾸어야 합니다. 이것을 타입변환이라고 하는데요, 문자열로 입력받은 값을 정수 타입으로 바꿔 달라는 명령입니다. 파이썬이 알아서 하지 못하고 우리가 그것을 해주어야 하는데, 그 이유는 앞에서도 얘기했듯이 입력이 문자열이어서 숫자로 바뀔 수 없는 경우도 있기 때문에 프로그래머가 책임을 지라는 뜻으로 int(&amp;nbsp; )를 붙이도록 요구하고 있는 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/meSqK/btrFLBzxYJo/dpe1dZl2WHjuzPpRjxr861/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/meSqK/btrFLBzxYJo/dpe1dZl2WHjuzPpRjxr861/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/meSqK/btrFLBzxYJo/dpe1dZl2WHjuzPpRjxr861/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmeSqK%2FbtrFLBzxYJo%2Fdpe1dZl2WHjuzPpRjxr861%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1246&quot; height=&quot;246&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 a = int(a)는 양쪽에 a가 나와서 좀 의외죠? 오른쪽 a는 a가 가진 값을 사용하라는 뜻이고 왼쪽의 a는 a라는 이름에 오른쪽 식의 결과를 넣으라는 뜻입니다. 이렇게 해서 a에는 숫자 54가 들어가게 되었죠.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 우리가 입력을 받을 수 있게 되었으므로 프로그램 수정 없이 Run을 다시 눌러서 다른 값을 입력해 볼 수 있습니다. 사실 여기서는 편집기와 실행이 바로 붙어있지만 프로그램을 수정하지 않고 실행할 수 있다는 것은 그 프로그램을 다른 곳에 가져가서 실행만 해도 되는 상태, 즉 배포 가능한 프로그램이 되었다는 뜻입니다. 우리는 숫자를 받아 2, 3, 5, 7의 배수인지를 출력하는 배포 가능한 프로그램을 만들었습니다.&lt;/p&gt;</description>
      <category>파이썬맛보기</category>
      <category>input</category>
      <category>INT</category>
      <category>PRINT</category>
      <category>TypeError</category>
      <category>숫자입력</category>
      <category>출력</category>
      <author>plas</author>
      <guid isPermaLink="true">https://plas.tistory.com/156</guid>
      <comments>https://plas.tistory.com/156#entry156comment</comments>
      <pubDate>Sun, 26 Jun 2022 17:40:42 +0900</pubDate>
    </item>
  </channel>
</rss>