Java JFrame MouseListener - java

I have a JFrame with small squares set as background. Squares are pictures.
Amount of squares depends on JFrame size, so I use ArrayList and I add JLabels to JFrame using:
for(int i = 0; i < squares.size(); i++){
add(squares.get(i));
}
I want to write a method so when mouse enters square it would change its color.
I have implemented MouseListener. However this does not work(it works with normal JLabels):
ArrayList<JLabel> squares = new ArrayList<JLabel>();
.
.
.
#Override
public void mouseEntered(MouseEvent e) {
Object source = e.getSource();
if(source == squares){
System.out.println("AAA");
}
if(source == squares.get(0)){
System.out.println("BBB");
}
}
My question: How do I get element out of ArrayList, so I could set it equal to source and if its equal to source do something?

However this does not work(it works with normal JLabels):
This statement does not make sense. A JLabel is a JLabel. As long as you add the label to the frame it should work. The fact that you created an ArrayList as well doesn't affect how the label works on the frame.
Object source = e.getSource();
You already have the source, so all you need to do is cast it to a JLabel:
JLabel enteredLabel = (JLabel).getSource();
enteredLabel.doSomething(...)

Related

JButton is drawn partially outside of window despite bounds being within size

I am a student trying to figure out the basics of Java's graphics. My class creates a window where a single red button will move every time it is pressed. I set the bounds of the window to 720x720 and the button is 50 pixels wide. Everytime it is pressed, the button goes to a new x and y coordinate that is between 0 and 670. My understanding is that if the setBounds() method is called with the parameters (670,670,50,50) then my red button will occupy the bottom right corner of the window.
Unfortunately, the button seems to be going outside of the window even when the bounds are set to something like (660,660,50,50).
Problem
I have tried tracking the bounds by printing every change in coordinates but this still does not add up.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Custom extends JPanel
{
//fields
private int kovakx = 0, kovaky = 0; //stores x and y coordinates of the button
private double accuracy_percent = 100; //not used yet
private JButton kovak = new JButton();
//Only ActionListener this program needs since theres only one button that moves around the screen.
private class Elim implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
kovakx = (int)(Math.random()*670);
kovaky = (int)(Math.random()*670);
kovak.setBounds(kovakx,kovaky,50,50);
System.out.println(kovakx+","+kovaky);//prints out the new coordinates of the button
}
}
//Constructor sets icon and initally puts the button in the top left corner
public Custom()
{
kovak.setIcon(new ImageIcon("Target.png"));
setLayout(null);
kovak.setBounds(0,0,50,50);
kovak.addActionListener(new Elim());
add(kovak);
}
//Creates frame based on teacher's tutorials.
public static void main(String args[])
{
Custom a = new Custom();
JFrame f = new JFrame("Reaction and Accuracy Test");
f.setSize(720,720);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(a);
f.setVisible(true);
}
}
You set the frame size, but are never setting the size on Custom. If you call getSize() on Custom, it returns (0,0). So what is happening I think is that the frame really is (720,720) in size, but that includes the area of the decorations (such as title bar) and frame borders. The effective area inside the frame is smaller, which is why you cannot see the entire button.
The solution is either to determine the actual area inside the frame, or to adjust the frame so that the area inside is (720,720).
To adjust the frame so the inner size is (720,720), the usual way is to set the component size and then pack the frame:
In main,
f.add(a);
a.setPreferredSize(720,720); // set desired size of JPanel
f.pack(); // resize frame to fit around its contents
f.setVisible(true);
It is not necessary to call frame.setSize() if you are calling pack(), because pack will set the size automatically. Note that it you call pack without calling setPreferredSize(), the frame will be a tiny zero-size frame that may be hard to see. If you run the program and don't see anything that is the likely problem.
Getting the frame size without the decorations is a little more complicated. See the part about getInsets() in JFrame: get size without borders?

Java Swing Icon not appearing

I'm trying to create a piece of code that displays either a smiley face or a sad face when a button is pressed, depending on some value, but it just won't display the image. I know that it's definitely getting past the if/else statements, so I really don't know what is going wrong.
try {
if(data[2] <= ((int) ChronoUnit.DAYS.between(localDate, RTS()))*MnHrs())
{
JLabel lblSmiley = new JLabel(new ImageIcon("C:\\. . .\\smileyface.jpeg"));
panel.add(lblSmiley);
}
else
{
JLabel lblSmiley = new JLabel(new ImageIcon("C:\\ . . . \\sadeface.png));
panel.add(lblSmiley);
}
} catch (Exception e1) {
e1.printStackTrace();
}
It looks like you're loading the icon and adding a new label each time. Instead, you can add the label once and call setIcon() like they show here.
Icon smile = new ImageIcon("C:\\…\\smileyface.jpeg");
Icon sad = new ImageIcon("C:\\…\\sadeface.png");
JLabel lblSmiley = new JLabel();
…
frame.add(lblSmiley);
…
if (…) {
lblSmiley.setIcon(smile);
} else {
lblSmiley.setIcon(sad);
}
Depending on your layout, you may need to change the labels preferred size or add an empty label before you pack() the window.
Probably, it is getting in the panel, but due to dimensions of panel it might be getting placed off screen. Check by modifying the panel dimensions and placing the smiley within that.

How to remove the panel from the panel it attached to in Java Swing?

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).

Dynamically generated jbuttons

I'm trying to make a GUI for that simulates elevators in a building (really to test threading/c-scan), but when generating the buttons for the elevator control panel and the buttons for each individual floor, I'm kind of stuck. I thinking about trying to generate a new pair of buttons for each floor, and generating a new control panel per elevator. Also there's the difficulty of having a variable amount of floors. Anyway my question what is this best way to go about doing this? Perhaps it's not necessary to generate new buttons for everything and just use one set and change what the actions do per floor/elevator? I'm asking because I'm not very familiar with GUIs. Thanks for the help
If all the elevators, and the control panel are the same, you can use a singular method and pass in the elevator or the control panel. CustomPanel extends JPanel and has a method foo.
public void createElevatorButtons(final CustomPanel panel) {
ArrayList<JButton> buttons = new ArrayList<>(); //arraylist of buttons we can keep track of
JPanel buttonPanel = new JPanel(); //the visible component
for(int i = 1; i <= numberOfFloors;i++) {
JButton button = new JButton(String.valueOf(i)); //creates buttons for floors 1 to max
buttons.add(button);
buttonPanel.add(button);
}
panel.add(buttonPanel);
//add the action listeners
for(JButton button : buttons) {
button.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton floor = (JButton) e.getSource();
int floorNumber = Integer.parseInt(floor.getText());
panel.foo(floorNumber); //we tell the elevator/panel/whatever to do something, you will have to extend JPanel to do foo
}
});
}
}
In this case that the number of floors is variable you can create an array of buttons:
JButton[] buttons = new JButton[MAX_NUMBER_OF_FLOORS];
Then when you determine the exact of number of floors at runtime, you can go to instantiate and add the buttons:
for(int i=0; i<numberOfFloors; i++) {
buttons[i] = new JButton();
controlPanel.add(buttons[i]);
}
Something like this should work.
Assign MAX_NUMBER_OF_FLOORS a big number like 100, there should be a possible limit given by the problem.

MouseListener on multiple JLabels not working as intended

I have 5 JLabels inside a JPanel which is inside a JFrame. I am adding the JLabels using a for loop which iterates through an array of Colors:
private JLabel target;
// This is the origin of the first label added.
Point origin = new Point(10, 20);
// This is the offset for computing the origin for the next label.
int offset = 200;
for (int i = 0; i < layerColors.length; i++) {
target = createColoredLabel(layerColors[i], origin, targetIcon);
layeredPane.add(target, new Integer(i));
origin.x += offset;
}
// Create and set up a colored label with icon image.
private JLabel createColoredLabel(Color color, Point origin, ImageIcon icon) {
JLabel label = new JLabel(icon);
label.setVerticalAlignment(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setOpaque(true);
label.setBackground(color);
label.setBorder(BorderFactory.createLineBorder(Color.black));
label.setBounds(origin.x, origin.y, 175, 263);
label.addMouseListener(this);
return label;
}
This creates 5 JLabels, with the same ImageIcon assigned to each, spread horizontally across the JPanel. Each one has a MouseListener added to it but only the last label to be added triggers the event.
#Override
public void mouseClicked(MouseEvent e) {
if (e.getSource().equals(target)) {
Toolkit.getDefaultToolkit().beep();
}
}
I have a secondary issue involving a label containing an ImageIcon trailing my cursor which stops when I mouse over any of the 5 labels. I imagine it's a layer indexing issue but can't solve it.
Any help with these is much appreciated thanks!
Your mouseClicked(MouseEvent evt) method only checks to see if the event source was a single component (target) which, as Geoffrey points out, is that last label you added. Try adding this as the first line in your mouseClicked method.
System.out.println("Color: " + ((JLabel)evt.getSource()).getBackground());
Note: Untested. Hopefully Color has a nice toString() implementation.
Note 2: You may get a ClassCastException if you added the class as a mouse listener to any other component.

Categories