The flow of the program is like this : Image from 1st set of buttons (leftButtonArea) is dragged to the 2nd set of buttons (rightButtonArea).
Each image has a unique name via setName(). The name of the image that was dragged over will be compared with the name of the button which it is dragged to.
If the name matches, I wish to disable that particular button from reacting to any hover event.
.setHoverEnabled(false) doesn't work =/
A similar SO thread regarding the disabling of event listeners, but it seems like the solutions such a using a glass pane are for whole components ?
link
Edit:
Somehow this works, but I am not sure of any side effects from this method
source.removeMouseListener(source.getMouseListeners()[1]);
Edit2:
Found something interesting.. This could be the reason why disabled buttons still reacts to mouseEvents.
"low-level: Component, Container, Focus, Key, Mouse, Paint, Window
semantic: Action, Adjustment, Item, Text
Only semantic events are affected by disabling any component. That is because they are directly handled by the component itself which is aware that it is enabled or not.
Low level events can't be affected by disabling. If you stop to think about this when you disabled your label was it still visible. If it was then the paint event must have happened. Low level events will always happen and it is up to your handlers to query the component if it is enabled or not."
// 1st set of 4 buttons
for(int a=0; a<4; a++){
leftButtonArea[a] = new JleftButtonArea(new ImageIcon(image));
TransferHandler transfer = new TransferHandler("icon");
leftButtonArea[a].setTransferHandler(transfer);
leftButtonArea[a].addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
JleftButtonArea leftButtonArea = (JleftButtonArea)e.getSource();
TransferHandler handle = leftButtonArea.getTransferHandler();
handle.exportAsDrag(leftButtonArea, e, TransferHandler.COPY);
// get unique name for the image that is dragged
// to rightButtonArea
name1 = e.getComponent().getName();
}
});
}
// creates 2nd set of 4 buttons
for(int b=0; b<4; b++){
rightleftButtonAreaArea[b] = new JleftButtonArea();
// <---- creates unique name for each leftButtonArea ----->
cc2 += 1;
id2+="a"+cc2;
rightleftButtonAreaArea[b].setName(id2);
// <---- creates unique name for each leftButtonArea ----->
TransferHandler transfer1 = new TransferHandler("icon");
rightleftButtonAreaArea[b].setTransferHandler(transfer1);
rightleftButtonAreaArea[b].addMouseListener(new MouseAdapter(){
#Override
public void mouseExited(MouseEvent me){
JleftButtonArea source = (JleftButtonArea)me.getSource();
try{
// compare unique name of image and the button in rightButtonArea
// if they are the same, disable hover for the button
if( name1.equals(source.getName())){
// this doesn't work
source.getName().setHoverEnabled(false);
// Somehow this works, but I am not sure of any side effects from this
source.removeMouseListener(source.getMouseListeners()[1]);
}
else{
source.setIcon(null);
}
}
catch (NullPointerException e)
{
}
}
});
}
for Buttons JComponents are MouseEvent are implemented in the ButtonModel
use implemented methods for Icon in the JButton API
examples JButton & Icon, JButton & ButtonModel
try
button.setRolloverEnabled(false);
Related
I am having issues with my java application and I can't find a suitable reply.
In summary a right click triggered default pop up menu changes my chart's background color behind the pop up.
You can find images below. I am happy to keep the default popup without the "buggy" behaviour or develop my own if required.
A click of a button starts a stream of data and adds a chart to a JInternalFrame component:
If I right click on the image a default pop up comes up:
If I then click away the rectangle area covered by the popup will overlay the chart like this:
TimeseriesMonitorModel model = new DefaultTweetMonitorModel();
jif.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
try {
jif.setContentPane(new TweetSeriesChartPane(model, TweetMonitor.keywords, tkc));
jif.setSize(jif.getWidth(), jif.getHeight());
} catch (InterruptedException ex) {
Logger.getLogger(TweetMonitor.class.getName()).log(Level.SEVERE, null, ex);
}
jif.setVisible(true);
where jif is the Jinternalframe and
public TweetSeriesChartPane(TimeseriesMonitorModel model, String[] seriesNames, TweetKeywordCount tkc) throws InterruptedException {
this.seriesNames = seriesNames;
this.tkc = tkc;
this.model = model;
XYChartTimeseries myRealTimeChart = new XYChartTimeseries();
chart = myRealTimeChart.getChartWithTitle();
List[] tweetData = model.getFrequencyCount(new AtomicIntegerArray(seriesNames.length)); // we are starting from 0
int i = 0;
for (String keyword : seriesNames) {
List<Integer> yData = (List<Integer>) tweetData[1].get(i);
chart.addSeries(keyword, tweetData[0], yData); // adding first value
i++;
}
setLayout(new BorderLayout());
XChartPanel<XYChart> chartPane = new XChartPanel<>(chart);
add(chartPane);
UpdateWorker worker = new UpdateWorker(this, seriesNames, this.tkc);
worker.execute();
}
I've managed to temporary solve the above.
I've checked specifically this line of code
XChartPanel<XYChart> chartPane = new XChartPanel<>(chart);
which extends Chart and Jpanel. The code is from the knowm-chart dependency https://github.com/knowm/XChart/blob/develop/xchart/src/main/java/org/knowm/xchart/XChartPanel.java)
Apparently it adds a listener and the customized PopUpMenu. After reviewing it, it looks like it didn't do any repainting when the mouse was clicked outside the PopUpMenu area.
So I created a new class and tried to customise it. However, the repaint was flickering the screen and I couldn't get it to work only in the PopUpMenu area.
I ended up disabling the .addMouseListener call so now I don't get any popUpMenu. I sad compromise, but oh well.
BTW:
Thanks to both, regardless of the last unneeded comment which didn't add any value.
I did read the link and I though I provided enough information.
In any case, posting to code helped me troubleshoot it
I have an array of JPanel with JLabel with icons that represent a seat at a theater, all of them are generated using loop.
Upon loading the seats, those that are already booked need to have a different image icon. So if(){} check is performed on all the seats to change the label icon if the seat is booked, after they are generated.
But the image icon I have on my disk is not loading fast enough so sometimes the panel adds only to the last one booked or not at all.
Every of those panels that represent the chairs has also MouseListener interfaces added to them. So also on mouse hover or click ImageIcon objects added to the panels are changed, there is too much delay when this happens. I'm thinking that has to do with the images being on the disk!.
How can I load and store those icon images 2,78 KB in size in memory and refer to it in memory, so it wont be delayed reading them?
When a seat is clicked I need to change the label image of that seat and remove mouse listener from that seat. Is there a way to remove the mouse listener to that particular seat without referring to a specific mouse listener. I needed to do that outside of the mouse listener itself!
panel.removeAll();
Does not remove the mouse listener added upon generating the panels.
public void drawSeats(int ammountSeat, int localLength, int localWidth) {
pnlSeatsHolder = new JPanel();
pnlSeatsHolder.setPreferredSize(new Dimension(localLength * 40,localLength * 45));
pnlSeatsHolder.setLayout(new FlowLayout());
for (int d = 0; d <= (ammountSeat); d++) {
imgIconYellow = new ImageIcon("seatYellow.png");
imgIconBlue = new ImageIcon("seatBlue.png");
imgIconRed = new ImageIcon("seatRed.png");
JButton chairs = new JButton();
chairs.setPreferredSize(new Dimension(30, 40));
pnlSeatsHolder.add(chairs);
chairs.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
for (int i = 0; i < listSeatsObjects.size(); i++) {
if (listSeatsObjects.get(i).equals(e.getSource())) {
/*I need to do this also outside of this method! how can i refer to this MouseListener
* to forexample do the equivalent of chairs.removeMouseListener(this);*/
chairs.removeAll();
chairs.setIcon(imgIconRed);
chairs.repaint();
chairs.removeMouseListener(this);
// send information of the chair somewhere else
}
}
}
public void mouseEntered(MouseEvent e) {
// chairs.setBackground(Color.blue);
chairs.removeAll();
chairs.setIcon(imgIconBlue);
chairs.repaint();
}
public void mouseExited(MouseEvent e) {
// chairs.setBackground(Color.BLACK);
chairs.removeAll();
chairs.setIcon(imgIconYellow);
chairs.repaint();
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
});
}
}
so this is the method it self that draws the seats when called. I did some modification as #AndrewThompson suggested, instead of JPanels i use now JButtons, but what happens is that the images are not loaded at all on to the buttons.. what am i missing? neither on mouse hover either.. tho it does work if i had for example charis.setBackgroundColor(); on hover or click.. so i now i need to rather change the buttons images when clicked and on hover, i've tried chairs.chairs.setRolloverIcon(); and .setIcon(); both not working as well. what is wrong. my images are in the same directory as the class files.. so that cant be the issue..
int localLength, int localWidth is the size of the the rooms that seats will be drawn in. about 1m^2/seat
For three images, load them when the class is initialized and store them as attributes of the class. Of course, each of the 3 images can be used in as many icons as needed.
So I'm trying to write a JButton that will act like an enter key when pressed. It must be able to fool a JTextField that is in focus into calling its action listeners. It can not use the robot framework, because that will make every program think enter is pressed, which is a problem.
Here is the backstory:
I have a program (written in Swing) which allows someone to enter data in many textfields and other things by hitting enter after typing in the data. It works great.
However, most people that use it are using a second program at the same time which automatically listens for an enter key and shuts off a robot (for those of you who are familiar with FIRST robotics, I'm talking about the SmartDashboard and the Driver Station). There have been quite a few complaints about this. People want to enter data without disabling the robot. As it turns out, the SmartDashboard (the program people want to hit enter on) allows custom swing components to be run along with it.
not entirely sure if I understand your requirement correctly (will delete this if not) ...
You can manually dispatch an event to whatever component you want to address. In the case of wanting to dispatch to the focusOwner
find the focusOwner by querying the KeyboardFocusManager
create a keyEvent with the focusOwner as sender
dispatch that event to the focusOwner
Something like:
Action action = new AbstractAction("fake enter") {
#Override
public void actionPerformed(ActionEvent e) {
KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
Component comp = manager.getFocusOwner();
KeyEvent event = new KeyEvent(comp,
KeyEvent.KEY_PRESSED, System.currentTimeMillis(), 0,
KeyEvent.VK_ENTER, KeyEvent.CHAR_UNDEFINED);
comp.dispatchKeyEvent(event);
}
};
JButton button = new JButton(action);
button.setFocusable(false);
Action textAction = new AbstractAction("text") {
#Override
public void actionPerformed(ActionEvent e) {
LOG.info("I'm the text action" + ((Component) e.getSource()).getName());
}
};
JComponent comp = Box.createVerticalBox();
for (int i = 0; i < 5; i++) {
JTextField field = new JTextField(20);
field.setName(": " + i);
field.setAction(textAction);
comp.add(field);
}
comp.add(button);
Edit
added some lines for actually playing with it (#Joe commented it's not working). Clicking the button triggers the action of the focused textField (here simply prints out the field's name) Local context is vista and jdk6u27.
You might try getRootPane().setDefaultButton() on the frame. There's an example here.
Grabbing the element with the focus and manually dispatching an enter event didn't quite work, but because I just wanted to effect various JTextField, I came up with a similar solution:
addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if (focusOwner instanceof JTextField) {
((JTextField) focusOwner).postActionEvent();
}
}
});
Thanks for pointing me in the right direction.
I have a panel containing a number of components, one of which is a JTable. When the JTable has focus and the TAB key is pressed, the default behaviour is to move focus from cell to cell within the table. I need to change this to focus on the next component instead i.e. leave the JTable completely.
Ctrl-TAB achieves the desired results, but is not acceptable to the user. I can add a key listener to the table and change the focus when TAB is pressed, but it feels as though there might be a better way to do this.
Any ideas?
Thanks...
You would typically do this by adding an Action to the components action map and then binding a keystroke with it in the component's input map (example code below). However, this will not work for tab as this event is consumed by the focus subsystem unless you add the following line to remove tab as a focus traversal key:
tp.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.<AWTKeyStroke>emptySet());
Here's the full example code:
public static void main(String[] args) {
final JTabbedPane tp = new JTabbedPane();
// Remove Tab as the focus traversal key - Could always add another key stroke here instead.
tp.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, Collections.<AWTKeyStroke>emptySet());
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0);
Action nextTab = new AbstractAction("NextTab") {
public void actionPerformed(ActionEvent evt) {
int i = tp.getSelectedIndex();
tp.setSelectedIndex(i == tp.getTabCount() - 1 ? 0 : i + 1);
}
};
// Register action.
tp.getActionMap().put("NextTab", nextTab);
tp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "NextTab");
tp.addTab("Foo", new JPanel());
tp.addTab("Bar", new JPanel());
tp.addTab("Baz", new JPanel());
tp.addTab("Qux", new JPanel());
JFrame frm = new JFrame();
frm.setLayout(new BorderLayout());
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.add(new JButton(nextTab), BorderLayout.NORTH);
frm.add(tp, BorderLayout.CENTER);
frm.setBounds(50,50,400,300);
frm.setVisible(true);
}
Well you probably don't want to just get rid of the Tab Action because it has other responsibilities. For example, when you are editing a cell the Tab Action stops cell editing before moving to the next cell. So you probably want to retain this behaviour while adding extra behavour to change focus to the next component.
I refer to this as "wrapping an action" and you can find an example of this by checking out the Table Tabbing action. You should be able to easily customize the code to use the KeyboardFocusManager to transfer focus.
Suppose I have 4 squares colored blue, white, red and green (myComponent) associated with the mouse press event. At one point, the mouse is pressed over one of them - say, the yellow one - and the event is activated.
Now, the control flux is inside the event handling function. How do I get the MyComponent - the yellow square - that caused this from here?
EDIT
I have another question. Is there a way to tell the position of the component? My problem is a bit more complicated than what I said.
Basically, I have a grid full of squares. When I click one of the squares, I have to know which one it is, so I can update my matrix. The thing is, if I calculate it myself, it only works on a given resolution.
I have a GridBagLayout, and inside it are the myComponents. I have to know which one of the components exactly - like, component[2][2] - caused the interruption.
I mean, I can tell which one of the components did it, but not where in the matrix it is located.
MouseEvent.getSource() returns the object on which the event initially occurred.
I have a GridBagLayout, and inside it
are the myComponents. I have to know
which one of the components exactly -
like, component[2][2] - caused the
interruption.
You could store the indices, e.g. (2,2), inside each myComponent when you add them to the matrix. That way, given the component, you can always identify its position in the matrix.
class MyComponent extends JButton
{
final int i; // matrix row
final int j; // matrix col
// constructor
MyComponent(String text, int i, int j)
{
super(text);
this.i = i;
this.j = j;
}
...
}
By adding a MouseListener (or alternatively, a MouseAdapter, if you don't need to override all the MouseListener' methods) to each of your colored boxes, when an event such as a mouse click occurs, theMouseListenerwill be called with a [MouseEvent`]3, which can be used to obtain the component that was clicked.
For example:
final MyBoxComponent blueBox = // ... Initialize blue box
final MyBoxComponent whiteBox = // ... Initialize white box
final MyBoxComponent redBox = // ... Initialize red box
final MyBoxComponent greenBox = // ... Initialize green box
MouseListener myListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
// Obtain the Object which caused the event.
Object source = e.getSource();
if (source == blueBox)
{
System.out.println("Blue box clicked");
}
else if (source == whiteBox)
{
System.out.println("White box clicked");
}
// ... and so on.
}
};
blueBox.addMouseListener(myListener);
whiteBox.addMouseListener(myListener);
redBox.addMouseListener(myListener);
greenBox.addMouseListener(myListener);