Java JPanel 设置位置
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19083355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPanel setLocation
提问by JeremyF
Where it says: usePanel.setLocation(800,usePanel.getY()); it doesn't set the location it just starts in the middle, but inside the for loop where it gradually changes the position for a cool animation, it works fine.
它说: usePanel.setLocation(800,usePanel.getY()); 它没有设置它刚从中间开始的位置,而是在 for 循环内逐渐改变一个很酷的动画的位置,它工作正常。
Any idea why the first set location to get it started isn't working? This is under FlowLayout btw so I assume that may have something to do with it but am not sure.
知道为什么开始它的第一个设置位置不起作用吗?这是在 FlowLayout btw 下,所以我认为这可能与它有关,但我不确定。
usePanel.setLocation(800,usePanel.getY());
for(int x=0;x<3500;x+=6){
usePanel.setLocation(usePanel.getX()-5,usePanel.getY());
Thread.sleep(500);
}
Updated with current code
使用当前代码更新
private Timer nextloc;
private JPanel usePanel;
private static ClosePanel cp = new ClosePanel("null");
public void run(){
Timer andgo = new Timer(10,new TimerListener());
while(!cp.getCloseDone()){
andgo.start();
andgo.restart();
}
if(panel.equals("topiccreator")){
usePanel=topiccreator;
}else{
System.out.println("NULL PANEL TO MOVE!");
usePanel=mainmenu;
}
//This is what is not working
usePanel.setLocation(usePanel.getX()+800,usePanel.getY());
usePanel.setVisible(true);
nextloc = new Timer(50,new TimerListener());
for(int r=0;r<3500;r+=6){
nextloc.start();
nextloc.restart();
}
}
private class TimerListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource()==nextloc){
usePanel.setLocation(usePanel.getX()-5,usePanel.getY());
}
}
}
回答by mentallurg
Why you think it is not working? Probably you cannot just notice it. After your first setPosition()
add following code:
为什么你认为它不起作用?可能你不能只是注意到它。第一次setPosition()
添加以下代码后:
Thread.sleep(3000);
Then you will notice it.
然后你会注意到它。
回答by MadProgrammer
By calling Thread.sleep
, you are likely blocking the Event Dispatching Thread, which is responsible for, amongst other things, processing paint requests. This means until your loop actually finishes, the EDT won't be able to process the updated location of your panel.
通过调用Thread.sleep
,您可能会阻塞事件调度线程,该线程负责处理绘制请求等。这意味着在您的循环实际完成之前,EDT 将无法处理面板的更新位置。
Instead, use a javax.swing.Timer
...
相反,使用javax.swing.Timer
...
Check out Concurrency in Swingfor more details
查看Swing 中的并发以获取更多详细信息
Updated
更新
This is under FlowLayout btw so I assume that may have something to do with it but am not sure
这是在 FlowLayout btw 下,所以我认为这可能与它有关,但我不确定
You are fighting the layout manager, you will find that once you revalidate
the container that usePanel
is using, it will reposition back to where the layout manager wants the component to be.
您正在与布局管理器进行斗争,您会发现一旦您使用revalidate
了usePanel
正在使用的容器,它将重新定位回布局管理器希望组件所在的位置。
Try taking a look at Sliding-Layoutfor an better solution
尝试查看滑动布局以获得更好的解决方案
Updated with a basic example
更新了一个基本示例
Animation is the illusion of change over time. Swing places some rather strict requirements on developers when it comes to updating the UI.
动画是随时间变化的幻觉。在更新 UI 时,Swing 对开发人员提出了一些相当严格的要求。
Apart from things like layout managers, Swing requires that all interactions and modifications to the UI be done within the context of the Event Dispatching Thread. It also requires that any long running or block process be executed in another thread other than the EDT.
除了布局管理器之类的东西,Swing 要求对 UI 的所有交互和修改都在事件调度线程的上下文中完成。它还要求在除 EDT 之外的另一个线程中执行任何长时间运行或阻塞的进程。
This places us in a catch 22. We need to run in the background so we don't stop the EDT from processing paint requests (amongst other things), but we need to update our components from within the context of the EDT...
这使我们陷入困境 22。我们需要在后台运行,这样我们就不会阻止 EDT 处理绘制请求(除其他外),但我们需要从 EDT 的上下文中更新我们的组件......
Lucky for us, there are a number of solutions available. The simplest to your problem would be the use of a javax.swing.Timer
幸运的是,有许多解决方案可用。您的问题最简单的是使用javax.swing.Timer
This example uses the glass pane capabilities of the root pane to provide an overlying slide out, see How to use Root Panesfor more details.
此示例使用根窗格的玻璃窗格功能提供叠加的滑出,有关更多详细信息,请参阅如何使用根窗格。
It also uses a variable timed animation. That is, the position of the panel is based on the progression of time through the animation rather than some fixed delta
它还使用可变定时动画。也就是说,面板的位置基于动画中的时间进程,而不是一些固定的增量
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class SlidingPane {
private SlidePane slidePane = new SlidePane();
public static void main(String[] args) {
new SlidingPane();
}
public SlidingPane() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JButton slideButton = new JButton("Slide");
slideButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
slidePane.slide();
}
});
JFrame frame = new JFrame("Testing");
JPanel glassPane = new JPanel(null);
glassPane.setOpaque(false);
glassPane.add(slidePane);
frame.setGlassPane(glassPane);
glassPane.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
frame.add(new JLabel("Look ma, no hands!"), gbc);
frame.add(slideButton, gbc);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SlidePane extends JPanel {
private long startTime = -1;
private int runTime = 1000;
private int startX;
private int targetX;
private boolean slideIn = false;
private Timer slideTimer;
public SlidePane() {
setBackground(Color.DARK_GRAY);
setBorder(new LineBorder(Color.BLACK));
setLocation(-getPreferredSize().width, 0);
setLayout(new GridBagLayout());
JLabel label = new JLabel("I'm your overload");
label.setForeground(Color.WHITE);
add(label);
slideTimer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
long diff = System.currentTimeMillis() - startTime;
double progress = (double)diff / (double)runTime;
if (progress >= 1d) {
progress = 1d;
slideTimer.stop();
startTime = -1;
}
Container parent = getParent();
int height = parent.getHeight();
setSize(getPreferredSize().width, height);
int x = calculateProgress(startX, targetX, progress);
setLocation(x, 0);
revalidate();
repaint();
}
});
}
protected int calculateProgress(int startValue, int endValue, double fraction) {
int value = 0;
int distance = endValue - startValue;
value = (int) Math.round((double) distance * fraction);
value += startValue;
return value;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 400);
}
public void slide() {
slideTimer.stop();
startTime = System.currentTimeMillis();
slideIn = !slideIn;
startX = getX();
targetX = 0;
if (!slideIn) {
targetX = -getPreferredSize().width;
}
slideTimer.start();
}
}
}