먼저 지난번과 같은 프로그램으로 또 질문드리게 되서 매우 송구합니다..ㅠ
아무리 봐도 왜 그런지 모르겠어서...... 염치불구 하고 또 질문 드립니다...
도서의 본문 내용을 보는 창을 띄워 본문을 보게 하려 합니다. 책의 내용은 MSSQL을 이용해 서버DB에 저장되어있구요....
클라이언트가 서버에 접속해서 DB에 저장되어있는 도서목록을 살펴본후 요청한 책에 대하여 본문을 보여주는 작업을 하고 있습니다.
제가 한 방식은 클라이언트가 '도서 보기' 버튼을 누르면 "CONTENTS" 라는 문구가 서버로 전송 되고...
서버는 'CONTENTS' 라는 문구를 받으면 DB로 부터 본문의 내용을 읽어와...
한줄씩 앞에 'CONTENTS:' 라는 문구를 붙여 다시 클라이언트로 전송합니다.
다시 클라이언트는 StringTokenizer를 이용 첫번째 토큰이 'CONTENTS' 인 경우 다음 토큰을 line이라는 벡터에 저장합니다...(이는 EOF 가 전송될때까지 반복됩니다..)
그리고 BContents창(본문이 뜨는창) 의 생성자에 page를 계산하는 코드를 넣었습니다. page는 30줄씩 잘라서 page라는 arraylist에 삽입합니다.
그래서 BContents창이 뜨면 바로 1페이지의 본문 내용이 뜨게 하였습니다, 그리고 이전페이지, 다음페이지 버튼을 추가하여.. 이동이 가능하게 하였습니다..
그런데 문제는..........
이 페이지가 뜰 떄도 있고... 안뜰때도 있다는 것입니다...
잘떠서 페이지간 이동이 잘 될 떄도 있고...... 아에 아무것도 안뜬 흰 textarea만 보일 때도 있습니다...
디버거를 해보니... 전송은 잘 되는 거 같은데요.....
뭐가 문제일까요?....;;;;
//client
//BooksManagementView.java 클라이언트 메인화면
private void BAddButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
BAddi badd = new BAddi();
int posX, posY;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = badd.getSize();
posX = (int)(screenSize.getWidth() / 2) - (int)(frameSize.getWidth() / 2);
posY = (int)(screenSize.getHeight() / 2) - (int)(frameSize.getHeight() / 2);
badd.setVisible(true);
badd.setLocation(posX, posY);
}
private void BQuitButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
if(connect == 0)
System.exit(0); // 종료
else {
writer.println("QUIT");
writer.flush();
System.exit(0); // 종료
}
}
private void BDelButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
BDel bdel = new BDel();
int posX, posY;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = bdel.getSize();
posX = (int)(screenSize.getWidth() / 2) - (int)(frameSize.getWidth() / 2);
posY = (int)(screenSize.getHeight() / 2) - (int)(frameSize.getHeight() / 2);
bdel.setVisible(true);
bdel.setLocation(posX, posY);
}
private void BSearchButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
BSearch bsear = new BSearch();
int posX, posY;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = bsear.getSize();
posX = (int)(screenSize.getWidth() / 2) - (int)(frameSize.getWidth() / 2);
posY = (int)(screenSize.getHeight() / 2) - (int)(frameSize.getHeight() / 2);
bsear.setVisible(true);
bsear.setLocation(posX, posY);
//BSNOTextArea.setText(""); // 출력창 비우기
v.clear();
title.clear();
BSNOTextArea.setListData(v);
BSNTextArea.setListData(title);
BSATextArea.setText("");
BSPTextArea.setText("");
BSITextArea.setText("");
}
private void BShowButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
//BSNOTextArea.setText(""); // 출력창 비우기
v.clear();
title.clear();
BSNOTextArea.setListData(v);
BSNTextArea.setListData(title);
BSATextArea.setText("");
BSPTextArea.setText("");
BSITextArea.setText("");
writer.println("SHOW");
writer.flush();
}
private void BConnectButtonActionPerformed(java.awt.event.ActionEvent evt) {
//JOptionPane.showMessageDialog(null, "서버에 접속합니다.");
String addr;
addr = JOptionPane.showInputDialog("IP를 입력하세요(기본값: 127.0.0.1)", "127.0.0.1");
if(addr==null) {} // 취소키 눌를시 창만 닫힘
else {
try {
clientSocket = new Socket(addr,13780);
InputStreamReader stream = new InputStreamReader(clientSocket.getInputStream());
reader = new BufferedReader(stream);
connect = 1;
writer = new PrintWriter(clientSocket.getOutputStream());
JOptionPane.showMessageDialog(null, "서버에 접속되었습니다.");
}catch(IOException e) {
if(addr!=null)
JOptionPane.showMessageDialog(null, "입력한 IP에 접속할 수 없습니다.");
}
Thread receiver = new Thread(new Receiver());
receiver.start();
}
}
private void BContentsButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String Bno;
Bno = JOptionPane.showInputDialog("도서번호를 입력하세요");
if(Bno==null) {} // 취소키 눌를시 창만 닫힘
BooksManagementView.writer.println("CONTENTS:"+Bno+":");
BooksManagementView.writer.flush();
BContents bc = new BContents();
int posX, posY;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = bc.getSize();
posX = (int)(screenSize.getWidth() / 2) - (int)(frameSize.getWidth() / 2);
posY = (int)(screenSize.getHeight() / 2) - (int)(frameSize.getHeight() / 2);
bc.setVisible(true);
bc.setLocation(posX, posY);
}
private void BSNOTextAreaMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
int Bno = BSNOTextArea.locationToIndex(evt.getPoint());
Bno = Bno+1;
BooksManagementView.writer.println("CONTENTS:"+Bno+":");
BooksManagementView.writer.flush();
BContents bc = new BContents();
int posX, posY;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = bc.getSize();
posX = (int)(screenSize.getWidth() / 2) - (int)(frameSize.getWidth() / 2);
posY = (int)(screenSize.getHeight() / 2) - (int)(frameSize.getHeight() / 2);
bc.setVisible(true);
bc.setLocation(posX, posY);
}
private void BSNTextAreaMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
int Bno = BSNOTextArea.locationToIndex(evt.getPoint());
Bno = Bno+1;
BooksManagementView.writer.println("CONTENTS:"+Bno+":");
BooksManagementView.writer.flush();
BContents bc = new BContents();
int posX, posY;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = bc.getSize();
posX = (int)(screenSize.getWidth() / 2) - (int)(frameSize.getWidth() / 2);
posY = (int)(screenSize.getHeight() / 2) - (int)(frameSize.getHeight() / 2);
bc.setVisible(true);
bc.setLocation(posX, posY);
}
public class Receiver implements Runnable {
public void run() {
String message = "";
String token = ":";
line = new Vector<String>();
try {
while(true) {
message = reader.readLine();
StringTokenizer st = new StringTokenizer(message,token);
String t1 = st.nextToken();
if(message==null || message.equals("EOF"))
break;
else {
if(t1.equals("SHOW1")) {
v.add(st.nextToken()); // 벡터에 저장
BSNOTextArea.setListData(v); // JList 업데이트
}
else if(t1.equals("SHOW2")) {
title.add(st.nextToken());
BSNTextArea.setListData(title);
}
else if(t1.equals("SHOW3"))
BSATextArea.append(st.nextToken()+'\n');
else if(t1.equals("SHOW4"))
BSPTextArea.append(st.nextToken()+'\n');
else if(t1.equals("SHOW5"))
BSITextArea.append(st.nextToken()+'\n');
else if(t1.equals("SEARCH1")) {
v.add(st.nextToken());
BSNOTextArea.setListData(v);
}
else if(t1.equals("SEARCH2")) {
title.add(st.nextToken());
BSNTextArea.setListData(title);
}
else if(t1.equals("SEARCH3"))
BSATextArea.append(st.nextToken()+'\n');
else if(t1.equals("SEARCH4"))
BSPTextArea.append(st.nextToken()+'\n');
else if(t1.equals("SEARCH5"))
BSITextArea.append(st.nextToken()+'\n');
else if(t1.equals("DEL"))
JOptionPane.showMessageDialog(null, "삭제되었습니다.", "경고", JOptionPane.WARNING_MESSAGE);
else if(t1.equals("DELNO"))
JOptionPane.showMessageDialog(null, "없는 도서입니다.", "경고", JOptionPane.WARNING_MESSAGE);
else if(t1.equals("CONTENTS"))
line.add(st.nextToken());
}
}
} catch(Exception ex) {}
}
}
//BContents.java 도서본문이 뜨는창
public class BContents extends javax.swing.JFrame {
int count=0;
int i=0;
String contents="";
int totalline = BooksManagementView.line.size(); // 도서 의 총 줄의 수
ArrayList<String> page = new ArrayList<String>();
/** Creates new form BContents */
public BContents() {
initComponents();
//페이지 계산
int lineNo = BooksManagementView.line.size(); // 도서 의 총 줄의 수
int pageNo = lineNo/30; // 도서의 총 page 수
for(int x=0;x<pageNo;x++) { // 페이지당 30줄씩 contents에 입력받음
for(int p=30*x; p<30*(x+1); p++) {
contents = contents +'\n' + BooksManagementView.line.get(p);
}
page.add(contents); // 한페이지씩 arrayList에 추가
if(x==0)
BContentsText.setText(contents); // 첫페이지 화면 출력
contents="";
}
for(int q=pageNo*30; q<lineNo; q++) // 30줄씩 페이지 만든후 남은 줄에 대하여
contents = contents +'\n' + BooksManagementView.line.get(q);
page.add(contents); // 맨 마지막 페이지로 추가
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
BContetsScroll = new javax.swing.JScrollPane();
BContentsText = new javax.swing.JTextArea();
BCBeforeButton = new javax.swing.JButton();
BCNextButton = new javax.swing.JButton();
BCQuitButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setMinimumSize(new java.awt.Dimension(528, 648));
setName("Form"); // NOI18N
BContetsScroll.setName("BContetsScroll"); // NOI18N
BContentsText.setColumns(20);
org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(booksmanagement.BooksManagementApp.class).getContext().getResourceMap(BContents.class);
BContentsText.setFont(resourceMap.getFont("BContentsText.font")); // NOI18N
BContentsText.setRows(5);
BContentsText.setText(resourceMap.getString("BContentsText.text")); // NOI18N
BContentsText.setName("BContentsText"); // NOI18N
BContetsScroll.setViewportView(BContentsText);
BCBeforeButton.setText(resourceMap.getString("BCBeforeButton.text")); // NOI18N
BCBeforeButton.setName("BCBeforeButton"); // NOI18N
BCBeforeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
BCBeforeButtonActionPerformed(evt);
}
});
BCNextButton.setText(resourceMap.getString("BCNextButton.text")); // NOI18N
BCNextButton.setName("BCNextButton"); // NOI18N
BCNextButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
BCNextButtonActionPerformed(evt);
}
});
BCQuitButton.setText(resourceMap.getString("BCQuitButton.text")); // NOI18N
BCQuitButton.setName("BCQuitButton"); // NOI18N
BCQuitButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
BCQuitButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(BContetsScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 738, Short.MAX_VALUE)
.addContainerGap())
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(BCBeforeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(50, 50, 50)
.addComponent(BCNextButton, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(61, 61, 61)
.addComponent(BCQuitButton, javax.swing.GroupLayout.PREFERRED_SIZE, 123, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(133, 133, 133))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(BContetsScroll, javax.swing.GroupLayout.PREFERRED_SIZE, 558, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(BCQuitButton, javax.swing.GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE)
.addComponent(BCBeforeButton, javax.swing.GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE)
.addComponent(BCNextButton, javax.swing.GroupLayout.DEFAULT_SIZE, 48, Short.MAX_VALUE))
.addGap(20, 20, 20))
);
pack();
}// </editor-fold>
private void BCBeforeButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
BContentsText.setText("");
i=i-1;
if(i == -1) {
JOptionPane.showMessageDialog(null, "처음 페이지입니다.", "안내", JOptionPane.PLAIN_MESSAGE);
BContentsText.setText(page.get(0));
i=0;
}
else
BContentsText.setText(page.get(i));
}
private void BCNextButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
BContentsText.setText("");
i=i+1;
if(i == page.size()) {
JOptionPane.showMessageDialog(null, "마지막 페이지입니다.", "안내", JOptionPane.PLAIN_MESSAGE);
BContentsText.setText(page.get(i-1));
i=page.size()-1;
}
else
BContentsText.setText(page.get(i));
}
private void BCQuitButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
page.clear();
BooksManagementView.line.clear();
this.setVisible(false);
this.dispose();
}
... 줄이 짤리네요...
서버소스는 아래 링크에 있습니다....
http://dl.dropbox.com/u/4141484/BookServer.java
혹시 BContents 의 생성자 안에서 해주고 있는 수많은(?) 일들을 별도의 method 로 분리하고, BContents 창이 open(또는 visible) 된 후에 해줘보실 생각은 없으신가요?
실제 실행되는 소스가 저한테는 없는 관계로 테스트를 해 볼수가 없어서 ㅎㅎ
예전 (한 10년은 더 된거 같긴한데 -_-) AWT를 갖고 놀 때의 기억을 더듬어보면, component 가 visible 안된 상태에서는 layout manager 가 간혹 오작동 하는 경우가
있었던 것 같은데.. 혹시 그 이유는 아닐까 싶네요.
보통 될때도 있고, 안될때도 있다. 동일한 환경 동일한 데이터 무엇이 문제인가?
라는 상황은 thread 간의 race-condition이 발생할때 나타납니다. 본인이 thread를 쓰지 않았다고 해도, AWT(Swing)는 자체적으로 다수의 thread(이벤트 펌핑 등을 위해)를
생성시키게 되고, 얘들이 main thread와 간혹 꼬이기도 한답니다. ;]