你的问题在这里不太合适。此外,尽管您的讲师声称不准确,但仍然可以想象一个人自己进行研究以从您必须的一组相当不错的特定要求到一个正常运行的程序。我并不是说它听起来那么重要。
不过,出于对你找导师的感激之情,也出于同情,也许我可以给你一些起点和提示。
首先,Swing 是正确的开始方式。阅读http://zetcode.com/tutorials/javaswingtutorial/上教程的相关部分,并跟随其中的一些项目。
您可以很容易地手动编写 Swing 接口,对于您相对简单的应用程序和学习体验来说,这是一个合理的选择。但是,为了将来参考,许多 IDE 都有 GUI 编辑器(NetBeans 附带我认为的功能,Eclipse 有 WindowBuilder 插件) - 需要注意的是,您必须将学习如何使用 IDE 添加到您的任务列表中(当然,这从长远来看,最终将节省您的时间)。
无论如何,您的第一步应该是设计您的软件。确定您需要执行哪些操作、您需要响应哪些用户操作、如何响应以及您正在使用哪些信息。您提出以下要求:
控制窗口仅对选定对象进行操作。单击更改图像按钮执行以下任务(取决于所选面部部分):
- 头部:头部由绿色变为黄色,变为紫色变为紫色,再变为绿色
- 鼻子:鼻子图像改变了三个可能的鼻子图像中的另一个
- 嘴巴:嘴巴图像变为三个可能的嘴巴图像中的另一个
- 眼睛:眼睛图像变为四个可能的眼睛图像中的另一个
包括带有行为的滚动条:
- 选定的头部:头部随着滚动条值的变化而变宽和变窄
- 选定的鼻子:鼻子图像随着滚动条值的变化向上或向下移动
- 选定嘴巴:嘴巴随着滚动条值的变化而变宽或变窄
- 选定的眼睛:眼睛随着滚动条值的变化而靠得更近或更远
您在这里使用的基本组件是一张脸,所以让我们在这里做出一个设计决定,让一张脸成为一个具有其他属性的对象(您可以采用不同的方法,让脸的不同部分成为您的基本单位)。根据您对滚动条的描述,面部具有以下可修改属性:
- 头宽。
- 垂直的鼻子位置。
- 口宽。
- 两眼之间的距离。
当然,一张脸还具有其他不变的特征,这些特征几乎取决于您任意决定的值,例如眼睛的直径、皮肤的颜色等。您必须解决这些问题。
除了修改上述属性之外,您还需要对人脸进行一些操作,也可以直接根据您的要求:
- 画(画)脸。
- 属性更改时重绘(重绘)面。
- 允许用户通过单击来选择一个部分,它分为:
- 响应鼠标点击。
- 在给定 XY 位置的情况下确定光标下的组件。
- 向应用程序提供有关选择的信息。
最后一部分“提供有关选择的信息”是一个实现细节,您有几个选择,您必须做出决定。例如,您可以创建某种类型的事件侦听器接口并将其告知面子,并让它在选择更改时调用该接口上的方法——这是一种非常灵活的方法。您还可以让面在内部维护当前选择的属性,在这种情况下,您需要赋予它获取/设置当前选定属性的值的能力。您还可以在编辑器 UI 窗口上直接调用方法。所有这些方法都有明显的优点和缺点,我将把它作为练习留给读者进行实验。
现在,您还需要根据您的要求在单独的窗口中为用户提供一个滚动条来编辑属性。所以现在,考虑一下您需要哪些 UI 组件以及您希望它们如何结合在一起:
- 面窗
- 编辑器窗口
- 包含滚动条。
- 如果您愿意,可能包含描述当前选择的标签。
Swing 已经提供了这些组件中的大部分。一个窗口是一个JFrame
。滚动条是一个JScrollBar
. 标签是JLabel
. Swing 不提供面,因此您需要自己编写自定义组件。
至于它们是如何联系在一起的:
- 更改面部的对象选择可以:
- 如果您愿意,将滚动条更新为当前值。
- 将滚动条范围更新为适当的值。
- 如果您愿意,请更新标签以描述当前选择。
- 更改滚动条必须:
那么,现在的主要任务是实现一个 Swing 组件,它可以绘制一张脸并响应鼠标点击。
由于您正在创建一个新组件,因此您需要选择一个合适的基础,可能是 aJComponent
或 a JPanel
,由您决定。在 Google 上的许多教程(包括我上面链接的教程中的一些基础知识)中可以很容易地找到如何创建新组件,这取决于您自己研究。但是,本质上,重申上面所说的,您的自定义面部组件具有以下自定义行为:
- 画一张脸。
- 接收鼠标事件。
- 从鼠标 X、Y 坐标确定单击的组件。在最基本的层面上,这将需要一些数学知识。例如,如果您的头部、眼睛、嘴巴和鼻子是椭圆,则由您来计算给定的 X、Y 坐标是否在这些椭圆之一的范围内。但是,您将需要查看Shape,这将允许您轻松定义形状并提供边界检查方法。
我认为这足以让您开始并将它们放在一起。手头有以下一般任务:
- 阅读我链接的那个教程,很多基础知识应该会变得清晰。尝试编写一些简单的“hello world”风格的应用程序。
- 尝试编写一些自定义组件;您的要求是基本的,其中大部分内容都包含在该教程的“绘画”部分中。
- 查看有关如何使用
Shape
和实验的教程或一些示例。
如果您对编写的代码有特定的问题,或者您可能正在尝试解决特定的问题,您可以随时回来并在 SO 上发布。
我希望这有帮助。更重要的是,我希望这至少能让您大致了解如何从需求到实现。
编辑:
我已经有一段时间没有玩了,Shape
所以我把这个小例子放在一起。单击/拖动两个形状以选择它们,这将使它们变为黄色:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class ShapeSelect extends JPanel {
private final Shape firstShape = new Rectangle2D.Float(60, 40, 70, 70);
private final Shape secondShape = new Ellipse2D.Float(30, 30, 90, 50);
private Shape selected = null;
public ShapeSelect () {
// set up the component
setPreferredSize(new Dimension(200, 200));
addMouseMotionListener(new MouseMotionAdapter() {
@Override public void mouseDragged (MouseEvent event) {
selectShapeUnder(event.getX(), event.getY());
}
});
addMouseListener(new MouseAdapter() {
@Override public void mousePressed (MouseEvent event) {
selectShapeUnder(event.getX(), event.getY());
}
});
}
// draw our shapes, selected shape is yellow.
@Override protected void paintComponent (Graphics g) {
Graphics2D graphics = (Graphics2D)g;
graphics.setColor((selected == firstShape) ? Color.YELLOW : Color.RED);
graphics.fill(firstShape);
graphics.setColor((selected == secondShape) ? Color.YELLOW : Color.GREEN);
graphics.fill(secondShape);
}
// updates 'selected' based on x,y coordinate and redraws component on change.
public void selectShapeUnder (int x, int y) {
Shape oldSelected = selected;
// note that since second shape is draw on top of first, we give second preference.
// for overlapping shapes the selection should be consistent with the gui display.
if (secondShape.contains(x, y))
selected = secondShape;
else if (firstShape.contains(x, y))
selected = firstShape;
else
selected = null;
if (selected != oldSelected)
repaint();
}
public static final void main (String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override public void run () {
JFrame frame = new JFrame("Shape Select");
frame.getContentPane().add(new ShapeSelect(), BorderLayout.CENTER);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}