我正在出于好奇而开始一个项目。我项目的目的是使用Java在Minecraft中创建资源包。最后,我想向Minecraft添加自定义歌曲。由于我是Java的新手,现在是本科生,所以我认为探索Java和学习可能是个好主意。无论如何,我想我会尝试创建自己的自定义绘画程序来创建包装图像。这是我现在遇到的问题:
我正在为某些绘画程序中的存储桶工具功能建模。我决定对其进行多线程处理,因为根据要绘制的区域大小,这可能是一个漫长的任务。具体来说,我在重叠线程方面遇到问题。我以前从未做过多线程处理,但是我感觉自己已经很接近正确了。
我尝试使用SwingWorker和Thread类。我最终发现它们都达到了完全相同的问题。因此,我决定摆脱SwingWorker并使用Thread,因为它更易于编码。 paintImmediately(0,0,getWidth(),getHeight())和repaint()方法对于完成这项工作至关重要。 paintImmediately方法位于 pixel [p]内部。我编写的Pixel类中的setColor()方法,对于这个问题,我认为并不重要。实现和不实现repaint()方法有很大的不同- repaint修复了图形问题,但导致每个线程执行得慢得多。如果没有重绘方法,线程的运行速度会大大提高,但它们会重叠。
顺便说一句,为了使我更容易监视和调试我的绘画程序,我已经将自己编写的所有类标记为私有。我计划一旦Paint程序按照我想要的方式运行,就将这些类放入单独的Java文件中。
PixelBoard:
private class PixelBoard extends JPanel implements MouseListener, MouseMotionListener {
private boolean leftMouse = false;
private HiddenOptions hiddenOptions;
@Override
public void mousePressed(MouseEvent m) {
leftMouse = (hiddenOptions == null) ? m.getButton() == MouseEvent.BUTTON1 : false;
boolean middleMouse = m.getButton() == MouseEvent.BUTTON2, rightMouse = (hiddenOptions == null) ? m.getButton() == MouseEvent.BUTTON3 : false;
Pixel p = (Pixel) m.getSource();
if (leftMouse) {
if (menuBar.isBucket()) {
ArrayList<Integer> bucket = new Bucket(p.getIndex(), p.getColor()).bucket();
drawnPixels.addAll(bucket);
} else {
setColor(p, colors.getColor());
}
} else if (middleMouse) {
if (hiddenOptions == null)
hiddenOptions = new HiddenOptions();
} else if (rightMouse) {
colors.setColor(p.getColor()); //'colors' is a JColorChooser declared in the Main class
}
}
}
存储桶:
private class Bucket implements Runnable {
private ArrayList<Integer> bucket = new ArrayList<Integer>(), getPixels = new ArrayList<Integer>();
private Color getColor = colors.getColor(), groupColor;
public Bucket(int startPixel, Color groupColor) {
this.groupColor = groupColor;
if (groupColor != getColor) {
add(startPixel);
getPixels.add(startPixel);
}
new Thread(this).start();
}
@Override
public void run() {
while (!getPixels.isEmpty()) {
move();
}
}
public ArrayList<Integer> bucket() {
return bucket;
}
private void add(int p) {
pixel[p].setColor(getColor);
pixel[p].setToolTipText(pixel(p));
container.repaint();
bucket.add(p);
}
private void move() {
ArrayList<Integer> pix = new ArrayList<Integer>();
for (int p : getPixels) {
for (int m : move(p)) {
if (!bucket.contains(m)) {
if (pixel[m].getColor().equals(groupColor)) {
add(m);
pix.add(m);
}
}
}
}
getPixels = pix;
}
private boolean[] pixelLocations(int index) {
boolean topLeftCorner = index == 0, topRightCorner = index == pixels - 1;
boolean bottomLeftCorner = index == lastPixel - pixels, bottomRightCorner = index == lastPixel - 1;
boolean leftEdge = index % pixels == 0, rightEdge = (index + 1) % pixels == 0;
boolean topEdge = index > 0 && index < pixels - 1, bottomEdge = index > lastPixel - pixels && index < lastPixel - 1;
return new boolean[] {topLeftCorner, topRightCorner, bottomLeftCorner, bottomRightCorner, leftEdge, rightEdge, topEdge, bottomEdge};
}
private int[] move(int p) {
int[] move = {p + 1, p - 1, p + pixels, p - pixels};
boolean[] location = pixelLocations(p);
if (location[0])
move = move(move, new int[] {0, 2});
else if (location[1])
move = move(move, new int[] {1, 2});
else if (location[2])
move = move(move, new int[] {0, 3});
else if (location[3])
move = move(move, new int[] {1, 3});
else if (location[4])
move = move(move, new int[] {0, 2, 3});
else if (location[5])
move = move(move, new int[] {1, 2, 3});
else if (location[6])
move = move(move, new int[] {0, 1, 2});
else if (location[7])
move = move(move, new int[] {0, 1, 3});
return move;
}
private int[] move(int[] move, int[] newMove) {
int[] m = new int[newMove.length];
for (int i = 0; i < m.length; i++)
m[i] = move[newMove[i]];
return m;
}
}
简单地(立即删除)重新绘制方法会产生非常明显的影响:
删除Pixel类中的paintImmediately方法(此处未显示) 不显示重叠,但是会降低每个线程的执行速度。
paintImmediately方法确实可以立即显示结果,但是您可以 看到有些像素与另一像素有一些重叠的颜色 线。
编辑:使用SwingWorker-我注意到SwingWorker出现了与使用Thread类时完全相同的问题
private class Bucket extends SwingWorker<ArrayList<Integer>, Void> {
private ArrayList<Integer> getBucket, getPixels = new ArrayList<Integer>();
private Color groupColor;
private int startPixel;
public Bucket(int startPixel, Color groupColor) {
this.startPixel = startPixel; this.groupColor = groupColor;
execute();
}
@Override
protected ArrayList<Integer> doInBackground() throws Exception {
ArrayList<Integer> bucket = new ArrayList<Integer>();
Color getColor = colors.getColor();
if (groupColor != getColor) {
bucket = add(startPixel, getColor, bucket);
getPixels.add(startPixel);
}
while (!getPixels.isEmpty()) {
move(getColor, bucket);
}
return bucket;
}
@Override
protected void done() {
try {
getBucket = get();
} catch (InterruptedException|ExecutionException e) {
e.printStackTrace();
}
}
public ArrayList<Integer> getBucket() {
return getBucket;
}
private ArrayList<Integer> add(int p, Color getColor, ArrayList<Integer> bucket) {
pixel[p].setColor(getColor);
pixel[p].setToolTipText(pixel(p));
bucket.add(p);
return bucket;
}
private void move(Color getColor, ArrayList<Integer> bucket) {
ArrayList<Integer> pix = new ArrayList<Integer>();
for (int p : getPixels) {
for (int m : move(p)) {
if (!bucket.contains(m)) {
if (pixel[m].getColor().equals(groupColor)) {
bucket = add(m, getColor, bucket);
pix.add(m);
}
}
}
}
getPixels = pix;
}
private int[] move(int p) {
int[] move = {p+1, p-1, p+pixels, p-pixels};
boolean[] location = pixelLocations(p);
if (location[0])
move = move(move, new int[] {0, 2});
else if (location[1])
move = move(move, new int[] {1, 2});
else if (location[2])
move = move(move, new int[] {0, 3});
else if (location[3])
move = move(move, new int[] {1, 3});
else if (location[4])
move = move(move, new int[] {0, 2, 3});
else if (location[5])
move = move(move, new int[] {1, 2, 3});
else if (location[6])
move = move(move, new int[] {0, 1, 2});
else if (location[7])
move = move(move, new int[] {0, 1, 3});
return move;
}
private int[] move(int[] move, int[] newMove) {
int[] m = new int[newMove.length];
for (int i = 0; i < m.length; i++)
m[i] = move[newMove[i]];
return m;
}
}