2012-05-04 2 views
5

이전에 Java로 몇 가지 GUI 응용 프로그램을 만들었습니다. 웹에서 찾은 여러 가지 GUI 예제의 스 니펫을 사용하여 원하는 작업을 수행 할 때까지는 정말 혼란 스럽습니다. 최근에 Swing을 사용하여 Java로 GUI를 작성할 때 좋은 사례에 대해 더 읽었지만 나에게 불분명 한 점이 몇 가지 있습니다. 먼저 다음 프로젝트에서 내가하고 싶은 것을 설명해 예를 들어 설명해 드리겠습니다.MVC 모델에 무엇을 저장할 것이며 구성 요소는 어떻게 통신합니까?

사용자에게 이미지를로드하고 일부 작업을 수행 할 수있는 실행 응용 프로그램을 만들고 싶습니다. 이러한 이미지를 저장하고 프로젝트를 저장하십시오. 로드 된 이미지를 전환하려면 간단한 탐색기가있는 기본 이미지 뷰어가 코어에 있어야합니다. 이미지에 대한 작업을 수행하는 버튼이있는 패널이 있어야합니다 (예 : 버튼의 '배경 색상 선택'). 이러한 작업에는 도구 모음이나 메뉴에서 선택적으로 액세스 할 수 있어야합니다.

예를 들어 GUI는 이벤트 발송 스레드에서 시작해야하며 시간 소비 작업을 위해 SwingWorker를 사용할 수 있다는 것을 알고 있습니다. 또한 액션을 사용하여 상태에서 기능을 분리하고 패널 버튼, 툴바 버튼 및 메뉴 항목 모두에 대해 하나의 액션을 만들 수 있음을 알게되었습니다.

내가 이해할 수없는 것은 이러한 모든 것들이 서로 통신하는 방법과 무엇을 넣는 지입니다. 예를 들어 : 내 모델의 상태를 유지합니까 (현재 어떤 이미지가 표시되어 있고 어떤 설정이 설정되어 있습니까)를 별도 모델로 유지하고이 모델에 대한 참조를 기본 창 클래스에 저장합니까? 컨트롤러는 어떨까요? 제어기의 모델에 대한 참조를 계속 유지합니까? 이미지에 대한 계산을 수행 할 때 컨트롤러에서 gui의 이미지를 업데이트하거나 간단한 repaint를 사용하여 GUI 자체에서 이미지를 업데이트합니까?

내가 가진 주요 문제는 내 프로그램의 다른 부분을 어떻게 통신하게 하는지를 이해할 수 없다는 것입니다. GUI는 많은 부분으로 구성되어 있으며, 이러한 모든 액션과 리스너, 모델, 컨트롤러가 있으며, 이러한 모든 작업이 어떻게 든 상호 작용할 필요가 있습니다. 이 모든 객체에서 거의 모든 것에 대한 참조를 계속 추가하지만 모든 것을 지저분하게 만듭니다.

내가 웹에서 찾은 또 다른 예 : ". '잘라 내기'조치를했을 것" http://www.devdaily.com/java/java-action-abstractaction-actionlistener

나는 이것이 어떻게 작동하는지 이해가, 이해가 안 무엇을 실제로 변경하는 방법입니다 실제 절단 작업으로 뷰어에서 내 이미지의 일부를 자르는 것이 포함되어 있다고 가정 해 봅시다. 이미지를 액션에 전달 했습니까? 그리고이 과정이 오래 걸리면 액션 안에 새로운 SwingWorker를 만들 수 있습니까? 그리고 SwingWorker가 계산하는 동안 어떻게 GUI를 업데이트하게 할 수 있습니까? SwingWorker에 대한 GUI 참조를 수시로 업데이트 할 수 있습니까?

아무에게도 이것을 수행하는 방법에 대한 좋은 예가 있거나 정확하게 이것을 배우는 방법에 대한 팁이 있습니다. 왜냐하면 나는 약간의 손실을 겪고 있기 때문입니다. 많은 정보와 다양한 방법으로 일을 처리 할 수 ​​있으며 깨끗한 코드로 확장 가능한 응용 프로그램을 만드는 방법을 배우고 싶습니다. 거기에 대해 배울 수 있도록 내가 설명한 것과 같은 GUI를 매우 잘 보여주는 코드가 너무 많지 않은 오픈 소스 프로젝트가 있습니까?

+1

보기이 [실시 예] (http://stackoverflow.com/a/3072979/230513) 또는 본 실시 예 (http://stackoverflow.com/a/8534162/230513) 중 어느 귀하의 [sscce] (http://sscce.org/)에 알릴 수 있습니다. – trashgod

+0

MVP (Model-View-Presenter)를 확인할 수도 있습니다. [이 프레젠테이션] (http://www.jgoodies.com/download/presentations/patterns-and-binding.pdf) – Robin

답변

6

몇 가지 Swing 및 SWT GUI를 만들었습니다. 내가 찾은 것은 GUI가 자체 MV (model-view) 구조를 필요로한다는 것입니다. 응용 프로그램 컨트롤러는 GUI 구성 요소가 아닌 GUI 모델과 상호 작용합니다.

기본적으로 저는 GUI에서 모든 Swing JPanel에 대한 Java bean을 빌드합니다. GUI 구성 요소는 Java Bean과 상호 작용하고 응용 프로그램 제어기는 Java Bean과 상호 작용합니다.

내가 만든 Spirograph GUI는 다음과 같습니다.

enter image description here

다음은 스피로 그래프 매개 변수를 관리하는 자바 빈입니다.

import java.awt.Color; 

public class ControlModel { 

    protected boolean isAnimated; 

    protected int jpanelWidth; 
    protected int outerCircle; 
    protected int innerCircle; 
    protected int penLocation; 
    protected int penSize; 

    protected Color penColor; 
    protected Color backgroundColor; 

    public ControlModel() { 
     init(); 
     this.penColor = Color.BLUE; 
     this.backgroundColor = Color.WHITE; 
    } 

    public void init() { 
     this.jpanelWidth = 512; 
     this.outerCircle = 1000; 
     this.innerCircle = 520; 
     this.penLocation = 400; 
     this.penSize = 2; 
     this.isAnimated = true; 
    } 

    public int getOuterCircle() { 
     return outerCircle; 
    } 

    public void setOuterCircle(int outerCircle) { 
     this.outerCircle = outerCircle; 
    } 

    public int getInnerCircle() { 
     return innerCircle; 
    } 

    public void setInnerCircle(int innerCircle) { 
     this.innerCircle = innerCircle; 
    } 

    public int getPenLocation() { 
     return penLocation; 
    } 

    public void setPenLocation(int penLocation) { 
     this.penLocation = penLocation; 
    } 

    public int getPenSize() { 
     return penSize; 
    } 

    public void setPenSize(int penSize) { 
     this.penSize = penSize; 
    } 

    public boolean isAnimated() { 
     return isAnimated; 
    } 

    public void setAnimated(boolean isAnimated) { 
     this.isAnimated = isAnimated; 
    } 

    public Color getPenColor() { 
     return penColor; 
    } 

    public void setPenColor(Color penColor) { 
     this.penColor = penColor; 
    } 

    public Color getBackgroundColor() { 
     return backgroundColor; 
    } 

    public void setBackgroundColor(Color backgroundColor) { 
     this.backgroundColor = backgroundColor; 
    } 

    public int getJpanelWidth() { 
     return jpanelWidth; 
    } 

    public int getJpanelHeight() { 
     return jpanelWidth; 
    } 

} 

컨트롤 패널 클래스를 추가하기 위해 편집 됨.

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Container; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.GridLayout; 
import java.awt.Insets; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 

import javax.swing.JButton; 
import javax.swing.JColorChooser; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JTextField; 
import javax.swing.JToggleButton; 
import javax.swing.SwingConstants; 

import com.ggl.spirograph.model.ControlModel; 

public class ControlPanel { 

    protected static final Insets entryInsets = new Insets(0, 10, 4, 10); 
    protected static final Insets titleInsets = new Insets(0, 10, 20, 10); 

    protected ControlModel model; 

    protected DrawingPanel drawingPanel; 

    protected JButton drawButton; 
    protected JButton stopButton; 
    protected JButton resetButton; 
    protected JButton foregroundColorButton; 
    protected JButton backgroundColorButton; 

    protected JLabel message; 

    protected JPanel panel; 

    protected JTextField outerCircleField; 
    protected JTextField innerCircleField; 
    protected JTextField penLocationField; 
    protected JTextField penSizeField; 
    protected JTextField penFadeField; 

    protected JToggleButton animationToggleButton; 
    protected JToggleButton fastToggleButton; 

    protected static final int messageLength = 100; 
    protected String blankMessage; 

    public ControlPanel(ControlModel model) { 
     this.model = model; 
     this.blankMessage = createBlankMessage(); 
     createPartControl(); 
     setFieldValues(); 
     setColorValues(); 
    } 

    public void setDrawingPanel(DrawingPanel drawingPanel) { 
     this.drawingPanel = drawingPanel; 
    } 

    protected String createBlankMessage() { 
     StringBuilder sb = new StringBuilder(); 
     for (int i = 0; i < messageLength/4; i++) { 
      sb.append(" "); 
     } 
     return sb.toString(); 
    } 

    protected void createPartControl() { 
     panel = new JPanel(); 
     panel.setLayout(new GridBagLayout()); 

     int gridy = 0; 

     JLabel title = new JLabel("Spirograph Parameters"); 
     title.setHorizontalAlignment(SwingConstants.CENTER); 
     addComponent(panel, title, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     resetButton = new JButton("Reset Default Parameters"); 
     resetButton.setHorizontalAlignment(SwingConstants.CENTER); 
     resetButton.addActionListener(new ResetButtonListener()); 
     addComponent(panel, resetButton, 0, gridy++, 4, 1, entryInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     JLabel outerCircleLabel = new JLabel("Outer circle radius:"); 
     outerCircleLabel.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, outerCircleLabel, 0, gridy, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     outerCircleField = new JTextField(5); 
     outerCircleField.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, outerCircleField, 2, gridy++, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     JLabel innerCircleLabel = new JLabel("Inner circle radius:"); 
     innerCircleLabel.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, innerCircleLabel, 0, gridy, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     innerCircleField = new JTextField(5); 
     innerCircleField.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, innerCircleField, 2, gridy++, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     JLabel penLocationLabel = new JLabel("Pen location radius:"); 
     penLocationLabel.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, penLocationLabel, 0, gridy, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     penLocationField = new JTextField(5); 
     penLocationField.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, penLocationField, 2, gridy++, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     JLabel penSizeLabel = new JLabel("Pen size:"); 
     penSizeLabel.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, penSizeLabel, 0, gridy, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     penSizeField = new JTextField(5); 
     penSizeField.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, penSizeField, 2, gridy++, 2, 1, entryInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     message = new JLabel(blankMessage); 
     message.setForeground(Color.RED); 
     message.setHorizontalAlignment(SwingConstants.LEFT); 
     addComponent(panel, message, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL); 

     title = new JLabel("Drawing Speed"); 
     title.setHorizontalAlignment(SwingConstants.CENTER); 
     addComponent(panel, title, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 4, 0)); 

     animationToggleButton = new JToggleButton("Animated"); 
     animationToggleButton.setSelected(model.isAnimated()); 
     animationToggleButton.setHorizontalAlignment(SwingConstants.CENTER); 
     animationToggleButton.addActionListener(new DrawingSpeedListener(
       animationToggleButton)); 
     buttonPanel.add(animationToggleButton); 

     fastToggleButton = new JToggleButton("Fast"); 
     fastToggleButton.setSelected(!model.isAnimated()); 
     fastToggleButton.setHorizontalAlignment(SwingConstants.CENTER); 
     fastToggleButton.addActionListener(new DrawingSpeedListener(
       fastToggleButton)); 
     buttonPanel.add(fastToggleButton); 

     addComponent(panel, buttonPanel, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     title = new JLabel("Drawing Colors"); 
     title.setHorizontalAlignment(SwingConstants.CENTER); 
     addComponent(panel, title, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     buttonPanel = new JPanel(new GridLayout(1, 2, 4, 0)); 

     foregroundColorButton = new JButton("Pen"); 
     foregroundColorButton.setHorizontalAlignment(SwingConstants.CENTER); 
     foregroundColorButton.addActionListener(new ColorSelectListener(
       foregroundColorButton)); 
     buttonPanel.add(foregroundColorButton); 

     backgroundColorButton = new JButton("Paper"); 
     backgroundColorButton.setHorizontalAlignment(SwingConstants.CENTER); 
     backgroundColorButton.addActionListener(new ColorSelectListener(
       backgroundColorButton)); 
     buttonPanel.add(backgroundColorButton); 

     addComponent(panel, buttonPanel, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     title = new JLabel("Drawing Controls"); 
     title.setHorizontalAlignment(SwingConstants.CENTER); 
     addComponent(panel, title, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 

     buttonPanel = new JPanel(new GridLayout(1, 2, 4, 0)); 

     drawButton = new JButton("Draw"); 
     drawButton.setHorizontalAlignment(SwingConstants.CENTER); 
     drawButton.addActionListener(new DrawButtonListener()); 
     buttonPanel.add(drawButton); 

     stopButton = new JButton("Stop"); 
     stopButton.setHorizontalAlignment(SwingConstants.CENTER); 
     stopButton.addActionListener(new StopButtonListener()); 
     buttonPanel.add(stopButton); 

     addComponent(panel, buttonPanel, 0, gridy++, 4, 1, titleInsets, 
       GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL); 
    } 

    protected void addComponent(Container container, Component component, 
      int gridx, int gridy, int gridwidth, int gridheight, 
      Insets insets, int anchor, int fill) { 
     GridBagConstraints gbc = new GridBagConstraints(gridx, gridy, 
       gridwidth, gridheight, 1.0, 1.0, anchor, fill, insets, 0, 0); 
     container.add(component, gbc); 
    } 

    protected void setFieldValues() { 
     outerCircleField.setText(Integer.toString(model.getOuterCircle())); 
     innerCircleField.setText(Integer.toString(model.getInnerCircle())); 
     penLocationField.setText(Integer.toString(model.getPenLocation())); 
     penSizeField.setText(Integer.toString(model.getPenSize())); 
    } 

    protected void setColorValues() { 
     foregroundColorButton.setForeground(model.getBackgroundColor()); 
     foregroundColorButton.setBackground(model.getPenColor()); 

     backgroundColorButton.setForeground(model.getPenColor()); 
     backgroundColorButton.setBackground(model.getBackgroundColor()); 
    } 

    public JPanel getPanel() { 
     return panel; 
    } 

    public class ResetButtonListener implements ActionListener { 

     @Override 
     public void actionPerformed(ActionEvent e) { 
      model.init(); 
      setFieldValues(); 
     } 

    } 

    public class StopButtonListener implements ActionListener { 

     @Override 
     public void actionPerformed(ActionEvent arg0) { 
      drawingPanel.stop(); 
     } 

    } 

    public class DrawButtonListener implements ActionListener { 

     @Override 
     public void actionPerformed(ActionEvent event) { 
      message.setText(blankMessage); 

      int ocTest = isNumeric(outerCircleField.getText()); 
      int icTest = isNumeric(innerCircleField.getText()); 
      int plTest = isNumeric(penLocationField.getText()); 
      int psTest = isNumeric(penSizeField.getText()); 

      boolean isInvalid = false; 

      if (psTest < 0) { 
       message.setText("Pen size is not a valid integer"); 
       isInvalid = true; 
      } 

      if (plTest < 0) { 
       message.setText("Pen location radius is not a valid integer"); 
       isInvalid = true; 
      } 

      if (icTest < 0) { 
       message.setText("Inner circle radius is not a valid integer"); 
       isInvalid = true; 
      } 

      if (ocTest < 0) { 
       message.setText("Outer circle radius is not a valid integer"); 
       isInvalid = true; 
      } 

      if (isInvalid) { 
       return; 
      } 

      if (ocTest > 1000) { 
       message.setText("The outer circle cannot be larger than 1000"); 
       isInvalid = true; 
      } 

      if (ocTest <= icTest) { 
       message.setText("The inner circle must be smaller than the outer circle"); 
       isInvalid = true; 
      } 

      if (icTest <= plTest) { 
       message.setText("The pen location must be smaller than the inner circle"); 
       isInvalid = true; 
      } 

      if (isInvalid) { 
       return; 
      } 

      model.setOuterCircle(ocTest); 
      model.setInnerCircle(icTest); 
      model.setPenLocation(plTest); 
      model.setPenSize(psTest); 

      drawingPanel.draw(model.isAnimated()); 
     } 

     protected int isNumeric(String field) { 
      try { 
       return Integer.parseInt(field); 
      } catch (NumberFormatException e) { 
       return Integer.MIN_VALUE; 
      } 
     } 

    } 

    public class DrawingSpeedListener implements ActionListener { 

     JToggleButton selectedButton; 

     public DrawingSpeedListener(JToggleButton selectedButton) { 
      this.selectedButton = selectedButton; 
     } 

     @Override 
     public void actionPerformed(ActionEvent arg0) { 
      if (selectedButton.equals(animationToggleButton)) { 
       model.setAnimated(true); 
      } else { 
       model.setAnimated(false); 
      } 

      animationToggleButton.setSelected(model.isAnimated()); 
      fastToggleButton.setSelected(!model.isAnimated()); 
     } 

    } 

    public class ColorSelectListener implements ActionListener { 

     JButton selectedButton; 

     public ColorSelectListener(JButton selectedButton) { 
      this.selectedButton = selectedButton; 
     } 

     @Override 
     public void actionPerformed(ActionEvent arg0) { 
      if (selectedButton.equals(foregroundColorButton)) { 
       Color initialColor = model.getPenColor(); 
       Color selectedColor = JColorChooser.showDialog(drawingPanel, 
         "Select pen color", initialColor); 
       if (selectedColor != null) { 
        model.setPenColor(selectedColor); 
       } 
      } else if (selectedButton.equals(backgroundColorButton)) { 
       Color initialColor = model.getBackgroundColor(); 
       Color selectedColor = JColorChooser.showDialog(drawingPanel, 
         "Select paper color", initialColor); 
       if (selectedColor != null) { 
        model.setBackgroundColor(selectedColor); 
       } 
      } 
      setColorValues(); 
     } 

    } 

} 
+0

좋아,이게 아주 도움이 될 것 같아. 그래서 나는 프로그램의 상태를 저장해야 할 것 같아. , 최소한의 GUI 부분, 일부 MainWindowState 객체 예를 들어. 하지만 다음 질문 : 누군가가 펜 색상 버튼을 클릭하면 어떻게됩니까? ControlModel에 액세스 할 수있는 리스너가 연결되어 있습니까? 그리고이 청취자는 별도의 클래스에 있습니까? 아니면 컨트롤 JPanel에 내부 클래스로 추가되어 있습니까? – FinalArt2005

+1

질문에 대답하는 가장 쉬운 방법은 내 대답에 제어판의 코드를 포함시키는 것입니다. –

+1

GUI 응용 프로그램의 코드를 보여 주셔서 대단히 감사합니다. 응용 프로그램의 여러 구성 요소가 어떻게 상호 작용하는지 이해할 수있었습니다. 이제 응용 프로그램을위한 설계 계획을 작성 했으므로 내일 코드 작성을 시작하겠습니다. 문제가 생기면 여기로 돌아올거야.하지만 지금은 너를 많이 도와 줬어. 고마워! – FinalArt2005

관련 문제