线程中的实例化组件是';t在Java中重新绘制到JFrame中
我只有一门课像这样线程中的实例化组件是';t在Java中重新绘制到JFrame中,java,multithreading,components,jframe,paint,Java,Multithreading,Components,Jframe,Paint,我只有一门课像这样 public class BlockSpawner implements Runnable{ public static long timeToSpawn; private GtrisJFrame frame; public BlockSpawner(GtrisJFrame frame) { this.frame = frame; timeToSpawn = 2000; } public void run() { while(true)
public class BlockSpawner implements Runnable{
public static long timeToSpawn;
private GtrisJFrame frame;
public BlockSpawner(GtrisJFrame frame)
{
this.frame = frame;
timeToSpawn = 2000;
}
public void run()
{
while(true)
{
try
{
Thread.sleep(timeToSpawn);
}
catch(InterruptedException e)
{
//Unhandled exception
}
//After awake, instanciate 2 blocks
//get the position of the first one
int index = Block.getRandomStartPosition();
new Block(frame, index);
new Block(frame, index+1);
}
}
}
我在JFrame main类中引用了这个类,并像这样启动它的线程:
private void initBlockSpawner()
{
spawner = new BlockSpawner(this);
new Thread(spawner).start();
}
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GtrisJFrame().setVisible(true);
}
});
}
public void run()
{
while(true)
{
System.out.println("SPAWN");
int index = Block.getRandomStartPosition();
new Thread(new Block(frame, index)).start();
new Thread(new Block(frame, index+1)).start();
try
{
Thread.sleep(timeToSpawn);
}
catch(InterruptedException e)
{
//Unhandled exception
}
}
}
我从JFrame构造函数中调用这个initBlockSpawner()函数。Block类确实有点大,但简而言之,它实现了runnable,并在构造函数末尾调用其run()方法。run()方法只能使块以一定的速度下落。我曾尝试在JFrame构造函数中手动实例化新块,它们工作、重新绘制并掉落。但是,每当我想实例化来自其他线程的块时,它们似乎会下降(即,它的属性会更新每个循环),但它们不会在JFrame中绘制
作为补充信息,我使用的是NetBeans,由于应用程序入口点位于JFrame类上,因此主方法如下所示:
private void initBlockSpawner()
{
spawner = new BlockSpawner(this);
new Thread(spawner).start();
}
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GtrisJFrame().setVisible(true);
}
});
}
public void run()
{
while(true)
{
System.out.println("SPAWN");
int index = Block.getRandomStartPosition();
new Thread(new Block(frame, index)).start();
new Thread(new Block(frame, index+1)).start();
try
{
Thread.sleep(timeToSpawn);
}
catch(InterruptedException e)
{
//Unhandled exception
}
}
}
我对Java线程、awt事件和swing组件没有太多经验。但是我读到的一些东西让我觉得我的问题是只有一个线程可以控制swing组件,或者其他什么。。。有什么办法解决我的问题吗
提前谢谢
编辑:其他信息,每当我检查线程实例化多维数据集上的toString方法时,它们都会给我这个[,0,0,0x0],但当我在同一JFrame类中实例化它们时,它们会给我这个结果[,0,0328x552],并显示在框架上。此328x552值与getPreferredSize()返回的组件维度相同。。。我试图通过如下方式实例化它们,将它们强制到该维度:
new Block(this, index).setPreferredSize(new Dimension(328, 552));
但它不起作用,有人知道这个[,0,0328x552]值可能意味着什么吗
谢谢大家,我想我们快到了
编辑2:
我意识到组件的大小是x:0y:0,这是为什么?我将BlockSpawner的run()方法更改为如下内容:
private void initBlockSpawner()
{
spawner = new BlockSpawner(this);
new Thread(spawner).start();
}
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GtrisJFrame().setVisible(true);
}
});
}
public void run()
{
while(true)
{
System.out.println("SPAWN");
int index = Block.getRandomStartPosition();
new Thread(new Block(frame, index)).start();
new Thread(new Block(frame, index+1)).start();
try
{
Thread.sleep(timeToSpawn);
}
catch(InterruptedException e)
{
//Unhandled exception
}
}
}
第一次跑步时,一切顺利!即使这对块在JFrame上绘制并正确地落下,但是在Thread.sleep()之后,其余的块只是被实例化,但是它们的getSize()方法给了我x:0y:0;这是否仍然与一个调度程序线程问题有关?或者现在有些不同了?我觉得(尽管我无法从上面的代码中看出)您正试图从事件调度线程以外的线程向live JFrame(即屏幕上显示的组件,或“已实现”)添加组件。这违反了Swing线程模型,将给您带来无尽的问题
如果要从其他线程对Swing对象进行更改,可以将更改打包到可运行线程中,并使用EventQueue.invokeLater()或invokeAndWait()将其提交给调度线程
编辑:更多信息
另外一些评论(与您的问题没有直接关系,但仍然很重要):在构造函数中执行活动可能不是一个好主意。将JFrame子类化以向其添加组件也可能不是一个好主意。因此,在JFrame而不是JPanel中执行这些操作可能也不是最好的方法
依次考虑:
BlockAnimator animator = new BlockAnimator();
DispatchThread.invokeLater(
new Runnable(){
public void run(){
JPanel blockAnimationPanel = new JPanel();
Block block = new Block(...);
blockAnimationPanel.add(block);
JFrame mainFrame = new JFrame();
mainFrame.add(blockAnimationPanel);
animator.start(); // note that we probably should start the thread *after* the panel is realized - but we don't really have to.
}
}
public class BlockAnimator extends Thread{
private final List<Block> blocks = new CopyOnWriteArray<Block>(); // either this, or synchronize adds to the list
public void addBlock(Block block){
blocks.add(block);
}
public void run(){
while(true){ // either put in a cancel check boolean, or mark the thread as daemon!
DispatchThread.invokeAndWait(
new Runnable(){
public void run(){
for(Block block: blocks){
block.moveTo(....); // do whatever you have to do to move the block
}
}
}
); // I may have missed the brace/paren count on this, but you get the idea
spawnNewBlockObjects();
Thread.sleep(50);
}
}
}
BlockAnimator animator=new BlockAnimator();
DispatchThread.invokeLater(
新的Runnable(){
公开募捐{
JPanel blockAnimationPanel=新的JPanel();
块=新块(…);
blockAnimationPanel.add(块);
JFrame mainFrame=新JFrame();
mainFrame.add(blockAnimationPanel);
animator.start();//请注意,我们可能应该在面板实现后启动线程,但实际上不必这样做。
}
}
公共类BlockAnimator扩展线程{
private final List blocks=new CopyOnWriteArray();//此选项或同步添加到列表中
公共无效添加块(块){
块。添加(块);
}
公开募捐{
while(true){//输入取消检查布尔值,或者将线程标记为守护进程!
DispatchThread.invokeAndWait(
新的Runnable(){
公开募捐{
用于(块:块){
block.moveTo(…);//执行所有必须执行的操作来移动块
}
}
}
)我可能错过了这个机会,但你明白了
产卵对象();
睡眠(50);
}
}
}
上面的代码还没有检查过准确性等
理论上,你可以有一个单独的线程来生成新的块,但是上面的操作非常简单。如果你决定用一个后台线程来实现,就像我在上面展示的那样,你可以在块列表中使用一个简单的ArrayList,因为