在我的程序中,在尝试获取拖放对象上的拖动数据时,程序在包含所有 StepPanel 的面板中创建新的 StepPanel 时变慢。我跟踪了代码,发现使程序变慢的是方法 getTransferData(DataFlavour df)。我在 Internet 上搜索了该问题,然后找到了 Oracle 提供的解决方案。解决方案页面说:
问题:当 Java 应用程序使用 Transferable.getTransferData() 进行 DnD 操作时,拖动似乎需要很长时间。为了只在需要时初始化传输的数据,初始化代码放在 Transferable.getTransferData() 中。
可传输数据的生成成本很高,并且在 DnD 操作期间,Transferable.getTransferData() 被多次调用,导致速度变慢。
解决方案:缓存Transferable数据,使其只生成一次。
但我找不到如何缓存可传输数据。有谁曾经为这个问题而苦苦挣扎过?我真的需要防止程序在这个问题上变慢。如果除了缓存可传输数据之外还有其他解决方案,我将不胜感激。谢谢你。
还有 StepPanel 代码:
public class StepPanel extends JPanel implements Transferable, DragSourceListener, DragGestureListener, DropTargetListener{
private DragSource source;
private TransferHandler transfer;
private DropTarget dropTarget;
StepContainer statementStep;
StepContainerPanel mainPanel;
JButton add;
JButton maximize;
JButton remove;
JTextArea stepCommand;
ImageIcon removeIcon;
ImageIcon maximizeIcon;
ImageIcon addIcon;
JPanel eastPanel;
public StepPanel( StepContainer step) /*throws MalformedURLException*/ {
setLayout( new BorderLayout());
setBackground(Color.WHITE);
statementStep = step;
removeIcon = new ImageIcon( "src/jlfgr-1_0/toolbarButtonGraphics/general/Delete24.gif");
maximizeIcon = new ImageIcon( "src/jlfgr-1_0/toolbarButtonGraphics/general/ZoomIn24.gif");
addIcon = new ImageIcon( "src/jlfgr-1_0/toolbarButtonGraphics/general/Add24.gif");
eastPanel = new JPanel();
add = new JButton( addIcon);
maximize = new JButton( maximizeIcon);
remove = new JButton( removeIcon);
stepCommand = new JTextArea();
stepCommand.setPreferredSize( new Dimension( StepContainer.WIDHT, StepContainer.HEIGHT));
stepCommand.setBorder( BorderFactory.createLineBorder( Color.BLACK));
add.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
statementStep.addSubStep();
((StepContainerPanel)getParent().getParent().getParent().getParent().getParent()).updateView();
}
});
maximize.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
((StepContainerPanel)getParent().getParent().getParent().getParent().getParent()).setStepContainer( statementStep);
((StepContainerPanel)getParent().getParent().getParent().getParent().getParent()).updateView();
}
});
remove.addActionListener( new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
statementStep.removeMe();
((StepContainerPanel)getParent().getParent().getParent().getParent().getParent()).updateView();
}
});
//Setting tool tips to the buttons
maximize.setToolTipText( "Click this button to maximize");
remove.setToolTipText( "Remove this step");
add.setToolTipText( "Add a sub-step");
//East Panel
eastPanel.setLayout( new GridLayout());
eastPanel.add( add);
eastPanel.add( remove);
eastPanel.setBackground( getBackground());
//StepPanel
add( maximize, BorderLayout.WEST);
add( eastPanel, BorderLayout.EAST);
add( stepCommand, BorderLayout.CENTER);
//The Properties for Drag and Drop
//setting transferhandler to the panel
transfer = new TransferHandler() {
@Override
public Transferable createTransferable( JComponent c) {
return new StepPanel( statementStep);
}
};
setTransferHandler( transfer);
source = new DragSource();
source.createDefaultDragGestureRecognizer( this, DnDConstants.ACTION_COPY_OR_MOVE, this);
//setting drop data
dropTarget = new DropTarget( this, this);
}
@Override
public void paintComponent( Graphics g) {
super.paintComponent( g);
setBorder( BorderFactory.createTitledBorder(statementStep.getBorderText()));
setToolTipText( statementStep.getBorderText());
}
public JButton getRemove() {
return remove;
}
public StepContainer getStep() {
return statementStep;
}
@Override
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[]{ new DataFlavor( StepPanel.class, "Step")};
}
@Override
public boolean isDataFlavorSupported( DataFlavor df) {
return true;
}
//when this method is called it returns this object
@Override
public Object getTransferData( DataFlavor df) throws UnsupportedFlavorException, IOException {
return this;
}
@Override
public void dragEnter(DragSourceDragEvent dsde) {}
@Override
public void dragOver(DragSourceDragEvent dsde) {}
@Override
public void dropActionChanged(DragSourceDragEvent dsde) {}
@Override
public void dragExit(DragSourceEvent dse) {}
@Override
public void dragDropEnd(DragSourceDropEvent dsde) {}
@Override
public void dragGestureRecognized(DragGestureEvent dge) {
source.startDrag( dge, DragSource.DefaultMoveDrop, this, this);
}
@Override
public void dragEnter(DropTargetDragEvent dtde) {}
@Override
public void dragOver(DropTargetDragEvent dtde) {}
@Override
public void dropActionChanged(DropTargetDragEvent dtde) {}
@Override
public void dragExit(DropTargetEvent dte) {}
@Override
public void drop(DropTargetDropEvent dtde) {
//getting the dragged step from dataFlavor and synchroning it if this
//step has same parent with dropped step then change their order
//getting and initalizing dragged step
Transferable transferedPanel = dtde.getTransferable();
DataFlavor[] datas = transferedPanel.getTransferDataFlavors();
try {
//its dragged panel, which is in the 0th index of DataFlavor array
StepPanel draggedPanel = ((StepPanel)transferedPanel.getTransferData( datas[0]));
//since the dragged step will come as if it is different object
//we cannot compare their parents directly since it will give
//wrong comparison. So we look order of parent step of both dragged
//and dropped step
if( statementStep.getParent().getBorderText().equals( draggedPanel.getStep().getParent().getBorderText())) {
StepContainer sameParent = statementStep.getParent();
int indexOfFirstSubStep = statementStep.getParent().getSubSteps().indexOf( statementStep);
int indexOfSecondSubStep = draggedPanel.getStep().getParent().getSubSteps().indexOf( draggedPanel.getStep());
System.out.println( "We ");
sameParent.changeOrders( indexOfFirstSubStep, indexOfSecondSubStep);
}
else {
System.out.println( "We cannot change those steps' orders since their parents are different");
}
} catch (UnsupportedFlavorException ex) {
Logger.getLogger(StepPanel.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(StepPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
}