【发布时间】:2014-05-23 08:51:59
【问题描述】:
我的目标是显示一个对象的多个视图。对于每个视图,我创建一个线程。另外,我有一个控制这些视图的类,例如发送命令以对齐它们。但是,我并不总是得到正确的对齐。所以有一个数据竞赛,我无法理解我做错了什么。
这里有一段代码显示了我遇到的问题。它有一个简单的想法:创建一个主视图窗口,然后将第二个相同大小的窗口靠近其右边框对齐。
首先,我有一个抽象类来创建线程:
public abstract class ViewWindow implements Runnable{
private Thread thread;
private boolean terminate = false ;
private Controller controller;
private UpdateTask currentUpdateTask = null;
private class UpdateTask {
boolean alignWindows = true;
}
public ViewWindow(Controller controller, String title) {
this.title = title;
this.controller = controller;
}
public void startThread() {
thread = new Thread(this);
thread.start();
}
@Override
public void run() {
UpdateTask updateTask = null;
synchronized (thread) {
while (terminate == false) {
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
updateTask = currentUpdateTask;
currentUpdateTask = null;
if(updateTask.alignWindows) {
controller.getLock().lock();
setLocationRelativeTo(controller.getMainWindow());
controller.getLock().unlock();
}
}
}
}
public void alignWindowsUsingThread() {
synchronized (thread) {
currentUpdateTask = new UpdateTask();
thread.notify();
}
}
public abstract void setLocationRelativeTo(ImageViewWindow imageWindow);
}
然后我扩展它来为窗口视图创建一个抽象:
public abstract class ImageViewWindow extends ViewWindow {
private JFrame frame;
public ImageViewWindow(Controller controller, String title) {
super(controller, title);
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel(title);
frame.getContentPane().add(label, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(300,500));
frame.pack();
frame.setVisible(true);
}
public JFrame getFrame() {
return frame;
}
synchronized public void setLocation(int x, int y) {
frame.setLocation(x, y);
}
synchronized public Point getLocation() {
return frame.getLocation();
}
}
最后,我重写了一个函数来设置每个窗口的相对位置:
public class FirstWindow extends ImageViewWindow {
public FirstWindow(Controller controller, String title) {
super(controller, title);
this.setLocation(50, 50);
this.startThread();
}
@Override
public void setLocationRelativeTo(ImageViewWindow imageWindow) { }
}
public class SecondWindow extends ImageViewWindow {
public SecondWindow(Controller controller, String title) {
super(controller, title);
this.startThread();
}
@Override
public void setLocationRelativeTo(ImageViewWindow imageWindow) {
Point location = imageWindow.getLocation();
int xOffSet = imageWindow.getFrame().getWidth();
int yOffSet = 0;
this.setLocation(xOffSet + location.x, yOffSet + location.y);
}
}
这里有一个类负责控制:
public class Controller {
private Lock controlLock;
private List<ImageViewWindow> windows = new ArrayList<ImageViewWindow>();
private ImageViewWindow mainWindow;
public Controller() {
controlLock = new ReentrantLock();
}
public ImageViewWindow getMainWindow() {
return mainWindow;
}
public Lock getLock() {
return controlLock;
}
public void addMainWindow(ImageViewWindow mainViewWindow) {
this.mainWindow = mainViewWindow;
this.addWindow(mainViewWindow);
}
public void addWindow(ImageViewWindow imageWindow) {
windows.add(imageWindow);
}
public void updateWindowPositions() {
for(ImageViewWindow window : windows) {
window.alignWindowsUsingThread();
}
}
}
然后运行一切:
public class Start {
public static void main(String[] args) {
Controller controller = new Controller();
ImageViewWindow window1 = new FirstWindow(controller, "FirstWindow");
controller.addMainWindow(window1);
ImageViewWindow window2 = new SecondWindow(controller, "SecondWindow");
controller.addWindow(window2);
controller.updateWindowPositions();
}
}
UPD:我根据下面的答案更新了代码,但问题仍然存在!
【问题讨论】:
-
猜想:由于每个线程根据另一个视图 (B) 的位置对齐一个视图 (A),因此视图 B 可能在视图 A 之后对齐。这可能导致一个错误对齐的 B。
-
嗯...但是我用来对齐其他视图的视图有一个预定义的位置,它不会改变。我在启动它的线程之前设置了它的值。所以我不确定是不是这个原因。
标签: java multithreading user-interface