gpt4 book ai didi

java - Swing drop 回调期间是否禁止更改组件层次结构?

转载 作者:行者123 更新时间:2023-12-02 11:58:46 26 4
gpt4 key购买 nike

我注意到如果我这样做removeAll() , add() , revalidate()处理掉落时 DropTargetListener.drop() ,放置将成功并且更改将生效,但我将无法开始第二次拖动。任何后续的拖动尝试都会抛出 java.awt.dnd.InvalidDnDOperationException: Drag and drop in progress

似乎如果对层次结构进行更改,拖动将不会被清除,并且 Swing 认为仍有一个正在进行的拖动等待完成。即使在调用 DropTargetDropEvent.acceptDrop() 之后层次结构发生更改,也会发生这种情况和DropTargetDropEvent.dropComplete()

import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.dnd.*;
import javax.activation.*;
import java.awt.datatransfer.*;
import java.util.TooManyListenersException;


class MyWidget extends JComponent {

MyWidget() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
updateState();
}

void updateState() {
Runnable runnable = new Runnable() {
@Override
public void run() {
// System.out.println("Hello World on " + Thread.currentThread());
removeAll();
add(newButton("aaa"));
add(newButton("bbb"));
revalidate();

}
};
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
} else {
SwingUtilities.invokeLater(runnable);
}

}

JButton newButton(String text) {
JButton theButton = new JButton(text);

DragSource ds = new DragSource();
DragGestureRecognizer dgr = ds.createDefaultDragGestureRecognizer(theButton, DnDConstants.ACTION_COPY, new DragGestureListener() {
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
Transferable transferable = new DataHandler("my text", "text/plain");
dge.startDrag(DragSource.DefaultCopyDrop, transferable);
}
});

DropTarget dt = new DropTarget();
dt.setComponent(theButton);
try {
dt.addDropTargetListener(new DropTargetAdapter() {
@Override
public void drop(DropTargetDropEvent dtde) {
System.out.println("drop accepted");
dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
dtde.dropComplete(true);
updateState();
}
});
} catch (TooManyListenersException e) {}
return theButton;
}

}

public class App
{
static void createGUI() {
JFrame frame = new JFrame();
frame.setTitle("my app");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyWidget(), BorderLayout.CENTER);
frame.setSize(500,500);
// frame.pack();
frame.setVisible(true);
}

public static void main( String[] args )
{
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
createGUI();
}
});
}
}

最佳答案

问题是在拖动尚未完成时组件层次结构发生了变化。调用 DropTargetDropEvent.dropComplete(true) 后,放置可能已完成,但拖动部分尚未完成。在当前 DropTargetListener.drop()(EDT 当前正在运行的内容)将控制返回到 EDT 主循环之后,拖动端有可能在 EDT 中运行的回调。

因此组件层次结构的更改必须延迟,以便在拖动操作完成后运行它们。

所以而不是

if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
} else {
SwingUtilities.invokeLater(runnable);
}

运行即可

SwingUtilities.invokeLater(runnable); // unconditionally 

这将安排该可运行对象在拖动后运行,因为 dropComplete() 已经在 EDT 事件队列中安排了一个事件来处理拖动完成。因此,invokeLater() 会将更改组件层次结构的代码放在将拖动标记为已完成的事件之后。

关于java - Swing drop 回调期间是否禁止更改组件层次结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47409561/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com