gpt4 book ai didi

java - 在 Swing 中使用线程的困难

转载 作者:太空宇宙 更新时间:2023-11-04 07:19:03 25 4
gpt4 key购买 nike

package combatframe;

import javax.swing.*;
import java.awt.event.*;
import static java.lang.Math.PI;
import javax.swing.border.*;

public class CombatFrame extends JFrame
{
String[] Ships = {"Battleship", "Cruiser", "Frigate"};
JComboBox attackCombo = new JComboBox(Ships);
JComboBox targetCombo = new JComboBox(Ships);
JButton calculate = new JButton();
JPanel mainPanel = new JPanel();
JPanel outPanel = new JPanel();
JPanel shipPanel = new JPanel();
JTextArea outText = new JTextArea("Results: ", 11, 30);
JTextArea attackStats = new JTextArea("Attacker stats.", 10,10);
JTextArea targetStats = new JTextArea("Target stats.", 10,10);

public static void main(String[] args)
{
CombatFrame combatFrame = new CombatFrame();
}

public CombatFrame()
{
this.setSize(500,500);
this.setTitle("OTG Combat Simulator");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

EventListener c1 = new EventListener();
EventListener c2 = new EventListener();
EventListener calc = new EventListener();

calculate.setText("Calculate!");

Border b1 = BorderFactory.createTitledBorder("Result");
outPanel.setBorder(b1);
Border b2 = BorderFactory.createTitledBorder("Ship Classes");
shipPanel.setBorder(b2);

mainPanel.add(shipPanel);
mainPanel.add(outPanel);
shipPanel.add(attackStats);
shipPanel.add(attackCombo);
shipPanel.add(targetCombo);
shipPanel.add(targetStats);
outPanel.add(calculate);

outPanel.add(outText);

attackCombo.addActionListener(c1);
attackCombo.setSelectedItem("Battleship");
targetCombo.addActionListener(c2);
targetCombo.setSelectedItem("Battleship");

calculate.addActionListener(calc);

this.add(mainPanel);
this.setVisible(true);

}

public double hitProbability(double factor)
{
double hitCount = (double)(Math.random() * 1.001 * factor );
return hitCount;
}

public double Combat(double[] turnArray)
{
double rRange = turnArray[0];
double rAngular = turnArray[1];
double rRadius = turnArray[2];
double damage = turnArray[3];

double appliedDamage = 0;

int[] attHit =
{
0, 0, 0
};

int[] strikes =
{
0, 0, 0, 0, 0
};

double[] damageMod =
{
0,0.4,0.75,1.0,1.25
};

double roll1, roll2, roll3;

roll1 = hitProbability(rRadius);
roll2 = hitProbability(rAngular);
roll3 = hitProbability(rRange);

if (roll1 <=1)
attHit[0]++;
if (roll2 <=1)
attHit[1]++;
if (roll3 <=1)
attHit[2]++;

switch (attHit[0]+attHit[1]+attHit[2])
{
case 3:
double wrecker = Math.random();
if (wrecker >= 0.95 - Math.random())
strikes[4]++;
else
strikes[3]++;
break;
case 2:
strikes[2]++;
break;
case 1:
strikes[1]++;
break;
case 0:
strikes[0]++;
break;
}

for (int x=0; x<5; x++)
{
appliedDamage += strikes[x]*Damage*
(Math.random()+Math.random())*damageMod[x];
}


return appliedDamage;
}

private class EventListener implements ActionListener
{
@Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource()== attackCombo)
{
switch ((String)attackCombo.getSelectedItem())
{
case "Battleship":
Attacker attackBS = new Attacker(50000.0, 400.0, 0.01, 45000.0, 400.0,
300.0, 10.0, 10000.0, 250.0);
break;
case "Cruiser":
Attacker attackCr = new Attacker(25000.0, 125.0, 0.23, 22500.0, 150.0,
600.0, 5.0, 5000.0, 75.0);
break;
case "Frigate":
Attacker attackFr = new Attacker(2500.0, 40.0, 0.365, 1000.0, 39.0,
900.0, 2.0, 1200.0, 25.0);
break;

}
attackStats.setText("Optimal: " + Attacker.Optimal
+ "\n Weapon Sig: " +Attacker.Attack_Signature
+ "\n Tracking: " + Attacker.Tracking
+ "\n Range: " + Attacker.Range
+ "\n Ship Sig: " + Attacker.Target_Signature
+ "\n Velocity: " + Attacker.Orbital
+ "\n Cycle Time" + Attacker.Period
+ "\n Health: " + Attacker.Health
+ "\n Damage: " + Attacker.Damage);
}

if (e.getSource()==targetCombo)
{
switch ((String)targetCombo.getSelectedItem())
{
case "Battleship":
Target targetBS = new Target(50000.0, 400.0, 0.01, 45000.0, 400.0,
300.0, 10.0, 10000.0, 250.0);
break;
case "Cruiser":
Target targetCr = new Target(25000.0, 125.0, 0.23, 22500.0, 150.0,
600.0, 5.0, 5000.0, 75.0);
break;
case "Frigate":
Target targetFr = new Target(2500.0, 40.0, 0.365, 1000.0, 39.0,
900.0, 2.0, 1200.0, 25.0);
break;
}
targetStats.setText("Optimal: " + Target.Optimal
+ "\n Weapon Sig: " + Target.Attack_Signature
+ "\n Tracking: " + Target.Tracking
+ "\n Range: " + Target.Range
+ "\n Ship Sig: " + Target.Target_Signature
+ "\n Velocity: " + Target.Orbital
+ "\n Cycle Time" + Target.Period
+ "\n Health: " + Target.Health
+ "\n Damage: " + Target.Damage);

}

if (e.getSource()==calculate)
{

double[] attackArray =
{//RRange,RAngular,RRadius,Attacker.Damage
0,0,0,0
};

double[] targetArray =
{//RRange,RAngular,RRadius,Target.Damage
0,0,0,0
};

double attackDamage = 0, targetDamage = 0;

for (int i=1; i<1000; i++)
{
if ((i+1)%Attacker.Period==0)
{
double rRange = Attacker.Optimal/Target.Range;
double rAngular =
((Math.sin(PI/4)*(Target.Orbital/Target.Range))
/Attacker.Tracking);
double rRadius = Attacker.Attack_Signature/
Target.Target_Signature;

attackArray[0] = rRange;
attackArray[1] = rAngular;
attackArray[2] = rRadius;
attackArray[3] = Attacker.Damage;

attackDamage += Combat(attackArray);
if (attackDamage >= Target.Health)
{
outText.setText("Attacker wins!");
break;
}
}


if (i%Target.Period==0)
{
double rRange = Target.Optimal/Attacker.Range;
double rAngular =
((Math.sin(PI/4)*(Attacker.Orbital/Attacker.Range))
/Target.Tracking);
double rRadius = Target.Attack_Signature/
Attacker.Target_Signature;

targetArray[0] = rRange;
targetArray[1] = rAngular;
targetArray[2] = rRadius;
targetArray[3] = Target.Damage;

targetDamage += Combat(targetArray);

if (targetDamage >= Attacker.Health)
{
outText.setText("Target wins!");
break;
}
}
}
}
}
}
}

我正在尝试构建一个非常简单的战斗模拟框架。它构建 2 个组合框并根据其中的选择分配统计数据。

然后用户点击计算按钮,并将结果弹出到“结果”字段中。一切都很好。

我希望 GUI 将战斗的每个“回合”附加到结果文本字段 outText 中 - 我认为我可以很容易地做到这一点。我希望它在任何有战斗的回合中都稍微延迟 - 我会在每个 if 语句中使用 Thread.sleep(10) 来为每艘船执行 Activity 回合。

唯一的问题是我无法弄清楚如何将 GUI 保持在一个线程上 - 单击按钮后战斗计算提示时该线程会更新 - 以及处理所有延迟计算的线程。

我知道如果我尝试在同一个线程上运行两者,GUI 将简单地卡住,以适当的延迟进行所有计算,然后立即将整个附加 block 扔到结果字段中。

有人可以给我任何指示、建议或氰化物吗?任何事情,任何能让痛苦消失的事情......

怀疑 SwingWorker 是个好主意,但仍然无法弄清楚如何在我的代码中实际实现它。

澄清:我最担心的是我无法弄清楚如何实现 SwingWorker 或一些类似的多线程进程,以便并行运行 GUI 和后台计算。

最佳答案

我会尝试一下,因为我想我明白你想要做什么。也许您正在寻找的是每次单击按钮时创建一个新的可运行对象:

class Turn implements Runnable {

private final Object source;
private final String attackComboMove;
private final String targetComboMove;

public Turn(Object src, String acm, String tcm) {

source = src;
attackComboMove = acm;
targetComboMove = tcm;

}

@Override public void run() {

// may want to disable GUI buttons here

if (source == attackCombo) {

switch (attackComboMove) {
// ...
// ...
// ...
}

append("attack combo results");

} else if (source == targetCombo) {

switch (targetComboMove) {
// ...
// ...
// ...
}

append("target combo results");

} else if (source == calculate) {

// ...

for (int i = 1; i < 1000; i++) {

// ...

attackDamage += combat(attackArray);

append("combat results: " + attackDamage + " total damage");

if (attackDamage >= target.health) {
append("Attacker wins!");
break;
}
}
}

// and enable the buttons again when combat is over

}

private void append(String text) {

SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
outTextArea.append("\n" + text);
}
});

try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
}

听起来你只是想要一个攻击发生时的滚动列表,这就是它为你做的。在我看来,这是正确的方法,而且最终也是最简单的。

当用户单击您执行的按钮时:

new Thread(new Turn(e.getSource(), (String)attackCombo.getSelectedItem(), (String)targetCombo.getSelectedItem())).start();

(或者,如果您需要能够因某种原因提前结束它或更改参数,则为新线程创建一个变量。)

如果 SwingWorker 需要长时间运行,则此模式可以轻松适应 SwingWorker,只需扩展 SwingWorker 并执行相同的操作,但重写 doInBackground() 而不是 run()

否则,如果您打算进行实时模拟并需要后台线程,则需要将 run/doInBackground 设为 while(running) 循环,并在需要更改参数或计算回合时使用标志和/或某种等待/通知方案。

关于java - 在 Swing 中使用线程的困难,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19572372/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com