该程序基本上是拖放JPanel。我想实现长按以选择JPanel,并在少数教程中建议使用计时器。因此,我尝试使用计时器1000毫秒来选择一个JPanel,但它只在首选方式工作一次,但有一些闪烁的JPanel,我不明白为什么。它以后无法识别鼠标按下的功能。另一个问题是,当点击JPanel时,面板开始无意中被移除。实际上,当点击JPanel时没有任何事情发生,因为我没有为Clicked函数写任何内容。 请提供一些建议,以消除上述问题 提前谢谢。
package swappaneleg;
import java.awt.Color;
import java.awt.Component;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.TimerTask;
import javax.swing.*;
public class SwapPanelEg extends JPanel{
private static final long serialVersionUID = 1594039652438249918L;
private static final int PREF_W = 400;
private static final int PREF_H = 400;
private static final int MAX_COLUMN_PANELS = 8;
private JPanel columnPanelsHolder = new JPanel();
public SwapPanelEg(){
columnPanelsHolder.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
for (int i = 0; i < MAX_COLUMN_PANELS; i++) {
int number = i + 1;
int width = 20 + i * 3;
int height = PREF_H - 30;
columnPanelsHolder.add(new ColumnPanel(number, width, height));
}
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
columnPanelsHolder.addMouseListener(myMouseAdapter);
columnPanelsHolder.addMouseMotionListener(myMouseAdapter);
setLayout(new GridBagLayout());
add(columnPanelsHolder);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class MyMouseAdapter extends MouseAdapter {
private JComponent selectedPanel;
private Point deltaLocation;
private JPanel placeHolder = new JPanel();
private JComponent glassPane;
java.util.Timer t;
@Override
public void mousePressed(final MouseEvent evt) {
if (evt.getButton() != MouseEvent.BUTTON1) {
return;
}
if(t == null) {
t = new java.util.Timer();
}
t.schedule(new TimerTask() {
public void run() {
JPanel source = (JPanel) evt.getSource();
selectedPanel = (JComponent) source.getComponentAt(evt.getPoint());
if (selectedPanel == null) {
return;
}
if (selectedPanel == source) {
selectedPanel = null;
return;
}
glassPane = (JComponent) SwingUtilities.getRootPane(source).getGlassPane();
glassPane.setVisible(true);
Point glassPaneOnScreen = glassPane.getLocationOnScreen();
glassPane.setLayout(null);
Point ptOnScreen = evt.getLocationOnScreen();
Point panelLocOnScreen = selectedPanel.getLocationOnScreen();
int deltaX = ptOnScreen.x + glassPaneOnScreen.x - panelLocOnScreen.x;
int deltaY = ptOnScreen.y + glassPaneOnScreen.y - panelLocOnScreen.y;
deltaLocation = new Point(deltaX, deltaY);
Component[] allComps = source.getComponents();
for (Component component : allComps) {
if (component == selectedPanel) {
placeHolder.setPreferredSize(selectedPanel.getPreferredSize());
source.add(placeHolder);
selectedPanel.setSize(selectedPanel.getPreferredSize());
int x = ptOnScreen.x - deltaLocation.x;
int y = ptOnScreen.y - deltaLocation.y;
selectedPanel.setLocation(x, y);
glassPane.add(selectedPanel);
repaint();
}
else {
source.add(component);
repaint();
}
}
}
},1000,500);
revalidate();
repaint();
}
@Override
public void mouseDragged(MouseEvent evt) {
if (selectedPanel != null) {
Point ptOnScreen = evt.getLocationOnScreen();
int x = ptOnScreen.x - deltaLocation.x;
int y = ptOnScreen.y - deltaLocation.y;
selectedPanel.setLocation(x, y);
selectedPanel.setBorder(BorderFactory.createLineBorder(Color.black));
selectedPanel.setOpaque(false);
repaint();
if(t != null)
{
t.cancel();
t = null;
}
}
}
@Override
public void mouseReleased(MouseEvent evt) {
if (evt.getButton() != MouseEvent.BUTTON1) {
return;
}
if (selectedPanel == null) {
return;
}
JComponent source = (JComponent) evt.getSource();
Component[] allComps = source.getComponents();
JPanel overComponent = (JPanel) source.getComponentAt(evt
.getPoint());
if (overComponent != null && overComponent != placeHolder
&& overComponent != source) {
for (Component component : allComps) {
if (component == overComponent) {
source.add(overComponent);
source.add(selectedPanel);
source.remove(placeHolder);
selectedPanel.setOpaque(true);
selectedPanel.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0)));
}
else {
source.add(component);
source.remove(placeHolder);
selectedPanel.setOpaque(true);
selectedPanel.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0)));
}
}
}
else {
for (Component component : allComps) {
if (component == placeHolder) {
source.add(selectedPanel);
source.remove(placeHolder);
}
else {
source.remove(placeHolder);
source.add(component);
selectedPanel.setOpaque(true);
selectedPanel.setBorder(BorderFactory.createLineBorder(new Color(0,0,0,0)));
}
}
}
revalidate();
repaint();
selectedPanel = null;
if(t != null)
{
t.cancel();
t = null;
}
}
}
private static void createAndShowGui() {
SwapPanelEg mainPanel = new SwapPanelEg();
JFrame frame = new JFrame("SwapPanelEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ColumnPanel extends JPanel {
private static final long serialVersionUID = 5366233209639059032L;
private int number;
private int prefWidth;
private int prefHeight;
public ColumnPanel(int number, int prefWidth, int prefHeight) {
setName("ColumnPanel " + number);
this.number = number;
this.prefWidth = prefWidth;
this.prefHeight = prefHeight;
add(new JLabel(String.valueOf(number)));
setBackground(Color.cyan);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(prefWidth, prefHeight);
}
public int getNumber() {
return number;
}
}
答案 0 :(得分:2)
我认为更好的解决方案是:
SwingTimer
。 SwingTimer
结束时没有释放且鼠标没有离开面板,则处理您的任务。SwingTimer教程:http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
答案 1 :(得分:0)
建议的计时器代码:
private class InnerTimer implements Runnable {
public boolean expired;
public boolean cancelled;
private long end;
public void run() {
expired = cancelled = false;
end = System.currentTimeMillis() + 1000;
while ( ! cancelled && ! expired) {
if (System.currentTimeMillis() >= end) {
expired = true;
} else {
try { Thread.sleep(100); }
catch(InterruptedException e) {/* no big deal */}
}
}
}
}
在每个需要监听长按的面板中保留InnerTimer innerTimer = new InnerTimer();
。在此类面板上按下鼠标时,请在单独的线程中启动此计时器:(new Thread(innerTimer)).start()
。如果鼠标离开面板或被释放,请取消计时器:innerTimer.cancelled = true;
。如果移动鼠标,请检查计时器是否自然过期:if (innerTimer.expired)
;如果是,则用户已成功长按此面板。如果它没有过期,那么只需取消定时器。
请注意,此代码有点快速和肮脏。然而,它很短且相对有效(除了它创建线程,但这些大部分都是睡眠很多,并且在1s之后无论如何都被丢弃)。使用Swing Timers可以避免线程创建开销,但更加冗长。