线程内的实例化组件不会重新绘制到Java中的JFrame中
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了线程内的实例化组件不会重新绘制到Java中的JFrame中,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5283字,纯文字阅读大概需要8分钟。
内容图文
![线程内的实例化组件不会重新绘制到Java中的JFrame中](/upload/InfoBanner/zyjiaocheng/729/a407bfb36ae54d7c94f7908f5d462437.jpg)
我有一个像这样的单一课程
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主类中实例化这个类,并像这样启动它的线程:
private void initBlockSpawner()
{
spawner = new BlockSpawner(this);
new Thread(spawner).start();
}
我在JFrame构造函数中调用此initBlockSpawner()函数. Block Class确实有点大,但简而言之,它实现了runnable,并在其构造函数的末尾调用了run()方法. run()方法只使块以特定速度下降.我已经尝试在JFrame构造函数中手动实例化新块,它们可以工作,它们会重新渲染并掉线.但每当我想从其他线程实例化块时,它们似乎都会掉落(即它的属性会更新每个循环),但它们不会在JFrame中绘制.
作为附加信息,我使用NetBeans,并且由于应用程序入口点在JFrame类上,因此main方法如下所示:
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new GtrisJFrame().setVisible(true);
}
});
}
我没有那么多Java Threads,awt事件和swing组件的经验.但是我读到here的东西让我觉得我的问题是只有一个线程可以控制摆动组件,或者其他东西……有什么方法可以解决我的问题吗?
提前致谢.
编辑:附加信息,每当我从线程检查实例化多维数据集上的方法toString时,他们给我这个[,0,0,0×0],但是当我在同一个JFrame类中实例化它们时,他们给我这个结果[,0, 0,328×552]并且它们出现在框架上.这个328×552的值与getPreferredSize()返回的组件的Dimension相同…我试图通过实例化它们来强制它们到这个维度:
new Block(this, index).setPreferredSize(new Dimension(328, 552));
但它没有用,有谁知道这个[,0,0,328×552]值是什么意思?
谢谢大家,我想我们差不多了!
编辑2:
我意识到组件的大小是x:0 y:0,为什么会这样?我将BlockSpawner的run()方法更改为如下所示:
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:0 y:0;这仍然与One Dispatcher Thread问题有某种关系吗?或者它现在有所不同?
解决方法:
听起来我(虽然我从上面的代码中无法分辨)你试图从活动发送以外的线程添加组件到实时JFrame(即已在屏幕上显示或“已实现”的组件)线.这违反了Swing线程模型,并且会导致问题无法解决.
如果要从其他线程更改Swing对象,可以将更改打包在Runnable中,并使用EventQueue.invokeLater()或invokeAndWait()将其提交到调度线程.
编辑:更多信息
一些额外的注释(与您的问题没有直接关系,但仍然很重要):在构造函数中执行活动可能不是一个好主意.对JFrame进行子类化以向其添加组件也可能不是一个好主意.就此而言,在JFrame而不是JPanel中执行这些操作可能也不是最好的方法.
反过来考虑这些:
>构造函数应该用于对对象执行初始配置 – 而不是调用行为.这种分离有助于保持您的设计清洁和可维护.虽然这样做似乎更容易,但我建议反对.在您的设计中的某个时刻,您可能会认为提前创建这些对象更有效,并且以后才能使用它们.
>对JFrame进行子类化以添加组件通常不是一个好主意.为什么?如果您决定要使用具有其他所需行为的专用JFrame,该怎么办?如果您决定使用为您提供JFrame的应用程序框架(这在框架可能希望跟踪窗口关闭事件以便它可以保存窗口大小和位置的情况下),该怎么办?无论如何 – 很多原因.将您的行为打包到非GUI相关类中,并使用它将行为注入JFrame(或JPanel).
>考虑使用JPanel而不是JFrame.如果需要,您始终可以将JPanel添加到JFrame.如果您直接使用JFrame,当您决定要在一个容器中并排使用其中两个面板时会发生什么?
所以,我建议你做更多的事情:
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);
}
}
}
上面的代码尚未检查准确性等…
理论上,你可以有一个单独的线程来产生新的块,但上面的内容非常简单.如果您决定使用我上面显示的单个后台线程来实现,则可以使用简单的ArrayList作为块列表,因为该对象上没有竞争条件.
关于这个的几个其他想法:
>在上文中,块动画师可以独立于块本身进行管理.例如,您可以添加一个暂停所有块的pause()方法.
>我在同一个调度线程调用中发生了所有块的动画更新.根据动画的成本,最好在后台线程上计算新坐标,并仅在EDT上发布实际位置更新.您可以选择为每个块更新发出单独的invokeAndWait(或可能使用invokeLater).这实际上取决于你正在做的事情的性质.
如果计算移动块的位置是粗糙的,请考虑将计算与实际移动分开.所以你有一个调用可以获得对象的新Point,然后是另一个实际上会进行移动的调用.
内容总结
以上是互联网集市为您收集整理的线程内的实例化组件不会重新绘制到Java中的JFrame中全部内容,希望文章能够帮你解决线程内的实例化组件不会重新绘制到Java中的JFrame中所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。