我试图在netbeans中创建一个基本的角色创建策划器,以尝试学习Java,如果我的问题有点愚蠢,请原谅我。
我创建了一个文本字段,每次更改相关统计信息时都需要使用公式进行更新。
在这个例子中,运气和魅力属性影响易货技能。因此,当我更改这些统计数据时,我需要再次运行公式以更新易货技能。
目前,公式是在创建对象时运行,而不是在更新其他统计信息时运行。
这是我目前的(相关)代码:
package AppPackage;
import javax.swing.JOptionPane;
public class StartGUI extends javax.swing.JFrame {
public StartGUI() {
initComponents();
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
BarterPts = new javax.swing.JTextField();
Chr = new javax.swing.JTextField();
ChrPlus = new javax.swing.JButton();
Luck = new javax.swing.JTextField();
BarterPts.setEditable(false);
BarterPts.setText("0");
BarterPts.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
BarterPtsActionPerformed(evt);
}
});
getContentPane().add(BarterPts, new org.netbeans.lib.awtextra.AbsoluteConstraints(470, 110, 30, -1));
int a = Integer.parseInt(Chr.getText()),l = Integer.parseInt(Luck.getText()),barter;
barter = (2 + (a*2) + (l/2) );
BarterPts.setText(String.valueOf(barter));
//plus button to add to the Charisma stat.
private void ChrPlusActionPerformed(java.awt.event.ActionEvent evt) {
int a = Integer.parseInt(Chr.getText()),i,l = Integer.parseInt(SLeft.getText());
if (a == 10) {
//print error
JOptionPane.showMessageDialog(null, "The Charisma value cannot exceed 10.", "Error", JOptionPane.ERROR_MESSAGE);
}
else if (l == 0) {
JOptionPane.showMessageDialog(null, "You have no special points remaining.", "Error", JOptionPane.ERROR_MESSAGE);
}
else{
l=--l;
SLeft.setText(String.valueOf(l));
i=++a;
Chr.setText(String.valueOf(i));
}
}
private void BarterPtsActionPerformed(java.awt.event.ActionEvent evt) {
}
下面有变量声明,但我没有包含它们。
答案 0 :(得分:1)
因此,从您的原始问题看,您希望基于按钮点击更新文本字段。
目前,您已将ActionListener注册到文本字段。相反,您的ActionListener应该注册到您的按钮。
git branch --no-merged
将监听器注册到按钮将强制按预期执行单击操作。
答案 1 :(得分:1)
作为一项学习练习,现在可能是了解Model-View-Controller的好时机。 Swing使用MVC的形式,更像是M-VC,其中视图和控制器更紧密地绑定,然后纯MVC实现可能拥有它。
这里的要点是,您希望将模型(数据和规则)与视图(/ controller)分开。视图/控制器成为您可以“操纵”模型的一种方式,但由于它是分开的,您可以更改模型及其工作方式,而无需更改视图
您应该学习的另一个原则是编程接口和实现的概念(对于一些初学者,请参阅Program to an Interface, Fool和Program to an interface, not an implementation)
基本上,这会进一步解耦代码,这意味着代码的某些部分不会对其他部分或其功能的状态做出假设,并允许您更改物理实现(规则)而无需更改整个代码代码来容纳它。
我可能做的第一件事是创建一个interface
,它描述了我希望任何人从我的角色表中获得的基本操作
public interface CharacterSheet {
public int getLuck();
public int getCharisma();
public int getBarter();
}
因为我特别偏执,我不明白为什么“每个人”都应该能够在他们想要的时候改变角色表,相反,我通过另一个界面来限制它。想一想,一旦生成角色,你就不能在以后的某个时候更改统计数据(比如在任务完成之后)然后你可能想要使用一些“经验”规则/算法来分发和更新统计数据,但是那是我;)
public interface MutableCharacterSheet extends CharacterSheet {
public void setLuck(int value);
public void setCharisma(int value);
public void addPropertyChangeListener(PropertyChangeListener listener);
public void removePropertyChangeListener(PropertyChangeListener listener);
}
好的,现在我们有了一种方法可以更新字符表。此interface
还包含Observer Pattern,可让您检测何时对字符表进行更改,以便您采取适当的操作。
现在,我们需要一个实现。通常,我可能会创建一个或多个abstract
实现,这些实现提供基本/通用功能,例如对PropertyChangeListener
的支持,但在这种情况下,我将坚持默认实现。 ..
public class DefaultCharacterSheet implements MutableCharacterSheet {
private PropertyChangeSupport propertyChangeSupport;
private int luck;
private int charisma;
private int barter;
public DefaultCharacterSheet() {
propertyChangeSupport = new PropertyChangeSupport(this);
}
@Override
public int getLuck() {
return luck;
}
@Override
public void setLuck(int value) {
if (luck != value) {
int old = luck;
this.luck = value;
propertyChangeSupport.firePropertyChange("luck", old, luck);
updateBarter();
}
}
@Override
public int getCharisma() {
return charisma;
}
@Override
public void setCharisma(int value) {
if (charisma != value) {
int old = charisma;
this.charisma = value;
propertyChangeSupport.firePropertyChange("charisma", old, charisma);
updateBarter();
}
}
protected void updateBarter() {
int luck = getLuck();
int charisma = getCharisma();
int old = barter;
// Or what ever formula you want to use
barter = (int) ((luck / 2d) * charisma);
propertyChangeSupport.firePropertyChange("barter", old, barter);
}
@Override
public int getBarter() {
return barter;
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
}
现在,这可能“看起来”很奇怪。我已经实现了MutableCharacterSheet
,但如果我不想让代码修改字符表会怎么样?这就是OO的魔力发挥作用的地方。
永远不应修改工作表的部分代码应该只支持CharacterSheet
接口,这意味着我可以传递DefaultCharacterSheet
的实例,但是他们只能看到并能够做什么接口CharacterSheet
允许他们这样做,Polymorphism baby!
现在,我们需要一些方法将它显示给用户并允许他们与之交互......
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
MutableCharacterSheet characterSheet = new DefaultCharacterSheet();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CharacterSheetPane(characterSheet));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class CharacterSheetPane extends JPanel {
private JSpinner luckField;
private JSpinner charismaField;
private JTextField barterField;
private MutableCharacterSheet characterSheet;
public CharacterSheetPane(MutableCharacterSheet sheet) {
this.characterSheet = sheet;
characterSheet.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("barter".equals(evt.getPropertyName())) {
int value = (int) evt.getNewValue();
barterField.setText(NumberFormat.getNumberInstance().format(value));
}
}
});
luckField = new JSpinner(new SpinnerNumberModel(0, 0, 10, 1));
charismaField = new JSpinner(new SpinnerNumberModel(0, 0, 10, 1));
barterField = new JTextField(5);
barterField.setEditable(false);
luckField.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
characterSheet.setLuck((int) luckField.getValue());
}
});
charismaField.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
characterSheet.setCharisma((int) charismaField.getValue());
}
});
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(2, 2, 2, 2);
gbc.anchor = GridBagConstraints.EAST;
add(new JLabel("Luck: "), gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx++;
add(luckField, gbc);
gbc.anchor = GridBagConstraints.EAST;
gbc.gridx = 0;
gbc.gridy++;
add(new JLabel("Charisma: "), gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx++;
add(charismaField, gbc);
gbc.anchor = GridBagConstraints.EAST;
gbc.gridx = 0;
gbc.gridy++;
add(new JLabel("Barter: "), gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx++;
add(barterField, gbc);
}
}
}
因此,随着运气和魅力字段的更改,我们更新模型,模型实习生更新barter
值,触发PropertyChangeEvent
,这样我们就可以更新易货字段
这可能看起来很多,但如果你能理解这些基本原则,那将需要很长的时间。
看看:
有关我在UI代码中完成的一些事情的更多信息。在您最早的说服力,我强烈建议您停止使用表单编辑器并开始手动编写UI。您将更好地了解布局管理器的工作方式和可以协同工作,创建复杂的UI,以及何时以及如何分离代码以降低复杂性和增加重复使用。这也有助于您了解表单编辑器何时有用以及何时不可用;)