Fin*_*005 5 java model-view-controller swing
我以前用Java创建了一些GUI应用程序,每次我真的只是乱搞,直到我想要它做的事情,使用我在网上找到的几个GUI示例的snippit.最近我阅读了一些关于使用Swing在Java中编写GUI时的良好实践,但仍有一些事情我不清楚.让我先描述一下我在下一个项目中想要做什么,以便我们可以将其作为一个例子:
我想创建一个可执行应用程序,使用户能够加载图像,对这些图像执行某些操作并保存项目.核心应该有一个主图像查看器,下面有一个简单的导航器,可以在加载的图像之间切换.应该有带按钮的面板对图像执行操作(例如按钮'从图像中选择背景颜色'),这些操作应该可以从工具栏或菜单中访问.
我知道,例如,GUI应该从Event Dispatch Thread启动,并且我可以使用SwingWorker进行耗时的操作.我还了解到,通过使用Actions,我可以将功能与状态分开,并为面板按钮,工具栏按钮和菜单项创建一个Action.
我不明白的是所有这些事情是如何相互沟通的,以及我把它放在哪里.例如:我是否在一个单独的模型中维护我的程序状态(当前显示哪个图像,设置了什么设置),并在我的主窗口类中引用该模型?那控制器怎么样?我是否继续参考控制器中的模型?当我对图像进行一些计算时,是否使用简单的重绘更新控制器中的gui图像或gui本身的图像?
我想我遇到的主要问题是我真的不明白如何让程序的不同部分进行通信.GUI由许多部分组成,然后有所有这些动作和监听器,模型,控制器,并且所有这些都需要以某种方式进行交互.我不断添加对所有这些对象中几乎所有内容的引用,但它使一切都非常混乱.
我在网上找到的另一个例子是:http: //www.devdaily.com/java/java-action-abstractaction-actionlistener
我理解这是如何工作的,我不明白的是如何真正改变"本来会做'切'动作." 进入实际切割动作.让我们说它涉及在观察者中从我的图像中切出一部分,我是否已将图像传递给动作?如果这个过程需要很长时间,我会在动作中创建一个新的SwingWorker吗?然后我如何让SwingWorker在计算时更新GUI?我是否会将GUI的引用传递给SwingWorker,以便它可以不时更新它?
有没有人有一个如何做到这一点的好例子,或者有关如何正确学习这个的一些提示,因为我有点不知所措.有太多的信息和许多不同的做事方式,我真的想学习如何使用干净的代码创建可伸缩的应用程序.是否有一个很好的开源项目,没有太多的代码,非常好地演示了我所描述的GUI,以便我可以从中学习?
我已经构建了一些Swing和SWT GUI.我发现GUI需要自己的模型 - 视图(MV)结构.应用程序控制器与GUI模型交互,而不是GUI组件.
基本上,我在GUI中为每个Swing JPanel构建一个Java bean.GUI组件与Java bean交互,应用程序控制器与Java bean交互.
这是我创建的Spirograph GUI.

这是管理Spirograph参数的Java bean.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑添加控制面板类.
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();
}
}
}
Run Code Online (Sandbox Code Playgroud)