Я сделал пример, делая то, что я думаю, что вы хотите без макета карты, и используя поток. Я думаю, что это подтверждение концепции, что то, что вы просите, возможно. Ниже я приведу несколько вещей, которые я бы сделал, чтобы улучшить его.
import javax.swing.*;
import java.awt.*;
public class SwapCards{
Thread gameLoop;
volatile boolean running = false;
double x = 0;
double y = 0;
double theta = 0;
JFrame frame = new JFrame("swapped");
Canvas gamePanel = new Canvas(){
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLACK);
g.drawOval((int)x, (int)y, 25, 25);
}
};
Canvas nonGame = new Canvas(){
public void paint(Graphics g){
super.paint(g);
g.setColor(Color.BLUE);
g.fillRect(0,0,200, 200);
}
};
public void step(){
x = 100 + 50*Math.sin( theta );
y = 100 + 50*Math.cos( theta );
theta += 0.02;
if(theta > 6.28) theta = 0;
}
public void startGameLoop(){
frame.remove(nonGame);
frame.add(gamePanel, BorderLayout.CENTER);
frame.validate();
running = true;
gameLoop = new Thread(()->{
while(running){
step();
gamePanel.repaint();
try{
Thread.sleep(30);
}catch (Exception e){
running = false;
throw new RuntimeException(e);
}
}
});
gameLoop.start();
}
public void stopGameLoop(){
frame.remove(gamePanel);
frame.add(nonGame, BorderLayout.CENTER);
running = false;
try{
gameLoop.join();
} catch(Exception e){
throw new RuntimeException(e);
}
}
public void buildGui(){
JButton button = new JButton("action");
button.addActionListener( evt->{
if(!running){
startGameLoop();
} else{
stopGameLoop();
}
});
frame.add(nonGame, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
EventQueue.invokeLater( new SwapCards()::buildGui );
}
}
Прежде всего, Canvas несколько устарел, используйте JPane и переопределите paintComponent
. Это дает вам больше доступа к силе свинга.
В этом примере я выполняю тривиальную работу, поэтому нить абсолютно избыточна, я могу заменить ее на javax.swing.Timer
.
Timer timer = new Timer(30, evt->{
step();
gamePanel.repaint();
});
Затем в методах start и stop я просто вызываю timer.start()
или timer.stop()
соответственно.
Использование CardLayout делает немного более понятным, что вы хотите сделать, плюс в нем есть методы для навигации по картам. Например. Если у вас есть вырезанная сцена с серией компонентов, которые вы хотите показать, вы можете использовать cardLayout.next(parent)
.
. При создании макета:
cards = new CardLayout();
swap = new JPanel(cards);
swap.add(gamePanel, "game");
swap.add(nonGame, "nogame");
cards.last(swap);
frame.add(swap, BorderLayout.CENTER);
Это добавит карты к swap
и заставь его показать "nogame". Затем в методах start / stop мы просто переключаемся на соответствующую карту.
cards.show(swap, "game");