2012-05-04 12 views
5

Daha önce Java'da birkaç GUI uygulaması oluşturdum ve her seferinde iş yapmak istediğim şeyi yapana kadar uğraştığım her zaman, web'de bulduğum birkaç GUI örneğinden snippits kullanarak. Son zamanlarda Swing kullanarak Java'da bir GUI yazarken iyi uygulamalarla ilgili daha fazla bilgi okuyorum, ancak yine de bazı şeyler bana açık değil. Bir sonraki projemde ilk olarak ne yapmak istediğimi açıklamama izin verin, böylece bunu bir örnek olarak kullanabiliriz:MVC modelinde neyin saklanacağı ve bileşenlerin nasıl iletişim kurduğu.

Kullanıcıya görüntüleri yükleme, bazı eylemler gerçekleştirme yeteneği veren bir yürütülebilir uygulama oluşturmak istiyorum Bu görüntüleri ve projeyi kaydedin. Yüklenen görüntüler arasında geçiş yapmak için alt kısmında basit bir gezginin bulunduğu ana görüntü görüntüleyici bulunmalıdır. Bir görüntü üzerinde işlemleri gerçekleştiren düğmelere sahip paneller olmalıdır (örneğin, 'görüntüden arka plan rengi seçin') ve bu işlemlerin isteğe bağlı olarak bir araç çubuğundan veya menüden erişilebilir olması gerekir.

Örneğin, GUI'nin Olay Sevk İpliği'nden başlatılması gerektiğini ve zaman damgası işlemleri için SwingWorker kullanabileceğimi biliyorum. Ayrıca, Eylemler'i kullanarak işlevsellik durumunu durumdan ayırabildiğimi ve hem bir panel düğmesi hem de bir araç çubuğu düğmesi ve bir menü öğesi için bir Eylem oluşturabildiğimi öğrendim.

Anlamadığım şey, tüm bu şeylerin birbirleriyle nasıl iletişim kurduğu ve neyi nereye koyduğumdur. Örneğin: programımın durumunu (hangi görüntü şu anda görüntüleniyor, hangi ayarlar ayarlanmış) ayrı bir modelde tutmalı ve ana penceremde bu modele bir referans yazmalı mıyım? Peki ya kontrolörler? Denetleyicilerindeki modellere bir referans göstereyim mi? Ve bir görüntü üzerinde bir hesaplama yaptığımda, gui'deki görüntüyü denetleyiciden mi yoksa gui'nin kendisinden basit bir yeniden boya kullanarak mı güncellerim?

Sanırım ana problemim, programımın farklı bölümlerinin iletişim kurmasına nasıl izin verileceğini anlamam. Bir GUI bir çok parçadan oluşur ve daha sonra tüm bu Eylemler ve Dinleyiciler, modeller, kontrolörler ve bunların hepsinin bir şekilde etkileşim kurması gerekir. Bu nesnelerin hepsinde hemen hemen her şeye referans eklemeye devam ediyorum, ama her şeyi son derece dağınık hale getiriyor.

Web'de bulunan başka örnek: " 'Kes' eylem yaparlar mıydı" http://www.devdaily.com/java/java-action-abstractaction-actionlistener

Bunun nasıl çalıştığını anlamak, ben anlamadığım şu aslında nasıl değiştirileceği olduğunu gerçek kesim eylemine. İzleyicideki imgemin bir bölümünü kesmeyi gerektirdiğini varsayalım, görüntüyü eyleme geçirebilir miydim? Ve eğer bu süreç uzun sürecek olursa, eylemin içinde yeni bir SwingWorker yaratmış mıyım? Ve sonra hesaplarken SwingWorker'ın GUI'yi güncellemesine nasıl izin veririm? GUI'nin SwingWorker'a bir başvurusunu zaman zaman güncelleştirebileceği şekilde iletebilir miyim?

Bunun nasıl yapılacağına dair iyi bir örneği var mı, yoksa belki de doğru bir şekilde nasıl öğrenileceğine dair bazı ipuçları var, çünkü ben biraz kayıttım. Bir şeyler yapmak için çok fazla bilgi ve çok farklı yollar var ve ben gerçekten temiz kod ile nasıl ölçeklenebilir uygulamalar oluşturmayı öğrenmek istiyorum. Çok iyi bir açık kaynak kodlu bir proje var mı? Çok iyi bir GUI'yi tanımladığım gibi çok güzel bir şekilde gösterdim, böylece bundan öğrenebilirim?

+1

bakınız bu [Örnek] (http://stackoverflow.com/a/3072979/230513) ya da bu [Örnek] (http://stackoverflow.com/a/8534162/230513), ya hangi senin [sscce] bildirebilir (http://sscce.org/). – trashgod

+0

MVP'yi (Model-View-Presenter), örn. Bu sunumda (http://www.jgoodies.com/download/presentations/patterns-and-binding.pdf) – Robin

cevap

6

Birkaç Swing ve SWT GUI'sı oluşturdum. Bulduğum şey, bir GUI'nin kendi model görünümü (MV) yapısını gerektirmesidir. Uygulama denetleyicisi, GUI bileşenlerinden ziyade GUI modeli ile etkileşime girer.

Temel olarak, GUI'deki her Swing JPanel için bir Java fasulyesi yapıyorum. GUI bileşenleri Java çekirdeği ile etkileşime girer ve uygulama denetleyicisi Java çekirdeği (leri) ile etkileşime girer.

Oluşturduğum bir Spirograph GUI.

enter image description here

İşte Spirograph parametrelerini yönetir Java fasulye var. Denetim Masası sınıfı eklemek için düzenlenmiştir.

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

Tamam, bu çok yardımcı görünüyor, bu yüzden programın durumunu kaydetmem gerekecek Örneğin, en azından bazı MainWindowState nesnesinde GUI parçası. Ama sonra sıradaki sorum: Birisi kalem rengi düğmesini tıkladığında ne olur? ControlModel'e erişimi olan bir dinleyici var mı? Ve bu dinleyici ayrı bir sınıfta mı yoksa Kontrollü JPanel'e bir iç sınıf olarak mı eklenmiştir? – FinalArt2005

+1

Sorunuzu yanıtlamanın en kolay yolu, yanıtımdaki Denetim Masası'nın kodunu eklemektir. –

+1

GUI uygulamanızın kodunu gösterdiğiniz için çok teşekkür ederim, uygulamanızdaki farklı bileşenlerin nasıl etkileşimde bulunduğunu anlamamda gerçekten yardımcı oldu. Şimdi başvurum için bir tasarım planı yazdım ve yarın kod yazmaya başlayacağım. Eğer problemlerle karşılaşırsam buraya döneceğim, ama şimdilik bana çok yardımcı oldunuz, teşekkürler! – FinalArt2005

İlgili konular