Việc sử dụng luồng của bạn là sai đối với các ứng dụng Swing. Bạn không nên cố gắng thêm hoặc loại bỏ các thành phần trong một chủ đề nền mà thay vào đó nên sử dụng một Swing Timer để làm điều này trên thread sự kiện Swing.
Ngoài ra, những gì bạn có nghĩa là bởi:
Tôi muốn có một JLabel di chuyển ở dưới cùng của màn hình
Xin làm rõ hiệu quả mà bạn đang cố gắng để đạt được.
Cũng liên quan,
Tôi cũng hiểu rằng tôi sẽ hầu như không thể sử dụng FlowLayout cho điều này, như tôi hiểu nó không cho phép bạn thiết lập vị trí của các thành phần của bạn. Tôi đã thử sử dụng cách bố trí rỗng, nhưng với cách bố trí rỗng, nhãn JL trống rỗng có viền không xuất hiện. Tôi hầu như không thể làm nổi bật phần đầu của đường viền ở cạnh dưới của khung hình, nhưng ngay cả với setLocation tôi không thể làm cho nó xuất hiện ở nơi tôi muốn nó.
Không, không sử dụng bố cục trống cho trường hợp này. Có nhiều trình quản lý bố cục tốt hơn có thể giúp bạn xây dựng ứng dụng của mình theo cách độc lập hơn về nền tảng.
Sửa 3
Về:
Để làm rõ, ở dưới cùng của màn hình tôi muốn có một JLabel ở góc xa bên phải, sau đó trong timer swing, các JLabel sẽ dần dần di chuyển đến còn lại cho đến khi nó rời khỏi màn hình. Nếu tôi có thể đặt setLocation để làm việc, tiền đề cơ bản sẽ là có một biến x đặt thành 600, và sau đó mỗi lần giảm thứ hai x bằng cách nói 50 và sau đó vẽ lại JLabel tại vị trí mới trên màn hình. Hoạt ảnh cơ bản.
Tôi sẽ tạo JPanel ở cuối màn hình với mục đích giữ JLabel hoặc hiển thị hình ảnh mà không có JLabel bằng cách ghi đè phương pháp paintComponent(...)
của nó. Nếu bạn sử dụng nó như một thùng chứa, thì có, bố cục của nó phải là rỗng, nhưng phần còn lại của GUI không được sử dụng bố cục rỗng. The Swing Timer chỉ đơn giản là sẽ thay đổi vị trí của JLabel và sau đó gọi repaint()
trên JPanel/container của nó. Nếu bạn đi tuyến đường thứ hai, bạn sẽ vẽ hình ảnh theo phương pháp paintComponent(...)
của JPanel bằng cách sử dụng g.drawImage(myImage, x, y)
và bộ hẹn giờ của bạn sẽ thay đổi x và/hoặc y và gọi repaint()
trên bản vẽ JPanel.
Ngoài ra, bạn có thể không muốn tiếp tục thêm JLabel vào bộ hẹn giờ mà chỉ cần di chuyển nhãn JLabel đã được hiển thị trong GUI.
Ngoài ra, để tránh các vấn đề trọng tâm, không sử dụng KeyListener để nắm bắt đầu vào gõ phím mà thay vào đó sử dụng Khóa Ràng buộc. Google sẽ hướng dẫn bạn đến một hướng dẫn tuyệt vời về cấu trúc này.
Sửa 4
Ví dụ:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.EnumMap;
import javax.imageio.ImageIO;
import javax.swing.*;
@SuppressWarnings("serial")
public class AnimateExample extends JPanel {
public static final String DUKE_IMG_PATH =
"https://duke.kenai.com/iconSized/duke.gif";
private static final int PREF_W = 800;
private static final int PREF_H = 800;
private static final int TIMER_DELAY = 20;
private static final String KEY_DOWN = "key down";
private static final String KEY_RELEASE = "key release";
public static final int TRANSLATE_SCALE = 3;
private static final String BACKGROUND_STRING = "Use Arrow Keys to Move Image";
private static final Font BG_STRING_FONT = new Font(Font.SANS_SERIF,
Font.BOLD, 32);
private EnumMap<Direction, Boolean> dirMap =
new EnumMap<AnimateExample.Direction, Boolean>(Direction.class);
private BufferedImage image = null;
private int imgX = 0;
private int imgY = 0;
private int bgStringX;
private int bgStringY;
public AnimateExample() {
for (Direction dir : Direction.values()) {
dirMap.put(dir, Boolean.FALSE);
}
try {
URL imgUrl = new URL(DUKE_IMG_PATH);
image = ImageIO.read(imgUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
new Timer(TIMER_DELAY, new TimerListener()).start();
// here we set up our key bindings
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition);
ActionMap actionMap = getActionMap();
for (final Direction dir : Direction.values()) {
// for the key down key stroke
KeyStroke keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0,
false);
inputMap.put(keyStroke, dir.name() + KEY_DOWN);
actionMap.put(dir.name() + KEY_DOWN, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent arg0) {
dirMap.put(dir, true);
}
});
// for the key release key stroke
keyStroke = KeyStroke.getKeyStroke(dir.getKeyCode(), 0, true);
inputMap.put(keyStroke, dir.name() + KEY_RELEASE);
actionMap.put(dir.name() + KEY_RELEASE, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent arg0) {
dirMap.put(dir, false);
}
});
}
FontMetrics fontMetrics = getFontMetrics(BG_STRING_FONT);
int w = fontMetrics.stringWidth(BACKGROUND_STRING);
int h = fontMetrics.getHeight();
bgStringX = (PREF_W - w)/2;
bgStringY = (PREF_H - h)/2;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.setFont(BG_STRING_FONT);
g.setColor(Color.LIGHT_GRAY);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.drawString(BACKGROUND_STRING, bgStringX, bgStringY);
if (image != null) {
g.drawImage(image, imgX, imgY, this);
}
}
private class TimerListener implements ActionListener {
public void actionPerformed(java.awt.event.ActionEvent e) {
for (Direction dir : Direction.values()) {
if (dirMap.get(dir)) {
imgX += dir.getX() * TRANSLATE_SCALE;
imgY += dir.getY() * TRANSLATE_SCALE;
}
}
repaint();
};
}
enum Direction {
Up(KeyEvent.VK_UP, 0, -1), Down(KeyEvent.VK_DOWN, 0, 1), Left(
KeyEvent.VK_LEFT, -1, 0), Right(KeyEvent.VK_RIGHT, 1, 0);
private int keyCode;
private int x;
private int y;
private Direction(int keyCode, int x, int y) {
this.keyCode = keyCode;
this.x = x;
this.y = y;
}
public int getKeyCode() {
return keyCode;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
private static void createAndShowGui() {
AnimateExample mainPanel = new AnimateExample();
JFrame frame = new JFrame("Animate Example");
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();
}
});
}
}
Mà sẽ tạo GUI này:
+1. Và thiết lập vị trí trong khi sử dụng một LayoutManager không có hiệu lực. Nó là LayoutManager xác định vị trí – Robin
Tôi thực sự đã có bộ đếm thời gian trước đó, nhưng ai đó đã nói với tôi nó là tốt hơn để sử dụng ScheduledExecutorService.Đặt nó trở lại sử dụng bộ hẹn giờ Swing là không có vấn đề, tôi sẽ chỉnh sửa câu hỏi – awestover89
Nếu vẫn không hoạt động, sau đó tạo một chương trình đơn giản và có thể chạy được, thể hiện vấn đề của bạn và sử dụng hình ảnh trực tuyến có sẵn cho tất cả, [sscce] (http://sscce.org). –