AspectJ capture button clicked - button

I want to know whether how to capture the button clicked with AspectJ and get its parameter (eg. button name). I think for having more generalized capturing with AspectJ, it shoudl be used MouseListener so it can capture other UI elements in general!
Example:
In a GUI example I have defined 2 buttons that take some actions
public JButton btn1 = new JButton("Test1");
public JButton btn2 = new JButton("Test2");
btn1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//take some actions
}
}
btn2.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//take some actions
}
}
How to capture these buttons with AspectJ, and get their parameters (eg. name)?

It is possible. I have provided two examples. The first that prints out for every JButton that has an ActionListener. The other example only prints out if a specific buttons is clicked.
Prints the text for every JButton clicked with an ActionListener:
#Pointcut("execution(* *.actionPerformed(*)) && args(actionEvent)")
public void buttonPointcut(ActionEvent actionEvent) {}
#Before("buttonPointcut(actionEvent)")
public void beforeButtonPointcut(ActionEvent actionEvent) {
if (actionEvent.getSource() instanceof JButton) {
JButton clickedButton = (JButton) actionEvent.getSource();
System.out.println("Button name: " + clickedButton.getText());
}
}
Prints the text for a specific JButton:
public static JButton j1;
#Pointcut("execution(* *.actionPerformed(*)) && args(actionEvent) && if()")
public static boolean button1Pointcut(ActionEvent actionEvent) {
return (actionEvent.getSource() == j1);
}
#Before("button1Pointcut(actionEvent)")
public void beforeButton1Pointcut(ActionEvent actionEvent) {
// logic before the actionPerformed() method is executed for the j1 button..
}
UPDATED:
You can do this in many different ways. For example add your buttons to the aspect directly. But I prefere to use a enum object between (ButtonManager in this case), so the code does not know about the aspect. And since the ButtonManager is an enum object, it is easy for the aspect to retrieve values from it.
I just tested it with a Swing button class from Oracle and it works. In the Swing class:
b1 = new JButton("Disable middle button", leftButtonIcon);
ButtonManager.addJButton(b1);
AspectJ is extremely powerful when it comes to manipulating classes, but it can not weave advises into specific objects since objects is not created at the time of weaving. So you can only work with objects at runtime and that is why I have added the addJButton(..) method above. That enables the aspect to check the advised button against a list of registered buttons.
The ButtonManager class:
public enum ButtonManager {
;
private static Collection<JButton> buttonList = new LinkedList<JButton>();
public static void addJButton(JButton jButton) {
buttonList.add(jButton);
}
public static Collection<JButton> getButtonList() {
return buttonList;
}
}
Modified pointcut and advice to only print the name of the buttons registered in the ButtonManager:
#Pointcut("execution(* *.actionPerformed(*)) && args(actionEvent) && if()")
public static boolean buttonListPointcut(ActionEvent actionEvent) {
Collection<JButton> buttonList = ButtonManager.getButtonList();
JButton registeredButton = null;
for (JButton jButton : buttonList) {
if (actionEvent.getSource() == jButton) {
registeredButton = jButton;
}
}
return registeredButton != null;
}
#Before("buttonListPointcut(actionEvent)")
public void beforeButtonListPointcut(ActionEvent actionEvent) {
JButton clickedButton = (JButton) actionEvent.getSource();
System.out.println("Registered button name: " + clickedButton.getText());
}
UPDATED 2
Okay, I believe I understand what you want. You want to listen to mouse events. That is possible. The downside is that you have to register all your GUI components that you want to listen for clicks with a mouse listener. It is not enough to register the JPanel of the JFrame with a MouseListener. So if you only have registered an ActionListener for your buttons, you also have to add a mouse listener.
I have created a quick solution that works for me. It only shows that it works. I have not tried to make the solution generic with many different GUI objects. But that should be quite easy to refactor in when you have got the basics to work.
In the Swing class:
private class MouseListener extends MouseInputAdapter {
public void mouseClicked(MouseEvent e) {}
}
In the init method of the Swing class:
MouseListener myListener = new MouseListener();
btn1.addMouseListener(myListener);
btn2.addMouseListener(myListener);
In the Aspect class:
#Pointcut("execution(* *.mouseClicked(*)) && args(mouseEvent)")
public void mouseEventPointcut(MouseEvent mouseEvent) {}
#Before("mouseEventPointcut(mouseEvent)")
public void beforeMouseEventPointcut(MouseEvent mouseEvent) {
if (mouseEvent.getSource() instanceof JButton) {
JButton clickedButton = (JButton) mouseEvent.getSource();
System.out.println("aspectJ --> mouseClicked: " + clickedButton.getText());
}
}
This results in the following output in the console:
aspectJ --> mouseClicked: Test1
I hope it helps!

Related

javaFX focusHandler?

I am just changing from AWT to JavaFX and im wondering how to work with focus.
For Exampe: In AWT I wrote something like that:
Button bFocus = new Button("Focus");
bFocus.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
System.out.println("Having the Focus");
}
public void focusLost(FocusEvent e) {
System.out.println("Lost the Focus");
}
});
But how does it work in JavaFX? I tried many different things, but that doesnt work...
JavaFX has an API that defines observable properties with which you can register listeners and respond when they change. Almost all state that belongs to UI elements in JavaFX is represented by these properties, allowing you to register a listener that responds when they change.
So, for example, the superclass of all UI elements, Node has a ReadOnlyBooleanProperty called focused, with which you can register a listener:
Button bFocus = new Button("Focus");
bFocus.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
if (isNowFocused) {
System.out.println("Having the Focus");
} else {
System.out.println("Lost the Focus");
}
});
I thought it might be helpful to see an example which specifies the ChangeListener as an anonymous inner class like James_D mention here.
TextField yourTextField = new TextField();
yourTextField.focusedProperty().addListener(new ChangeListener<Boolean>()
{
#Override
public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue, Boolean newPropertyValue)
{
if (newPropertyValue)
{
System.out.println("Textfield on focus");
}
else
{
System.out.println("Textfield out focus");
}
}
});
I hope this answer is helpful!

How to make always visible headers of rows in RowsFragment

Here is what i have now.
Simply my RowsFragment is look like this,
public static class SampleFragmentB extends RowsFragment {
private final ArrayObjectAdapter mRowsAdapter;
public SampleFragmentB() {
mRowsAdapter = new ArrayObjectAdapter(new ShadowRowPresenterSelector());
setAdapter(mRowsAdapter);
setOnItemViewClickedListener(new OnItemViewClickedListener() {
#Override
public void onItemClicked(
Presenter.ViewHolder itemViewHolder,
Object item,
RowPresenter.ViewHolder rowViewHolder,
Row row) {
Toast.makeText(getActivity(), "Implement click handler", Toast.LENGTH_SHORT)
.show();
}
});
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
createRows();
getMainFragmentAdapter().getFragmentHost().notifyDataReady(getMainFragmentAdapter());
}
private void createRows() {
String json = Utils.inputStreamToString(getResources().openRawResource(
R.raw.page_row_example));
CardRow[] rows = new Gson().fromJson(json, CardRow[].class);
for (CardRow row : rows) {
mRowsAdapter.add(createCardRow(row));
}
}
private Row createCardRow(CardRow cardRow) {
PresenterSelector presenterSelector = new CardPresenterSelector(getActivity());
ArrayObjectAdapter adapter = new ArrayObjectAdapter(presenterSelector);
for (Card card : cardRow.getCards()) {
adapter.add(card);
}
HeaderItem headerItem = new HeaderItem(cardRow.getTitle());
return new CardListRow(headerItem, adapter, cardRow);
}
}
This is what i exactly want to do,
So I want to make always visible Header of each row without selecting into or focusing into RowsFragment. I'am using leanback v24 to add multiple rows into each header item.
You might want to check the Sofa library for Android TV that extends the Leanback library capabilities by offering a set of more powerful features. In BrowseSupportFragment, mRowsFragment.setExpand should be true. Additional reference: how to always show headers in RowsFragment

vaadin 7 layout click doesn't work

I've created MainGameTab which extends TabSheet.
In constructor I create layouts and add them as tabs. I wanted to add right click event to the layout
mainLayout.addLayoutClickListener(new LayoutClickListener() {
private static final long serialVersionUID = 1871942396979048283L;
#Override
public void layoutClick(LayoutClickEvent event) {
if (event.getButton() == MouseButton.RIGHT) {
TextQuestUi.getCurrent().addWindow(new CharacterSheet(c));
}
}
});
this.addTab(mainLayout, "Game");
CharacterSheet is a class, that extends Window
public class CharacterSheet extends Window {
But when I click on tab - I've got basic right click items for browser instead of new window.
What's the problem?
My MainGameTab looks like this
public MainGameTab() {
final Player c = new Player();
c.setName("Hero");
c.setLevel(100);
Skill skill = new Skill();
skill.setName("Help from heaven");
skill.setEffect("Full recover health");
c.addSkill(skill);
Stat stat = new Stat();
stat.setName("Attack");
stat.setValue(50);
c.addStat(stat);
HorizontalLayout mainLayout = new HorizontalLayout();
mainLayout.addLayoutClickListener(new LayoutClickListener() {
private static final long serialVersionUID = 1871942396979048283L;
#Override
public void layoutClick(LayoutClickEvent event) {
if (event.getButton() == MouseButton.RIGHT) {
TextQuestUi.getCurrent().addWindow(new CharacterSheet(c));
}
}
});
this.addTab(mainLayout, "Game");
HorizontalLayout logLayout = new HorizontalLayout();
this.addTab(logLayout, "Log");
}
And I add it in UI
#Override
protected void init(VaadinRequest request) {
this.setContent(new MainGameTab());
}
I'll suggest you to use one of the existing Vaadin addons. See here
Or, I am assuming that you're probably looking for getButton() in ItemClickEvent - something like this:
t.addListener(new ItemClickListener() {
public void itemClick(ItemClickEvent event) {
if (event.getButton()==ItemClickEvent.BUTTON_RIGHT) {
// Right mouse button clicked, do greatThings!
}
}
});

Adding Action listener for buttons created by method

Ok if i have the following code:
protected void makebutton(String name){
JButton button = new JButton(name);
mypanel.add(button);
}
then:
makebutton("Button1");
makebutton("Button2");
makebutton("Button3");
How can i add ActionListener to them. Which name do I use for ActionListener, tried many combination but no success.
What you could do is make the method return a Button. Thats way you can use the button variable else where in your program. What's happening in your case is that the button is encapsulated. so you can't access from anywhere else in your code. Something like this
private JButton makeButton(String name){
JButton button = new JButton(name);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
// code action to perform
}
});
return button;
}
You can use the method when you declare the button
JButton aButton = makeButton();
panel.add(aButton);
The more reasonable way to do it is just create the buttons without a method.
JButtton button = new JButton("Button");
panel.add(button);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
// code action to perform
}
});
I don't really see the need for a method.
Another option is to create a custom listener class
public class GUI {
JButton button1;
JButton button2;
public GUI(){
button1 = new JButton();
button2 = new JButton();
button1.addActionListner(new ButtonListener());
button2.addActionListner(new ButtonListener());
}
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
if (e.getSource() == button1){
// do something
} else if (e.getSource() == button2){
// something
}
}
}
}
protected void makebutton(String name){
final String n = name;
JButton button = new JButton(name);
mypanel.add(button);
button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
if(n=="Button1"){
button1ActionListener();
}else if(n=="Button2"){
button2ActionListener();
}
}
});
}
you have to create more methods for every button.
I think peeskillet's second code is the good one.

Retrieving mouse-clicks in Graphstream

Since I couldn't find any specific place to discuss this, I thought I'd post here...
I'm using graphstream 1.1 (http://graphstream-project.org/), a graph visualization library for java, to develop a data visualization tool. I'm needing to retrieve mouseclicks on nodes to display related data, but after following the library tutorial, it's still not clear for me how to do this. Does anyone that used this could help me out here with a more straightfoward answer? The tutorial I'm following is at:
http://graphstream-project.org/doc/Tutorials/Graph-Visualisation_1.0/#retrieving-mouse-clicks-on-the-viewer
public class Clicks implements ViewerListener {
protected boolean loop;
public static void main(String args[]) {
new Clicks();
}
public Clicks() {
// We do as usual to display a graph. This
// connect the graph outputs to the viewer.
// The viewer is a sink of the graph.
Graph graph = new SingleGraph("Clicks");
Viewer viewer = graph.display();
// The default action when closing the view is to quit
// the program.
viewer.setCloseFramePolicy(Viewer.CloseFramePolicy.HIDE_ONLY);
// We connect back the viewer to the graph,
// the graph becomes a sink for the viewer.
// We also install us as a viewer listener to
// intercept the graphic events.
ViewerPipe fromViewer = viewer.newViewerPipe();
fromViewer.addViewerListener(this);
fromViewer.addSink(graph);
// Then we need a loop to wait for events.
// In this loop we will need to call the
// pump() method to copy back events that have
// already occured in the viewer thread inside
// our thread.
while(loop) {
fromViewer.pump();
}
}
viewClosed(String id) {
loop = false;
}
buttonPushed(String id) {
System.out.println("Button pushed on node "+id);
}
buttonReleased(String id) {
System.out.println("Button released on node "+id);
}
}
Just got it solved! I sent an e-mail to their mailing group. The tutorial code on the website was lacking some information. Those three functions need to be public void, and other 'imports' must be added:
import org.graphstream.ui.swingViewer.Viewer;
import org.graphstream.ui.swingViewer.ViewerListener;
import org.graphstream.ui.swingViewer.ViewerPipe;
Here a simple code to show you how to add click event to the nodes of a given graph in graphstream library. This code show how you can change the node's background by clicking on it. The colors are choosen randomly:
public class TutoMouseClicked{
Graph graph;
public TutoMouseClicked(){
}
public void run(){
//Build a simple graph with one node
graph = new SingleGraph("TutoMouseClicked", false, true);
graph.setAttribute("ui.quality");
graph.setAttribute("ui.antialias");
Node n1 = graph.addNode("n1");
n1.setAttribute("ui.style", "size: 100px;");
Viewer viewer = graph.display();
viewer.getDefaultView().setMouseManager(new TutoMouseManage());
}
public static void main(String args[]) {
new TutoMouseClicked().run();
}
}
And the class TutoMouseManage that implements MouseManager interface:
public class TutoMouseManage implements MouseManager{
/**
* The view this manager operates upon.
*/
protected View view;
/**
* The graph to modify according to the view actions.
*/
protected GraphicGraph graph;
protected GraphicElement element;
#Override
public void init(GraphicGraph gg, View view) {
this.graph = gg;
this.view = view;
view.addMouseListener(this);
view.addMouseMotionListener(this);
}
#Override
public void release() {
view.removeMouseListener(this);
view.removeMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent me) {
element = view.findNodeOrSpriteAt(me.getX(), me.getY());
if(element != null){
Random r = new Random();
element.setAttribute("ui.style", "fill-color: rgb("+r.nextInt(256)+","+r.nextInt(256)+","+r.nextInt(256)+");");
}
}
#Override
public void mousePressed(MouseEvent me) {
}
#Override
public void mouseReleased(MouseEvent me) {
}
#Override
public void mouseEntered(MouseEvent me) {
}
#Override
public void mouseExited(MouseEvent me) {
}
#Override
public void mouseDragged(MouseEvent me) {
}
#Override
public void mouseMoved(MouseEvent me) {
}
}
you can adapt this code to get what you need, add any other mouse event you want: mouse released, mouse pressed, mouse dragged and all mouse events.

Resources