I'm trying to build a program that utilizes a 3x3 grid of buttons (using Java Swing), so I initialize it with a GridLayout and a loop to create the buttons:
panel.setBorder(BorderFactory.createEmptyBorder(3,3,5,5))
panel.setLayout(new GridLayout(3,3,10,10));
String[] buttons = {"Top Left", "Top Middle", "Top Right", "Middle Left", "Middle", "Middle Right", "Bottom Left", "Bottom Middle", "Bottom Right"};
for(int i = 0; i < buttons.length; i++) {
buttray[i] = new JButton(buttons[i]);
panel.add(buttray[i]);
buttray[i].addActionListener(this);
}
The buttons load just fine, but I do not understand how to use ActionListeners to differentiate between the buttons. When I check the paramString() method from the printout, each button gives the same modifier:
Top Left
ACTION_PERFORMED,cmd=Top Left,when=1431640106712,modifiers=Button1
Top Middle
ACTION_PERFORMED,cmd=Top Middle,when=1431640107566,modifiers=Button1
Top Right
ACTION_PERFORMED,cmd=Top Right,when=1431640107978,modifiers=Button1
Does this modifier value act as the button's identifier, and if so, how do I change it?
There are multiple ways to distinguish which button fired the ActionEvent:
Set/get the action command of each button (eg if (e.getActionCommand().equals("Top Left"))
Use == to compare instances (eg if (e.getSource() == buttray[0] ))
Get the text of the JButton (eg if (e.getSource().getText().equals("Top Left"))
Set/get the name of the JButton (eg if (e.getSource().getName().equals("Top Left"))
Add a different ActionListener to each button (in other words 1:1 Listener to button)
...and perhaps more ways will be added in the comments section below.
you already keep a track of the buttons by the array index i.e. buttray[i]. Use getSource()
public void actionPerformed(ActionEvent e)
{
// TODO Auto-generated method stub
for(int i=0;i<buttray.length;i++)
if(e.getSource()==buttray[i])
{
//code here
}
}
Related
I am a bit confused regarding a situation I have. I created a ListModel extending DefaultListModel and ListRenderer implementing ListCellRenderer for displaying a custom cell in a JList. The cells are some objects created from a class extending JPanel, that contain a JLabel and a JButton.
My issue is related to the mouse events: I want to trigger a certain event when clicking on the JButton inside a cell of the JList, yet I can not figure out how to match the mouse source point to that of the JButton from the respective index. More exactly, I added a mouse listener to the list, but I want it to trigger something if the mouse point is located inside the bounds of the JButton, and another action if it's on the data item. I added some prints to find out the cause of this, but before that some code to highlight the structure:
public WifiGuiHandler(JButton reference) {
btnReference = reference;
wifiListener = new WifiListener();
wifiPopupContainer = new JScrollPopupMenu("Connections.");
wifiPopupContainer.setMaximumVisibleRows(7);
connectionsHolder = new ArrayList<>();
listOfConnections = new JList();
listOfConnectionsModel = new ListModel(connectionsHolder);
listOfConnectionsRenderer = new ListRenderer();
listOfConnections.setModel(listOfConnectionsModel);
listOfConnections.setCellRenderer(listOfConnectionsRenderer);
wifiPopupContainer.add(listOfConnections);
wifiPopupContainer.pack();
initializeTestVariables();
initializeListeners();
}
Here, the constructor for the class that takes a JButton and adds a mouse listener to it, that triggers the appearance of a JPopupMenu, which has only one component, the JList that hold the entire data. Also, links the ArrayList with the data items to the ListModel.
public void initializeTestVariables() {
for (int i = 0; i <= 10; i++) {
WifiItem item = new WifiItem("Connection number " + i + ".", i);
connectionsHolder.add(item);
}
}
Setting up the data items.
public void initializeListeners() {
listOfConnections.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int index = listOfConnections.locationToIndex(e.getPoint());
if (index >= 0) {
WifiItem item = (WifiItem) ((ListModel) listOfConnections.getModel()).getElementAt(index);
System.out.println("Button of " + item.getConnectionName() + " is at location :" + item.getButton().getLocation());
System.out.println("Button has the bounds : " + item.getButton().getBounds());
System.out.println("MouseEvent detected on : " + e.getPoint().getLocation());
if (item.getButton().getBounds().contains(e.getPoint())) {
item.connectHere();
}
if (item.getButton().isVisible()) {
System.out.println("Set expanded on : " + item.getConnectionName());
item.setExpandedState(false);
listOfConnectionsModel.fireContentsChanged(item, index, index);
updateGui(false);
} else {
System.out.println("Set expanded on : " + item.getConnectionName());
listOfConnectionsModel.fireContentsChanged(item, index, index);
item.setExpandedState(true);
updateGui(false);
}
}
}
});
btnReference.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
updateGui(true);
}
});
}
And this is where the confusion arises. I correctly get the data item( WifiItem) from the mouse event location/point, but when I click on the JButton of the WifiItem, it doesn't trigger that method, like it doesn't seem to detect that the JButton actually is there. I also set up the prints, and what is strange, the Point for the JButton is always the same, even though it actually is different, and this seems to be the problem. More exactly, from the output of the program:
Button of Connection number 2. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
Button of Connection number 3. is at location :java.awt.Point[x=137,y=33]
Button has the bounds : java.awt.Rectangle[x=137,y=33,width=90,height=26]
MouseEvent detected on : java.awt.Point[x=172,y=125]
The above mouse events points were actually located on the JButton itself, only it didn't get that. As another strange fact, only if I click the JButton of the FIRST element of the list does it trigger the required mouse action.
Another print revealed that all the JButtons have the same Point and Rectangle, and I don't get it. There are 10 items in the JList, each displayed properly, how can all their JButtons have the same location? I must be missing some key element here. I looked at other posts and tried other recommendations: converting the point with SwingUtilities, removing all the mouse listeners from the JList and adding them to the data items.
To sum it up,the issue is that the list triggers the events for the correct data item in it(meaning, I do get the correct index for the item located there), but if the mouse event happens on the JButton of any data item inside the list, it doesn't trigger the required effect (the point is not withing the bounds of the button, even though it should be).
More exactly, I added a mouse listener for the list, but I want it to trigger something if the mouse point is located inside the bounds of the JButton, and another action if it's on the data item.
An easier solution would be to use a JTable. The data is separated into columns and the JTable has an API to let you know which row/column was selected.
You can use the Table Button Column as your renderer/editor for the button.
Edit:
only if I click the JButton of the FIRST element of the list does it trigger the required mouse action
Sounds like your conversion of the mouse point is off.
, how can all their JButtons have the same location?
Again, the button location is releative to the renderer panel. The panel itself is relative to the row in the JList. So I would guess you need to need the row index and add the height of each of the previous rows to your calculation.
I have met a serious problem with my Java swing.
This is how I initialize my chart, everything seems fine now, xyChartPanel is declared as a JPanel in the field, I initialize it with the xyChart I just created. When this step is done, I am okay to see the chart (painted to xyChartPanel) centered to the JPanel I am writing code on, see add(xyChartPanel, BorderLayout.CENTER);.
private void initXYChart() {
// Create Chart
xyChart = new XYChartBuilder().width(800).height(800).xAxisTitle(xColName).yAxisTitle("Y").build();
// Customize Chart
xyChart.getStyler().setLegendPosition(LegendPosition.InsideNE);
xyChart.getStyler().setAxisTitlesVisible(true);
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Line);
double[] yCoordArray = new double[xCoordArray.length];
// Loop through the series
for (int i = 0; i < yCoordinates.size(); i++) {
List<Double> yCoordOneSeries = yCoordinates.get(i);
// Convert list to array
for (int j = 0; j < yCoordArray.length; j++) {
yCoordArray[j] = yCoordOneSeries.get(j);
}
xyChart.addSeries(yColNames.get(i), xCoordArray, yCoordArray);
}
xyChartPanel = new XChartPanel<>(xyChart);
add(xyChartPanel, BorderLayout.CENTER);
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Area);
add(xyChartPanel, BorderLayout.CENTER);
}
Now the problem comes, I don't want my chart to be unchanged all the time, actually I want to change the style of my chart responded to my action on the radio buttons.
I just wrote the updateChartPanelStyle(JRadioButton styleButton) method that takes
private void updateChartPanelStyle(JRadioButton styleButton) {
String style = styleButton.getText();
if (styleButton.isSelected()) {
System.out.println(style);
switch (style) {
case "Line":
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Line);
break;
case "Area":
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Area);
break;
case "Scatter":
xyChart.getStyler().setDefaultSeriesRenderStyle(XYSeriesRenderStyle.Scatter);
}
xyChartPanel = new XChartPanel<>(xyChart);
add(xyChartPanel, BorderLayout.CENTER);
}
}
See in this method, I changed the style of xyChart I initialized in the last function, and reinitialize the xyChartPanel, then add the updated xyChartPanel to the working panel. Interestingly, I didn't see any change in my GUI. I thought this might be a problem with my xyChart whose style could not be changed afterward. But this is not really the case.
Even if I "removed" xyChartPanel with this.remove(xyChartPanel);, the GUI doesn't seems to be changed.
This is really weird, what should I do now?
Every time you add/remove components to swing dynamically, you need to call revalidate(); and then repaint(); on your JPanel (or JFrame if you're adding it straight to that).
How I can control the actionListener of two JButtons pressed one after another?
I have got 2 JPanels. In each JPanel I've got a matrix of JButtons named tUsuari and tUsuariCPU
void actionPerformed(ActionEvent){
/****//
for (int i=0;i<tUsuari.length;i++){
for (int j=0;j<tUsuari.length;j++ ){
if (e.getSource()==tUsuari[i][j]){
System.out.println("hello");
for (int r=0;r<tUsuariCPU.length;r++){
for (int s=0;s<tUsuariCPU.length;s++ ){
if (e.getSource()==tUsuariCPU[r][s]){
System.out.println("bye");
parent.provaAtac(i,j,r,s);
}
}
}
}
}
}
}
When I pressed the JButton from the tUsuari it prints "hello", then I pressed a JButton from the other panel ant it doesn't print "bye".
Why so many nested loops? Split in 2 parts and fill panels individually... also, what is doing the method: parent.provaAtac(i,j,r,s); ?
for (int i=0;i<tUsuari.length;i++){
for (int j=0;j<tUsuari.length;j++ ){
if (e.getSource()==tUsuari[i][j]){
System.out.println("hello berlin");
}
}
}
for (int r=0;r<tUsuariCPU.length;r++){
for (int s=0;s<tUsuariCPU.length;s++ ){
if (e.getSource()==tUsuariCPU[r][s]){
System.out.println("bye madrid");
}
}
}
Your logic is wrong. If e.getSource()==tUsuari[i][j], yes, you indeed print out "Hello". But if that condition is true, there's no way that e.getSource()==tUsuariCPU[r][s] can be true, since e.getSource can't be both your tUsari button and your tUsuariCPU button at the same time. Conversely, if you presss the CPU button, you'll fail the first check for it being the tUsuari button, and therefore never get to the check for the CPU button. I suggest creating two different actionListeners, one for each button that does what you want the particular button to do.
I have a JFrame extended class that implements a multi-tab chat. Every tab is a chat with someone or with a group of people. What I have implemented works fine, except when I assign a ToolTipText to the label of a tab. In this case I can't click anymore (and select) the tab that has a ToolTipText assigned. The others work fine.
Graphical example:
As you can see the tabs are properly being added, and the first two tabs ("Gruppo prova" and "Gruppo test") have a ToolTipText, the other two don't. I can switch between the last two, but I can't do the same with the first two. I thought that the icon next to the label could be a problem, but I removed it and still doesn't work. However I can still click all the 'X' (close) buttons (working properly).
This is a piece of the code I used to add a tab:
// Some stuff...
JChat chat = new JChat(gui.chatClient, email, name, group);
jTabbedPane.add(email, chat); // I instantiated this before
int index = jTabbedPane.indexOfTab(email);
JPanel pnlTab = new JPanel(new GridBagLayout());
pnlTab.setOpaque(false);
// Core function
JLabel lblTitle;
if (group == 1) {
// If it's a group and not a single chat I assign a name, an icon and a ToolTipText to the tab
lblTitle = new JLabel(name, icon, JLabel.LEFT);
lblTitle.setToolTipText(membersList.toString());
} else {
// otherwise I only assign a name to the tab
lblTitle = new JLabel(name);
}
jTabbedPane.setTabComponentAt(index, pnlTab);
// This applies the 'X' (close) button next to the tab name
CloseButton btnClose = new CloseButton(this, jTabbedPane, tabs, email);
lblTitle.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
pnlTab.add(lblTitle);
pnlTab.add(btnClose);
Is this a Swing bug or am I doing something wrong?
you can use :
void setToolTipTextAt(int, String) to set tool-tip text to specific tab.
void setIconAt(int index, Icon icon) to set the icon to specific tab.
No need to use JLabel for setting tool-tip text or icon.
The above solution, however doesn't however answer your question:
except when I assign a ToolTipText to the label of a tab. In this
case I can't click anymore (and select) the tab that has a ToolTipText
assigned
The only reason i am suspecting:
JLabel doesn't register to any mouse listener by default. When no mouse listener is set to JLabel any mouse clicked event will go through to the UI objects underneath: in this case the JTabbedPane. But when we are setting tool-tip text using setToolTipText(text), the ToolTipManger adds a mouse listener to this JLabel, which will continue to consume the mouse click event.
Check the following code snippets demonstrating the issue and providing a work around setSelectedIndex function:
JLabel label = new JLabel("a Label");
System.out.println(label.getMouseListeners().length); // length is printed as 0
label.setToolTipText("Danger: setting tool tip will consume mouse event");
System.out.println(label.getMouseListeners().length); // length is printed as 1
jTabbedPane1.setTabComponentAt(0, label);
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int index = jTabbedPane1.indexOfTabComponent((Component)e.getSource());
jTabbedPane1.setSelectedIndex(index);
}
});
I have a JTextField represents a day in a week, such as "Friday", when I click on it, I want to have a choice such as "1st of month, 3rd of month or last of month", so I came up with two options :
<1> Hold down a number or letter, let's say "2" or "L", then click on "Friday" means 2nd (or last) Friday of the month, in this case, how to get the number while mouse clicks on the JTextField ?
<2> Right mouse click on the "Friday" JTextField, drop down a menu, with either buttons or checkboxes that let me choose, then close the menu and get the value.
My code look like this so far :
private final JTextField[] dayHeadings=new JTextField[]{new JTextField("Su"),
new JTextField("Mo"),
new JTextField("Tu"),
new JTextField("We"),
new JTextField("Th"),
new JTextField("Fr"),
new JTextField("Sa")};
......
for (int ii=0; ii < dayHeadings.length; ii++)
{
dayHeadings[ii].setEditable(false);
dayHeadings[ii].setFocusable(false);
dayHeadings[ii].addMouseListener(new MouseAdapter() { public void mouseClicked(final MouseEvent evt) { onHeadingClicked(evt); } });
add(dayHeadings[ii],new AbsoluteConstraints(x,38,X_Cell_Size+1,Y_Cell_Size+1));
}
......
void onHeadingClicked(final java.awt.event.MouseEvent evt)
{
final javax.swing.JTextField fld=(javax.swing.JTextField) evt.getSource();
...
}
How to do either of the above, are they doable in Java ?
getModifiers is actually that what I needed. a sample for the modifiers can be found
here
Option 1:
There is no way to do this in one step. You would need to add a KeyListner to track whenever a key is pressed and then save the character value. Then you would need to add a MouseListener to listener for mousePressed events. When the mousePressed event fires you would need to to check which character is saved and then do your processing. Therefore your listener would to implement both the KeyListener and MouseListener interfaces.
Option 2:
You need to add a mouse listener and listen for a right mouse click, then display a popup menu.
I think option 2 is more intuitive and more easily done. Its always easier to work with one hand then be forced to use two hands.
Another, lazier way to do it would be using getModifiers() on the mouseclick event. It shows which modifier keys (ctrl, alt, shift, etc), if any, were pressed during the mouse click. Using these buttons isn't as intuitive as a drop down menu or numbers in my opinion, but could work.
Read more here