Я работаю над проектом, который я начал из любопытства.Цель моего проекта - использовать Java для создания пакета ресурсов в Minecraft.В конце концов, я хотел добавить собственные песни в Minecraft.Поскольку я довольно новичок в Java и в настоящее время являюсь старшекурсником, я подумал, что это может быть хорошей идеей для изучения Java и изучения.В любом случае, я подумал, что попробую создать свою собственную программу рисования для создания изображения пакета.Вот проблема, с которой я сталкиваюсь сейчас:
В некоторых программах рисования я моделирую функцию инструмента-ведра.Я решил использовать многопоточность, потому что в зависимости от размера области, которую я хочу нарисовать, это может быть долгой задачей.В частности, у меня есть проблемы с перекрывающимися потоками.Раньше я никогда не занимался многопоточностью, но мне кажется, что я настолько близок к правильному пониманию.
Я пытался использовать классы SwingWorker и Thread.Я обнаружил, что они оба достигли одной и той же проблемы.Поэтому я решил избавиться от SwingWorker и использовать Thread, потому что его легче кодировать. Методы рисования paintImmediately (0, 0, getWidth (), getHeight ()) и repaint () очень важны для этой работы. Метод paintImmediately находится внутри pixel [p] .setColor.() метод внутри класса Pixel, который я написал, и я не думаю, что это важно знать для этого вопроса.Существует большая разница в реализации и не реализации метода repaint () - repaint устраняет графические проблемы, но заставляет каждый поток выполняться намного медленнее.Без метода перерисовки потоки идут намного быстрее, но они перекрываются.
Кстати, чтобы мне было легче отслеживать и отлаживать свою программу рисования, я пометил все классы, которые я написал закрытыми внутримой основной класс.Я планирую поместить классы в отдельные файлы 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
}
}
}
Bucket:
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;
}
}
Простое удаление методов перерисовки (и paintImmediately) вызывает очень очевидные последствия:
Удаление метода paintImmediately в классе Pixel (здесь не показано) приводит кне показывает перекрытие, но замедляет скорость выполнения каждого потока.
Метод paintImmediately показывает результаты мгновенно, но вы можете видеть, что некоторые пиксели имеют перекрывающиеся цвета из другого потока.
- Добавление метода перерисовки значительно замедляет скорость выполнения каждого потока, но также уменьшает визуальное перекрытие графики.
- Удаление метода перерисовки возвращает программу к проблемам с перекрытием.
Редактирование: Использование SwingWorker - я заметил, что SwingWorker выдает точно такую же проблему, которая была у меня, когда я использовалПоток класса
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;
}
}