I'm working with Netbeans IDE in Java.
I've a form with one JPanel.
Each JPanel has a gridLayout 3x3 and in each place there is an image representing a number[0,1,2,3,4,5,6,7,8](the image is created used a custom class,not just fitting the image in a lab).
I want to be able to exchange two images in the panel when the user click them (First click: no action , second click: switch the two images fitted in the jPanel Components).
I already created a function exchangeComponents and with a test code (like:
exchangeComponents (0,8,jPanel1)
it exchanges correctly the images located in position1 (1st row,1st column) and in position2 (3rd row,3rd column).
The function a creted is the following:
public void exchangeComponents(int component1,int component2,JPanel jpanel){
try{
Component aux1 = jpanel.getComponent(component1);
Point aux1Loc = aux1.getLocation();
Component aux2 = jpanel.getComponent(component2);
Point aux2Loc = aux2.getLocation();
aux1.setLocation(aux2Loc);
aux2.setLocation(aux1Loc);
}
catch (java.lang.ArrayIndexOutOfBoundsException ex){ /* error! bad input to the function*/
System.exit(1);
}
}
I suppose I neeed to have an event that call the function exchangeComponents() when the user click on one of the images on the jPanel1 but how should I do it? and how to check what components (images) the user has selected?
I just know that when I create a Button if a click on it (from the IDE) an event like
private void button1ActionPerformed(java.awt.event.ActionEvent evt) {
// some code..
}
is created and the code I fill in is executed.
Thank you in advance for any hint.
You need to add the same mouse listener to all you JLabels or whatever container you have for your images, like:
img1.addMouseListener(this);
img2.addMouseListener(this);
etc., then detect which Jlabel you clicked with MouseEvent.getSource(); , like this
boolean hasclicked1=false;
JLabel click1label=null;
public void mouseClicked(MouseEvent me){
if(!hasclicked1){ //clicked first pic
hasclicked1 = true;
click1label = (JLabel) me.getSource();
} else { //clicked second pic
hasclicked1 = false;
exchangeComponents(click1label, (JLabel) me.getSource(), /*your jpanel here*/);
}
//now change exchangeComponents so it uses JLabels as parameters
public void exchangeComponents(JLabel component1, JLabel component2, JPanel jpanel){
try{
Component aux1 = component1;
Point aux1Loc = aux1.getLocation();
Component aux2 = component2;
Point aux2Loc = aux2.getLocation();
aux1.setLocation(aux2Loc);
aux2.setLocation(aux1Loc);
} catch (java.lang.ArrayIndexOutOfBoundsException ex) { /* error! bad input to the function*/
System.exit(1);
}
}
If you are not using JLabels for the images though, replace JLabel in the code with whatever you are using...
EDIT: Sorry, I don't think I made this unclear, but your class with the method exchangeComponents has to implement MouseListener. Then, in the mouseClicked event put the code I gave for it. Make sure to include the variables hasclicked1 and click1label in your class. Make you class something like this
public class ComponentExchanger implements MouseListener {
boolean hasclicked1=false;
JLabel click1label=null;
JPanel mainPanel;
public ComponentExchanger(){
//create JFrame, JPanel, etc.
JFrame f=new JFrame();
//etc.
mainPanel=new JPanel();
f.add(mainPanel);
//set layout of panel, etc.
for(int i=0;i<9;i++){
JLabel l=new JLabel(/*label image here*/);
Point loc=new Point(/*coordinates here*/);
l.setLocation(loc);
mainPanel.add(l);
/*more code*/
f.setVisible(true);
}
}
public static void main(String args[]){
new ComponentExchanger();
}
public void mouseClicked(MouseEvent me){
if(!hasclicked1){ //clicked first pic
hasclicked1 = true;
click1label = (JLabel) me.getSource();
} else { //clicked second pic
hasclicked1 = false;
exchangeComponents(click1label, (JLabel) me.getSource(), mainPanel);
}
//now change exchangeComponents so it uses JLabels as parameters
public void exchangeComponents(JLabel component1, JLabel component2, JPanel jpanel){
try{
Component aux1 = component1;
Point aux1Loc = aux1.getLocation();
Component aux2 = component2;
Point aux2Loc = aux2.getLocation();
aux1.setLocation(aux2Loc);
aux2.setLocation(aux1Loc);
} catch (java.lang.ArrayIndexOutOfBoundsException ex) { /* error! bad input to the function*/
System.exit(1);
}
}
//Also, you will need to include the other mouselistener implemented methods, just
//leave them empty
}
First of all, to be technical it's methods not functions.
There are a couple of ways you could do this. You could go ahead with actionListener, but then you would probably need buttons or something.
Or you could use MouseListener, and detect clicks over a certain region of the panel.
For the switching algorithm, perhaps an array of 2 images. There is a variable that increases by 1 every click. When the variable is 2, it resets back to 0.
clicks++; //every time the mouse is clicked; clicks starts out at 0
if(clicks == 2){
clicks = 0; //at the end of the listener method
}
On the first click the clicked image goes into the first array slot, because the user has clicked once.
clickImage = imageArray[clicks];
On the second click, the other clicked image goes to the second array slot, because 2 clicks have been detected. In this case, your exchangeComponents method would go at the end of the listener method, with the arguments being imageArray[1], imageArray[2], .
You can apply this to ints or whatever, just save the value in an array and use an incrementing and resetting variable.
Related
I got 2 array,for color and button
private JButton[] buttons = new JButton[16];
private Color[] c={
Color.red,Color.yellow,Color.black,Color.magenta,
Color.blue,Color.green,Color.cyan,Color.pink,
Color.green,Color.black,Color.red,Color.pink,
Color.magenta,Color.blue,Color.cyan,Color.yellow
};
and the Layout is
DrawingPanel c=new DrawingPanel();
c.setLayout(new GridLayout(4,4));
when I clicked 2 button,the 2 button will be remove, then how can I check the 2 color(the color is on button back) is match or not?
public class bl implements ActionListener{
public void actionPerformed(ActionEvent e){
Component c = (Component)e.getSource();
Color c1=Color.black,c2=Color.black;
if(clickCount == 2){
c.hide();
c1 = c.getBackground();
clickCount--;
}if(clickCount ==1){
c.hide();
c2 = c.getBackground();
clickCount--;
}
if(clickCount == 0 ){
if(bx == by){
System.out.println("Corret");
clickCount=2;
}
}else{
c.show();
}
}
}
Full code
You could extend the Button class to be able to hold a record of its colour and then get it each time to compare.
The button needs to keep a record of what colour it has, or something has to anyway.
General advice bro:
1. Give your variables meaningful names:
DrawingPanel c=new DrawingPanel();
c.setLayout(new GridLayout(4,4));
This is way better and makes your code far easier to read:
DrawingPanel drawingPanel = new DrawingPanel();
drawingPanel.setLayout(new GridLayout(4,4));
It never hurts to add descriptive comments everywhere as well, makes code far easier to read.
To extend Button you could go something like this:
public class ColourButton extends JButton{
private final String colourOfButton;
public ColourButton(String colourOfButton){
this.colourOfButton = colourOfButton;
}
public String getColour(){
return colourOfButton;
}
}
Then use something like this to check for colour matches:
public boolean hasColourMatch(ColourButton colourButton1, ColourButton colourButton2){
if(colourButton1.getColour().equals(colourButton2.getColour())){
return true;
}
return false;
}
Hope this helps..
I am attempting to use a forloop to be able to change which jlabel is being affected, as for they all perform the same function, and have the same name other than the numerical value at the end of each name.
Essentially, I use a drag and drop transfer handler to create a food web game. I want to randomize the game to three different food webs that may appear. The randomization is fine and all, but I am unknowledgable of how to use a loop to determine which JLabel's icon is being set. Since I am using generally all the same name for each individual JLabel that has an icon that will change based on which themed food web was randomly selected, I am wanting to know how to make the loop change which JLabel is being selected, as for I get a syntax error from attempting to do the "selection(i+1)".
private static int randomNumber(){
return(int) (Math.random() * (3 - 1 + 1) + 1);
}
private void generateQuiz(){
switch(randomNumber()){
case 1: //the for loop changes each available selection based on each element in the foor loop.
for(int i = 0; i < consumers1.size(); i++){
selection(i+1).setIcon(new ImageIcon(getClass().getResource(
"/resources/quiz/"+consumers1.get(i)+".png")));
}
break;
case 2:
break;
case 3:
break;
want: change each of these selection boxes auto-magically using a for loop rather than typing each individual thing manually for each case
EDIT: This is the rest of the general code around this problem,
private String[] producers = {"grass", "plankton", "berries"};
private ArrayList<String> consumers1 = new ArrayList();
private ArrayList<String> consumers2 = new ArrayList();
private ArrayList<String> consumers3 = new ArrayList();
//mouselistener to handle all image move-ability
MouseListener mouseListener = new MouseListener() {
#Override public void mouseClicked(MouseEvent e) {}
//a mouselistener for that each img has the ability to be moved into spots
#Override
public void mousePressed(MouseEvent e) {
JComponent jc = (JComponent)e.getSource();
TransferHandler th = jc.getTransferHandler();
th.exportAsDrag(jc, e, TransferHandler.COPY);
// System.out.println(producers1.getIcon());
}
#Override public void mouseReleased(MouseEvent e) {}
#Override public void mouseEntered(MouseEvent e) {}
#Override public void mouseExited(MouseEvent e) {}
};
/**
* Creates new form Quiz
*/
public Quiz() {
initComponents();
//sets the jframe to the center of the screen
setLocationRelativeTo(null);
//changes how the jframe closes
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent windowEvent) {
//confirm dialog to ensure user wants to close, if not return
int confirm = JOptionPane.showConfirmDialog(null,
"A quiz is currently inprogress. "
+ "\nAll unsubmitted quizs will not be saved!"
+ "\nDo you wish to exit?",
"Exit",
JOptionPane.YES_NO_OPTION);
if (confirm == JOptionPane.YES_OPTION){
System.exit(0);
}
}
});
//random algorithm; t1 = x, tn = (tn-1) + xn
//<--- RANDOM QUIZ GENERATION --->
//add all the image names to array lists
Collections.addAll(consumers1, "goat", "rabbit", "jackal", "wildcat",
"lion");
Collections.addAll(consumers2, "fish", "mussel", "bird", "octopus",
"human");
Collections.addAll(consumers3, "butterfly", "grasshopper", "frog",
"spider", "snake");
generateQuiz();
// end of quiz generaiton
//<--- DRAG AND DROP ADDITIONS LISTENERS AND TRANSFER HANDLERS --->
//adds mouse listener to be able to drag and drop the imgs in the seleciton boxes
selection1.addMouseListener(mouseListener);
selection2.addMouseListener(mouseListener);
selection3.addMouseListener(mouseListener);
selection4.addMouseListener(mouseListener);
selection5.addMouseListener(mouseListener);
selection6.addMouseListener(mouseListener);
//creates transfer handlers to bea ble to drag and drop the images in the frame
TransferHandler th = new TransferHandler("icon");
selection1.setTransferHandler(th);
selection2.setTransferHandler(th);
selection3.setTransferHandler(th);
selection4.setTransferHandler(th);
selection5.setTransferHandler(th);
selection6.setTransferHandler(th);
producer.setTransferHandler(th);
consumer1.setTransferHandler(th);
consumer2.setTransferHandler(th);
consumer3.setTransferHandler(th);
consumer4.setTransferHandler(th);
consumer5.setTransferHandler(th);
//<--- END OF DRAG AND DROP ADDITIONS LISTENERS AND TRANSFER HANDLERS --->
}
private static int randomNumber(){
return(int) (Math.random() * (3 - 1 + 1) + 1);
}
private void generateQuiz(){
switch(randomNumber()){
case 1:
for(int i = 0; i < consumers1.size(); i++){
selection(i+1).setIcon(new ImageIcon(getClass().getResource(
"/resources/quiz/"+consumers1.get(i)+".png")));
}
break;
case 2:
break;
case 3:
break;
}
}
P.S.: It's made in netbeans gui builder for a school assignment so it'x declared in the automatic generated code by neatbeans
Ah, "selection..." is simply a variable name.
When the Java program is compiled, most variable names are replaced by pointers to memory locations, so you can't assemble a string at run time and invoke the corresponding variable. (You could make them public and use Reflection but it would be absolutely wrong here).
Here the simplest way to do what you are trying is the following:
JLabel[] selections={
selection1,
selection2,
selection3,
selection4,
selection5,
selection6
};
and then use selections[i] instead of selection(i+1).
I have a JButton[][] array that stores every button on a grid.
What I want to do is :
1) click the jbutton(icon) that I want to move on the grid.
2) click on the jbutton that I want the previous selected jbutton(icon) to move to.
private class BListener implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
JButton but = ((JButton) e.getSource());
if(iconSelected && !but.equals(selectedButton)){ // move(swap) buttons
but.setIcon(selectedButton.getIcon());
selectedButton.setBorder(BorderFactory.createLineBorder(Color.black));
selectedButton.setName(null);
selectedButton=but;
iconSelected=false;
}else if(!iconSelected && but.getName()!=null){
iconSelected=true;
selectedButton=but;
but.setBorder(BorderFactory.createLineBorder(Color.YELLOW,3));
}else{
if(iconSelected){
System.out.println("Already Selected");
}else{
System.out.println("Not selected");
}
}
}
I have tried some things that didnt work ( this moves the icon but the icon also remains at the starting location). Any insight would be helpfull.
That is because you never change the selectedButton's icon, Try this:
if(iconSelected && !but.equals(selectedButton)){ // move(swap) buttons
Icon bIcon = but.getIcon();
but.setIcon(selectedButton.getIcon());
selectedButton.setIcon(bIcon);
...
}
I'm writing a simple paint program with Java. As all paint applications there are buttons for brushTool, sprayTool, sprayTool... This tools have their own class which extends to MouseAdapter. They are working as they should. However, the problem starts when I choose a tool after choose another tool, both buttons and their ActionListeners keep executing and they do what they are written for at the same time. I mean if I choose lineTool(which draws straight line) with rectangleTool I hava a diagonal too. here is example of my two button. What I'm tring to do is stop the current action when I click another button. Can you guys help me
brushBotton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
pen = new PenTool(mainDrawArea);
mainDrawArea.addMouseListener(pen);
mainDrawArea.addMouseMotionListener(pen);
}
});
rectangleButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
shapeToolbar.setVisible(false);
rect = new RectangleTool(mainDrawArea);
rect.setStrokeSize(strokeInt);
mainDrawArea.addMouseListener(rect);
mainDrawArea.addMouseMotionListener(rect);
}
});
You can't keep adding a MouseListener to the drawing area every time you click a button.
Instead you need to keep track of the current MouseListener. Then when you click a button you need to:
remove the current MouseListener
add the new MouseListener
I would replace the button action listener for a set of Toggle Buttons in a group
https://docs.oracle.com/javase/tutorial/uiswing/components/buttongroup.html
Then you move everything in a single mouse listener.
public void mousePressed(MouseEvent e) {
this.drawingState = !this.drawingState
if ( isRightCLick(e) ) resetAllPendingOperation();
if (drawingState) {
this.startPoint = getPointFromEvent(e);
switch(toolbarGetCurrentTool()) {
case "line":
registerMouseLineListener(startPoint);//here you draw live preview
break
case "rectangle":
registerMouseRectangleListener(startPoint); //here you draw live preview
break;
}
} else {
//user clicked the second time, commit changes
//same switch as above
this.endPoint = getPointFromEvent(e);
switch(toolbarGetCurrentTool()) {
case "line":
commitLine(startPoint, endpoint);//here you draw live preview
break
case "rectangle":
commitRectangle(startPoint, endpoint); //here you draw live preview
break;
}
}
}
You are currently binding the listeners to the mainDrawArea, not setting an action for each individual button.
Note that the codes you write within actionPerformed() for each button's actionListener is the action you want to trigger everytime that button is clicked. You do not want to add a new listener to the mainDrawArea everytime we click the buttons.
You can a create a state for your current action, for example:
brushBotton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
state = BRUSH;
}
});
lineBotton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
state = LINE;
}
});
state can be an integer and BRUSH and LINE are constant such as 0 and 1.
Then in the listener (for the mainDrawArea), check the current state
switch (state){
case BRUSH: //trigger action needed for brushing;
break;
case LINE: //trigger action needed for drawing line;
break;
}
I´m trying to implement an undo (and redo) function for an editable JTable with the default components. The JTable has an extra class to specify its properties called SpecifiedJTable.
To do so I wanted to grab the moment when a cell is doubleclicked (i.e. the moment when a cell is chosen/marked to be edited) to push the information in the cell and its coordinates onto the stack.
This should be done by a MouseListener ...at least that was my idea.
I tried this (standing in the constructor of my SpecifiedJTable class)
class JTableSpecified extends JTable {
private static final long serialVersionUID = 1L;
private int c; // the currently selected column
private int r; // the currently selected row
public JTableSpecified(String[][] obj, String[] columnNames) {
super(obj, columnNames); // constructs the real table
// makes that you can only select one row at a time
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// makes that columns are not squeezed
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// forbids to rearrange the columns
getTableHeader().setReorderingAllowed(false);
// adds action listener
this.getModel().addTableModelListener(new TableModelListener() {
public void tableChanged(TableModelEvent e) {
r = getSelectedRow();
c = getSelectedColumn();
// get the String at row r and column c
String s = (String) getValueAt(r, c);
if (jobDisplayed) jobSwitch(c, s);
else resSwitch(c, s);
}
});
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println("test");
}
}
});
}
}
but somehow the clickCounter doesn´t want to reach anything that´s higher than 1.
I am glad about any answer and help. Thanks.
The problem you are experiencing is related to use of mouseClicked() rather than using mousePressed(). In this case it appears to be very hard to increase the click counter, yet still it is possible. It took me lots of clicking and also mouse movement to increase the click counter over 1. You could try it by yourself, in your code. To get the counter over 1 you need to go crazy on the mouse by pressing & releasing fast while moving the mouse from cell to cell at the same time (or maybe I was just luckily clicking between the cells?).
As you can see in this fully working sample, made from your code, two mouse presses, using the mousePressed() method are being detected just fine.
public class JTableSpecified extends JTable {
private static final long serialVersionUID = 1L;
public JTableSpecified(String[][] obj, String[] columnNames) {
super(obj, columnNames); // constructs the real table
// makes that you can only select one row at a time
this.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
// makes that columns are not squeezed
this.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// forbids to rearrange the columns
getTableHeader().setReorderingAllowed(false);
// adds action listener
this.getModel().addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
}
});
this.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getClickCount() == 2) {
System.out.println("test");
}
System.out.println("e.getClickCount() = " + e.getClickCount());
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JPanel panel = new JPanel();
panel.add(new JTableSpecified(new String[][]{{"oi", "oi2"}, {"oi3", "oi4"}}, new String[]{"Col1", "Col2"}));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
f.pack();
f.setVisible(true);
}
});
}
}
Conclusion: Maybe you in fact want to use the mousePressed() method?
This answer extends Boro´s answer.
To catch every case that enables the user to edit the table I will also need to add a KeyListener for F2 (which has the same effect as double clicking onto a cell) and disable the automatic cell editing by pressing any key.
I just added it to the constructor right behind the mouseListener (see above)
// forbids the editing by striking a key
this.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
// keyListener to react on pressing F2 (key code 113)
this.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 113) System.out.println("test");
}
});
The BasicTableUI is responding to the double-click by going into an edit mode on the cell that was double-clicked. It does lots of complicated stuff, part of which involves creating a JTextField (or other component) to allow the data to be edited, and then preventing the mouse click event from propagating any further.
If your table, or that table cell, is not editable, you can easily capture mouse events with click count 2, 3, 4, .... But since you want your table to be editable, you need a different approach.
One idea would be to override JTable.editCellAt()
A better idea is to forget about messing with the JTable and instead listen for data changes on the table model itself.
the error in the code is that the mouseClicked method is called as soon as the first click takes place. when a double click takes place the mouseClicked method is called again. you can place a static variable (or a class variable) for the earlier click event storing the time (using the e.getWhen() method).
Check for the time difference and if it's small enough, execute your actions (I'd suggest calling a doubleClick method).
you may have to implement mouse listener in your class JTableSpecified since a static variable might not be placed in your existing code.