【问题标题】:Windows alignment in SWING-based GUI基于 SWING 的 GUI 中的 Windows 对齐
【发布时间】: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


【解决方案1】:

您没有指定要如何“对齐”窗口,而是从您的代码中指定

public void setLocationRelativeTo(ImageViewWindow imageWindow) {
    Point location = imageWindow.getLocation();

    int xOffSet = this.getFrame().getWidth();
    int yOffSet = 0;

    this.setLocation(xOffSet + location.x, yOffSet + location.y);
}

我想您希望将this 放在imageWindow 的右侧。在这种情况下,您必须使用imageWindow.x + imageWindow.width 而不是imageWindow.x + this.width

| imageWindow | this
x ← width   → x ← width →
              ↳=imageWindow.x+imageWindow.width 

所以正确的方法是:

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);
}

顺便说一句,我不明白你为什么要做一个如此复杂甚至多线程的简单任务。多线程在这里没有任何好处,只是一个复杂的东西阻碍了对最简单事物的看法……

【讨论】:

  • 感谢您的回复!实际上,这是一个显示我遇到的问题的婴儿示例。对于当前的更新任务,我想传递更多信息。基本上,我想发送参数来重新渲染不同的视图,而主线程正在继续做一些计算。在我的原始代码中,“this”没有这个错误。而且它仅在大约 50% 的运行中仍能正常工作。此外,在我的真实代码中,我使用 ImageJ 中的“ImageWindow”(派生自“Frame”)类,并且在窗口位置获得了一个恒定的偏移量。即使我在没有任何额外的多线程的情况下这样做。
  • 这里解释了我的偏移量问题:stackoverflow.com/questions/23074312/… 但似乎没有解决方案......
猜你喜欢
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-25
相关资源
最近更新 更多