At##Use Arrays
At a glance, your creating and instantiating the ButtonTemplate objects could be done as an array.
e.g.
private ButtonTemplate[] buttons = new ButtonTemplate[10];
It would allow you to use a simple loop to instantiate, and add the ActionListener, e.g.
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new ButtonTemplate(Integer.toString(i));
buttons[i].addActionListener(this);
}
If##Employ Lambda Expressions If you have access to Java 8, You can use lambda expressions to simply the code where you use Functional Interfaces, e.g.
instead of:
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ButtonTemplate source1 = (ButtonTemplate) e.getSource();
if (source1 == btn) {
operatorListener.OperatorEmitter(btn.getText());
}
}
});
You can simply write:
btn.addActionListener(e -> {
if ((ButtonTemplate)e.getSource() == btn) {
operatorListener.OperatorEmitter(btn.getText());
}
});
I also use e.getSource() directly here rather than storing it as a variable since we're only doing one thing with it anyway, but feel free to use it your way if you find it makes it more understandable/readable.
Read up on what I linked, but just as an additional example, your MathOperatorListener is a functional interface. So this section where you call setOperatorListener
formpanel.setOperatorListener(new MathOperatorListener() {
public void OperatorEmitter(String text2a) {
Can be replaced with:
formpanel.setOperatorListener(e -> {
// content
});
The e is just a variable used to refer to the text2a that is passed. You can name it anything. Same deal of course for your DigitListener interface. You may start using the @FunctionalInterface annotation so the compiler would check and confirm for you, albeit Functional Interfaces are easily identifiable since they only have a single method).