I have a TextArea class in GWT that I have extended however none of my Event Handling methods seem to get called. I have defined my class like so :
private class MTextBox extends TextArea {
public MTextBox() {
super();
this.addDomHandler(new BlurHandler(){
#Override
public void onBlur(BlurEvent event) {
//Handle Blur
}
}, BlurEvent.getType());
this.addDomHandler(new FocusHandler(){
#Override
public void onFocus(FocusEvent event) {
// Handle Focus.
}
}, FocusEvent.getType());
}
Seems fine to me, the events are triggered correctly:
import com.google.gwt.core.shared.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.goulds.client.views.ApplicationEntryPoint;
/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class TestMTextBox extends ApplicationEntryPoint
{
private class MTextBox extends TextArea {
public MTextBox() {
super();
this.addDomHandler(new BlurHandler(){
#Override
public void onBlur(BlurEvent event) {
//Handle Blur
GWT.log("onBlur");
}
}, BlurEvent.getType());
this.addDomHandler(new FocusHandler(){
#Override
public void onFocus(FocusEvent event) {
// Handle Focus.
GWT.log("onFocus");
}
}, FocusEvent.getType());
}
}
#Override
public void onModuleLoad()
{
VerticalPanel verticalPanel = new VerticalPanel();
verticalPanel.add(new MTextBox());
verticalPanel.add(new MTextBox());
verticalPanel.add(new MTextBox());
RootPanel.get().add(verticalPanel);
}
}
Related
A Controller creates a new JFrame with a button. Using the actionListener is getting the order correctly but the action is asked to perform after is not working. Is asked to change a button name literal on the view but it never happens. Otherwise with debugging the function seems tu run but there is no change on the view.
With Java are implemented the following classes:
public class Window extends JFrame {
JButton bGoFile;
public static final String FILE = "FILE";
public Window(ActionListener actionListener) {
this.actionListener = actionListener;
setupButtons();
setupView();
}
private void setupButtons() {
bGoFile = new JButton("Button");
bGoFile.addActionListener(actionListener);
bGoFile.setActionCommand(GO_FILE);
}
private void setupView() {
setTitle("Cover pdf to img");
setBounds(300, 90, 900, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
ImageIcon icon = new ImageIcon("./src/resources/logo.jpg");
setIconImage(icon.getImage());
JPanel jp = new JPanel;
jp.add(bGoFile);
add(jp);
}
public void changeButtonName(String name) {
bGoFile.setText(name);
System.out.println("Name should be changed.");
// Here I already tried to user repaint() but with no result.
}
public class WindowController implements ActionListener {
Window window;
public WindowController() {
this.window = new Window(this);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Action performed");
switch (e.getActionCommand()) {
case GO_FILE -> {
synchronized (this) {
window.changeButtonName("New name");
break;
}
}
}
}
The point is that the both prints on terminal are shown but the button name on the running Window is not changing.
You shouldn't be creating an instance of the view in the controller. This should be passed to the controller (AKA using dependency injection).
You should also be making use of interfaces, as the controller should not be bound to an implementation of a view (or model), but should be working through an established series of contracts and observers.
So, let's start with some basics...
public interface View {
public JComponent getView();
}
public interface Controller<V extends View> {
public V getView();
}
I did say basic. But, working with these interfaces directly will become tedious really fast, so let's add some helpers...
public abstract class AbstractController<V extends View> implements Controller<V> {
private V view;
public AbstractController(V view) {
this.view = view;
}
#Override
public V getView() {
return view;
}
}
public abstract class AbstractView extends JPanel implements View {
#Override
public JComponent getView() {
return this;
}
}
Nothing special, but this takes care of the a lot of boiler plating.
Next, we want to define the contract of our view...
public interface MainView extends View {
public interface Observer {
public void didPerformGoFile(MainView view);
}
public void addObserver(Observer observer);
public void removeObserver(Observer observer);
public void setDescription(String description);
}
That's pretty simple. Note though, this does not describe any kind of implementation detail. The contract does not care how didPerformGoFile might be generated, only that the action can be observed by interested parties
Next, we want to define or implementations for the MainView...
public class DefaultMainView extends AbstractView implements MainView {
private List<Observer> observers = new ArrayList<>(8);
private JButton goFileButton;
private JLabel descriptionLabel;
public DefaultMainView() {
goFileButton = new JButton("Make it so");
descriptionLabel = new JLabel("...");
descriptionLabel.setHorizontalAlignment(JLabel.CENTER);
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
add(goFileButton, gbc);
add(descriptionLabel, gbc);
goFileButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireDidPerformGoFile();
}
});
}
#Override
public void addObserver(Observer observer) {
observers.add(observer);
}
#Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
protected void fireDidPerformGoFile() {
for (Observer observer : observers) {
observer.didPerformGoFile(this);
}
}
#Override
public void setDescription(String description) {
descriptionLabel.setText(description);
}
}
And MainController....
public class MainViewController extends AbstractController<MainView> {
public MainViewController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
#Override
public void didPerformGoFile(MainView view) {
view.setDescription("Go file!");
}
});
}
}
Now, we can put them together and run them...
JFrame frame = new JFrame();
Controller controller = new MainViewController(new DefaultMainView());
frame.add(controller.getView().getView());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Now, you're probably sitting there thinking, "that's a lot of work for little gain" and you'd be ... wrong, actually.
Let's say you wanted to change how the controller responds to the goFileAction depending on some kind of state, like the user's credentials or something. You could put a lot of logic into the MainViewController to handle it, or, more easily, just create a different controller altogether (nb: This is where the model in "Model-View-Controller" would come in, but since there's no concept of model in your example, I've done it "differently")
public class OverlordController extends AbstractController<MainView> {
public OverlordController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
#Override
public void didPerformGoFile(MainView view) {
view.setDescription("Your overload has spoken!");
}
});
}
}
Then, by simply changing...
Controller controller = new MainViewController(new DefaultMainView());
to
Controller controller = new OverlordController(new DefaultMainView());
you change the output!
"Model-View-Controller" is not as straight forward in Swing as it might be in other APIs/frameworks, this is because Swing is already based on MVC, so you're actually wrapping a MVC on a MVC. If you understand this, you can make it work more easily.
For example, above, I don't expose the ActionListener to the controller, instead I created my own observer which described the actual actions which might be triggered by implementations of the view. The actual action handling took place in the implementation of the view itself.
This is good in the fact that we've decoupled the workflow, it also means that the view is free to implement the triggers for these actions in any way it sees fit.
You might want to also take a look at:
Implementing the Controller part of MVC in Java Swing
How MVC work with java swing GUI
Java and GUI - Where do ActionListeners belong according to MVC pattern?
What is the correct way of Message Passing between Classes in MVC?
Listener Placement Adhering to the Traditional (non-mediator) MVC Pattern
JTextField input fails to update output in TextView in MVC
Multithreaded MVC to recreate plane dashboard with multiple independent gauges
Where to store model objects in MVC design?
Runnable example...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public final class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
Controller controller = new OverlordController(new DefaultMainView());
frame.add(controller.getView().getView());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface View {
public JComponent getView();
}
public interface Controller<V extends View> {
public V getView();
}
public abstract class AbstractController<V extends View> implements Controller<V> {
private V view;
public AbstractController(V view) {
this.view = view;
}
#Override
public V getView() {
return view;
}
}
public abstract class AbstractView extends JPanel implements View {
#Override
public JComponent getView() {
return this;
}
}
public interface MainView extends View {
public interface Observer {
public void didPerformGoFile(MainView view);
}
public void addObserver(Observer observer);
public void removeObserver(Observer observer);
public void setDescription(String description);
}
public class MainViewController extends AbstractController<MainView> {
public MainViewController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
#Override
public void didPerformGoFile(MainView view) {
view.setDescription("Go file!");
}
});
}
}
public class OverlordController extends AbstractController<MainView> {
public OverlordController(MainView view) {
super(view);
view.addObserver(new MainView.Observer() {
#Override
public void didPerformGoFile(MainView view) {
view.setDescription("Your overload has spoken!");
}
});
}
}
public class DefaultMainView extends AbstractView implements MainView {
private List<Observer> observers = new ArrayList<>(8);
private JButton goFileButton;
private JLabel descriptionLabel;
public DefaultMainView() {
goFileButton = new JButton("Make it so");
descriptionLabel = new JLabel("...");
descriptionLabel.setHorizontalAlignment(JLabel.CENTER);
setBorder(new EmptyBorder(32, 32, 32, 32));
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
add(goFileButton, gbc);
add(descriptionLabel, gbc);
goFileButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
fireDidPerformGoFile();
}
});
}
#Override
public void addObserver(Observer observer) {
observers.add(observer);
}
#Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
protected void fireDidPerformGoFile() {
for (Observer observer : observers) {
observer.didPerformGoFile(this);
}
}
#Override
public void setDescription(String description) {
descriptionLabel.setText(description);
}
}
}
Found a simple JComboBox sample on java2 and expanded it to include both a DocumentListener and KeyListener
hoping to capture keystrokes done within the JComboBox.
Eventually those keystrokes will be captured to display the data which matches the keys entered.
For example, as the user types APP, all records beginning with A is return then AP is return and then all data beginning with APP. Basically doing a Filter on "APP*".
But for now, I am unable to get either a KeyListener or DocumentListener working.
Actually, it works sporadically and can't narrow down why. It seems to only work for the Enter key but would like for it to capture for all keystrokes.
Here is the code.
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.ComboBoxEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.metal.MetalFileChooserUI;
public class JComboBoxFilter extends JPanel implements ItemListener {
public JComboBoxFilter () {
JComboBox jc = new JComboBox();
jc.addItem("A");
jc.addItem("AA");
jc.addItem("AAA");
jc.addItem("C");
jc.addItem("CC");
jc.addItem("CCC");
jc.addItem("B");
jc.addItem("BB");
jc.addItem("BBB");
jc.addItemListener(this);
add(jc);
ComboBoxEditor editor = jc.getEditor();
JTextField textField = (JTextField)editor.getEditorComponent();
textField.addKeyListener(new KeyListener()
{
#Override
public void keyPressed(KeyEvent arg0) {
runThisKeyListener();
}
#Override
public void keyReleased(KeyEvent arg0) {
runThisKeyListener();
}
#Override
public void keyTyped(KeyEvent arg0) {
runThisKeyListener();
}
private void runThisKeyListener()
{
System.out.println("Inside runThisKeyListener() : " + textField.getText());
}
});
DocumentListener textFieldDL = new DocumentListener()
{
#Override
public void insertUpdate(DocumentEvent e)
{
runThis();
}
#Override
public void removeUpdate(DocumentEvent e)
{
runThis();
}
#Override
public void changedUpdate(DocumentEvent e)
{
runThis();
}
private void runThis()
{
System.out.println("Inside runThis() : " + textField.getText());
}
};
textField.getDocument().addDocumentListener(textFieldDL);
}
public void itemStateChanged(ItemEvent ie) {
String s = (String)ie.getItem();
System.out.println(s);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new JComboBoxFilter ());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
Is there anything wrong with the code or is there a Java rule or restriction not allowing this type of functionality?
I have the following code for a JMenuBar. How would I add my key listener CustomKeyListener to the entire JMenuBar?
package UI;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.*;
import java.awt.Point;
import java.awt.font.*;
import UI.*;
public class GuiDMenuBar extends JMenuBar
{
JMenu m_file,m_code;
JMenuItem mi_f_new,mi_f_open;
public GuiDMenuBar()
{
setBorderPainted(true);
makeFileMenu();
makeCodeButton();
}
void makeFileMenu()
{
m_file = new JMenu("File");
m_file.setMnemonic('F');
mi_f_new = new JMenuItem("New");
mi_f_new.setMnemonic('N');
mi_f_open = new JMenuItem("Open");
mi_f_open.setMnemonic('O');
mi_f_new.setAccelerator(KeyStroke.getKeyStroke("control N"));
mi_f_open.setAccelerator(KeyStroke.getKeyStroke("control O"));
m_file.add(mi_f_new);
m_file.add(mi_f_open);
add(m_file);
}
void makeCodeButton()
{
m_code = new JMenu("Code");
m_code.setMnemonic('C');
add(m_code);
}
public void addListeners(ActionListener al)
{
mi_f_new.addActionListener(al);
mi_f_open.addActionListener(al);
}
class CustomKeyListener implements KeyListener
{
#Override
public void keyTyped(KeyEvent e)
{
System.out.println("Type");
}
#Override
public void keyPressed(KeyEvent e)
{
System.out.println("Press");
}
#Override
public void keyReleased(KeyEvent e)
{
System.out.println("Release");
}
}
}
I have tried adding
m_code.setFocusable(true);
m_code.addKeyListener(new CustomKeyListener());
to the void makeCodeButton however that did not pick up when anything was typed for that one JMenu. This is why I want it added to the whole JMenuBar instead.
Edit to show full CustomKeyListener
class CustomKeyListener implements KeyListener
{
Robot Roby = null;
#Override
public void keyTyped(KeyEvent e)
{
char c = e.getKeyChar();
if(c==KeyEvent.VK_ENTER)
{
if(m_code.isSelected())
{
try
{
Roby = new Robot();
}
catch(AWTException awte)
{
awte.printStackTrace();
}
clcikComponent(m_file);
}
}
System.out.println("Type");
}
#Override
public void keyPressed(KeyEvent e)
{
System.out.println("Press");
}
#Override
public void keyReleased(KeyEvent e)
{
System.out.println("Release");
}
public void clcikComponent(Component comp)
{
Point p = comp.getLocationOnScreen();
System.out.println(p);
Roby.mouseMove(p.x,p.y);
Roby.mousePress(MouseEvent.BUTTON1_MASK);
Roby.mouseRelease(MouseEvent.BUTTON1_MASK);
}
}
I still think this is a bad idea. As a user I would find it very confusing to find out that using the Enter key on one menu invokes an Action, while it doesn't do anything on other menus. The suggestion I gave in my comment is a far better solution.
However, I was curious why it didn't work and I found out that focus is actually on the JRootPane when the menu is displayed (and events are only dispatched to the component with focus). So you could add the KeyListener to the root pane.
However, there is an easier approach. You can use the JMenu.addMenuKeyListener(...) method. The interface is the same as a KeyListener except all methods include "menu" in the name.
When I use two radio buttons with the same name then they are in a group. If one gets selected the other one gets unselected.
I want to build my own Radio Button Widget which is represented by the following code.
How can I achieve that if more than one of my widgets have the same name only one is selected just like for normal radio buttons that are grouped?
public class MyRadioButton extends Composite implements HasText, HasName, HasValueChangeHandlers<Boolean>, HasValue<Boolean> {
private FlowPanel picker;
private boolean isChecked;
public MyRadioButton() {
picker = new FlowPanel();
initWidget(picker);
addValueChangeHandler(new ValueChangeHandler<Boolean>() {
#Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
ValueChangeEvent.fire(MyRadioButton.this, isChecked);
}
});
}
#Override
public void setValue(Boolean value, boolean fireEvents) {
...
if (fireEvents) {
ValueChangeEvent.fire(MyRadioButton.this, value);
}
}
}
Do you solved your problem? If not this could help
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.RadioButton;
public class MyRadioButton extends Composite implements
DeselectOtherRadioButtonsHandler {
private RadioButton rb;
private String radioButtonGroup;
public MyRadioButton(String radioButtonGroup) {
rb = new RadioButton("Foo Button");
getEventBus().addHandler(DeselectOtherRadioButtonsEvent.getType(), this);
rb.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
#Override
public void onValueChange(ValueChangeEvent<Boolean> event) {
if (event.getValue().booleanValue()) {
// deselect other in same group
getEventBus().fireEvent(new DeselectOtherRadioButtonsEvent(radioButtonGroup);
}
}
});
}
#Override
public void onDeselectOtherRadioButtons(DeselectOtherRadioButtonsEvent event) {
// Same RadioButton Group?
if (radioButtonGroup.equalsIgnoreCase(event.getRadioButtonGroup())) {
rb.setValue(false);
}
}
}
class DeselectOtherRadioButtonsEvent extends
GwtEvent<DeselectOtherRadioButtonsHandler> {
private final static Type<DeselectOtherRadioButtonsHandler> TYPE = new Type<DeselectOtherRadioButtonsHandler>();
private final String radioButtonGroup;
public DeselectOtherRadioButtonsEvent(String radioButtonGroup) {
this.radioButtonGroup = radioButtonGroup;
}
public String getRadioButtonGroup() {
return radioButtonGroup;
}
#Override
public Type<DeselectOtherRadioButtonsHandler> getAssociatedType() {
return TYPE;
}
#Override
protected void dispatch(DeselectOtherRadioButtonsHandler handler) {
handler.onDeselectOtherRadioButtons(this);
}
}
interface DeselectOtherRadioButtonsHandler extends EventHandler {
void onDeselectOtherRadioButtons(DeselectOtherRadioButtonsEvent event);
}
What is the simplest way to implement "hover behavior" in Piccolo2D?
I.e. to change object's color or style when mouse cursor is above it? Need to take in account both move ins and outs correctly.
You can add input event handlers to nodes. Below is a basic example that attaches PBasicInputEventHandler to a layer to capture mouseEntered and mouseExited events. It is also possible to add event handler to individual nodes in a layer.
import java.awt.Color;
import javax.swing.SwingUtilities;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import edu.umd.cs.piccolo.nodes.PPath;
import edu.umd.cs.piccolox.PFrame;
public class DemoInputHandler {
#SuppressWarnings("serial")
private static void createAndShowUI() {
new PFrame() {
#Override
public void initialize() {
PPath node = PPath.createRectangle(0, 0, 100, 100);
node.setOffset(50, 50);
node.setPaint(Color.BLUE);
getCanvas().getLayer().addChild(node);
node = PPath.createRectangle(0, 0, 100, 100);
node.setOffset(200, 50);
node.setPaint(Color.BLUE);
getCanvas().getLayer().addChild(node);
getCanvas().getLayer().addInputEventListener(
new PBasicInputEventHandler() {
#Override
public void mouseEntered(final PInputEvent event) {
event.getPickedNode().setPaint(Color.RED);
}
#Override
public void mouseExited(final PInputEvent event) {
event.getPickedNode().setPaint(Color.BLUE);
}
});
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}