GridLayout Representing an ArrayList of JLabels issue - java

I'm looking for a bit of help with a problem I'm having. I am creating a GridLayout on my GUI and in each Grid there will be a JLabel. Along side this I have an ArrayList which contains images which will be displayed in each Grid.
What I am trying to do is when I click a specific grid, it will add an image from the ArrayList and place it in the grid position. What I would like is have a left click to add the item in the ArrayList and a right click to remove the item in the list.
The ArrayList and GUI code are in different classes and the ArrayList is implemented in the main method. I have tried to no avail, I cannot seem to get the grids to represent the list.
Basically I need a GridLayout to give a visual representation of an ArrayList, that can be manipulated with mouse interaction
Can anyone point me in the right direction?
Code for the Grids:
for (int i = 0; i < 12; i++)
{
JLabel assetLabel = new JLabel("Test"+(i+1));
System.out.println("assetLabel"+(i));
assetLabel.addMouseListener(new ParcelInfo(i));
assetLabel.setBackground(Color.WHITE);
assetLabel.setOpaque(true);
assetGrid.add(assetLabel);
}
Code for the items I need in the JLabel:
public class test
{
private ImageIcon img;
test(ImageIcon i)
{
this.img=i;
}
}

This is how you define a Listener for it.
public List<Image> arrayList = new ArrayList<>();
public OtherClassWithArray foo = new OtherClassWithArray();
jLabel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1) // left click
jLabel.setIcon(arrayList.get(xyz)); // access arraylist here
// jLabel.setIcon(foo.getArrayList.get(xyz); // access arrayList from other class
else // right click
// do smth here
}
});

Related

Changing colour of all buttons in netbeans

I've got 4 Buttons on my Form and a menu bar with an option to change their colours. In my code I change colour of each one individually, like this:
jButton1.setBackground(Color.cyan);
jButton2.setBackground(Color.cyan);
jButton3.setBackground(Color.cyan);
jButton4.setBackground(Color.cyan);
Which isn't a problem right now but might become one if I add more of them. So is there a way to change the colour of all present buttons at once?
You can try to create an array of jbuttons such as:
JButton[] buttonsArr = new JButton[4];
and then you can loop on the items and set color of text for all of them.
Such as:
for(int i = 0;i < 4;i++){
buttonsArr[i] = new JButton(String.valueOf(i));
// Or you can add the color such as
buttonsArr[i].setBackground(Color.cyan);
}
Another solution is to declare a Color Variable and use it as a global variable or as Enum such as:
Color globalColor = new Color(187, 157, 177);
jButton1.setBackground(globalColor);
jButton2.setBackground(globalColor);
jButton3.setBackground(globalColor);
jButton4.setBackground(globalColor);
And whenever you need to change it you can change it easily by changing it is value.
Check those links for more help:
Link_1 & Link_2
Assume you have this interface
and you want to change color of all buttons to any other color you want.
My recommendation is to create a recursive method similar to DFS algorithm that can scan all components in your interface and find all buttons even if each button is a child for another component.
Here is an example:-
private List<Component> getAllButtons(Component[] components) {
List<Component> buttons = new LinkedList();
for (Component component: components) {
if (component instanceof JButton) {
buttons.add(component);
} else {
JComponent jComponent = ((JComponent) component);
buttons.addAll(getAllButtons(jComponent.getComponents()));
}
}
return buttons;
}
This method needs to pass the parents components of the interface and it will scan each component either it's a button or not, if it's a button! it will be added to the list, if not! it will get the children's of this component and scan each one recursively until get all buttons.
Now, to call this method, you should add listeners to Button Color items. For me, i prefer to create a one action listener for all these items.
private void actionPerformed(java.awt.event.ActionEvent evt) {
String colorName = ((JMenuItem) evt.getSource()).getText();
Color color = null;
if (colorName.equals("red")) {
color = Color.RED;
} else if (colorName.equals("green")) {
color = Color.GREEN;
} else if (colorName.equals("blue")) {
color = Color.BLUE;
} else if (colorName.equals("cyan")) {
color = Color.CYAN;
}
List<Component> buttons = getAllButtons(this.getComponents());
for (Component component : buttons) {
component.setBackground(color);
}
}

Java / JavaFX getting around final or effectively final, is this a good approach?

this feels like I am cheating or doing something wrong. I am a Java student working on a simple JavaFX project.
As I loop through and create buttons in a flowPane, I was having trouble using the loop counter i inside an inner class. It's the part where I assign event handlers. I have dealt with this issue before, I get the difference between "final" and "effectively final" so I don't believe I am asking that.
It's just that creating this copy of i by using "int thisI = i" just feels wrong, design-wise. Is there not a better way to do this? I looked into lambdas and they also have the "final or effectively final" requirement.
Here's my code, any level or criticism or suggestion for improvement is welcome, thanks!
private FlowPane addFlowPaneCenter() {
FlowPane flow = new FlowPane();
flow.setPadding(new Insets(0, 0, 0, 0));
flow.setVgap(0);
flow.setHgap(0);
flow.setPrefWrapLength(WIDTH_OF_CENTER); // width of function buttons
Button centerButtons[] = new Button[NUM_BUTTONS];
ImageView centerImages[] = new ImageView[NUM_BUTTONS];
for (int i=0; i < NUM_BUTTONS; i++) {
centerImages[i] = new ImageView(
new Image(Calculator.class.getResourceAsStream(
"images/button-"+(i)+".png")));
centerButtons[i] = new Button();
centerButtons[i].setGraphic(centerImages[i]);
centerButtons[i].setPadding(Insets.EMPTY);
centerButtons[i].setId("button-"+(i));
flow.getChildren().add(centerButtons[i]);
// add a drop shadow on mouseenter
DropShadow shadow = new DropShadow();
// ***** here's the workaround is this really a good approach
// to use this in the inner class instead of i? thanks *****
int thisI = i;
// set event handlers for click, mousein, mouseout
centerButtons[i].setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
// change graphic of button to down graphic
ImageView downImage = new ImageView(new
Image(Calculator.class.getResourceAsStream(
"images/button-"+(thisI)+"D.png")));
// call function to effect button press
System.out.println("Button click");
// change graphic back
centerButtons[thisI].setGraphic(centerImages[thisI]);
}});
centerButtons[i].addEventHandler(MouseEvent.MOUSE_ENTERED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
centerButtons[thisI].setEffect(shadow);
}
});
centerButtons[i].addEventHandler(MouseEvent.MOUSE_EXITED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
centerButtons[thisI].setEffect(null);
}
});
}
return flow;
}
You can remove the arrays centerButtons and centerImages completely. Instead create local variables for the image and the button within the loop and use those, e.g.
final ImageView image = new ImageView(...);
final Button button = new Button();
button.setGraphic(centerImages[i]);
...
You can use the local variables in your eventhandlers, e.g.
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
...
// change graphic back
button.setGraphic(image);
}});
Two minor improvements I noticed:
Try to avoid creating an Image more than once, because every time you create an Image, the actual data will be loaded again. Your handler will create a new Image for each click. I usually create Images in static final fields.
Event handlers are a nice opportunity to practice lambda expressions. :)

dealing with tictactoe detecting the buttons

So, I'm working on a project that uses a GridLayout and an array of tictactoetile, which is a class which extends JButton.
For an example of the first thing I'm trying to do, I want to find out what button is clicked, and then set that button's text to equal either x or o depending on which turn it is. I have the logic for that down, I just don't know how to get the row and column of the button clicked.
Sorry if this is not worded well.
public class tictactoetile extends JButton implements ActionListener {
private int cory;
private int corx;
//Create your own GameObj class with the necessary members
//Some examples for members below...
private GameObj game;
public tictactoetile(int x,int y,GameObj gam) {
cory = y;
corx = x;
game = gam;
super();
}
public void actionPerformed(ActionEvent e) {
this.setText(game.getTurnMarker()); //returns either x or o
game.updateGameState(game.getTurn(),cory,corx);
game.nextTurn();
}
}

Put widget inside RowExpander in GXT

Is there a way to display widget in the expanded area? RowExpander uses AbstractCell which can display only simple html. It is possible to take html from widget and place it into cell but the buttons in the widget won't work after this.
Extend the RowExpander class and/or override the method beforeExpand. Here's what I did and it works great for inserting a button or in my case i needed a grid:
public class RowWidgetExpander extends RowExpander {
private Widget widget;
public void setWidget(Widget widget) {
this.widget = widget;
}
public Widget getWidget() {
return widget;
}
#Override
protected boolean beforeExpand(ModelData model, Element body, El row, int rowIndex) {
RowExpanderEvent e = new RowExpanderEvent(this);
e.setModel(model);
e.setRowIndex(rowIndex);
e.setBodyElement(body);
if(fireEvent(Events.BeforeExpand, e)) {
body.setInnerText("");
body.appendChild(widget.getElement());
ComponentHelper.doAttach(widget);
return true;
}
return false;
}
Instead of inserting the widget to the grid. You can put widget on the grid.
Insert grid in AbsolutPanel. And after expand event you can insert widget into the AbslolutPanel and set position on expanded area.
Set the height of the AbsolutPanel such as total height of grid (all grid lines). And AbsolutPanel put inside a Scroll Panel.
With this solution, You have a widget - not only pure html. And you do not have to worry about Scrolling.
Try this workaround to get events working again in the row expander.
http://www.sencha.com/forum/showthread.php?250316-RowExpander-dosn-t-fire-events-on-ContentCell

JColorChooser: Save/restore recent colors in Swatches panel

I am using a JColorchooser at various places in an application. There can be multiple instances of the panel that can invoke a JColorChooser.
The "Swatches" panel in the chooser has an area of "recent" colors, which only persists within each instance of JColorChooser. I would like to (a) have the same "recent" colors in all my choosers in my application, and (b) to save the colors to disk so that these colors survive close and restart of the application.
(At least (a) could be solved by using the same single chooser instance all over the whole app, but that apears cumbersome because I would need to be very careful with attached changelisteners, and adding/removing the chooser panel to/from various dialogs.)
I did not find any method that lets me set (restore) these "recent" colors in the chooser panel. So to me, it appears that the only ways of achieving this would be:
serialize and save / restore the whole chooser (chooser panel?)
or
create my own chooser panel from scratch
Is this correct, or am I missing something?
BTW: I would also like to detect a double click in the chooser, but it seems hard to find the right place to attach my mouse listener to. Do I really need to dig into the internal structure of the chooser panel to do this? (No, it does not work to detect a second click on the same color, because the change listener only fires if a different color is clicked.)
As you noticed, there is no public api to access the recent colors in the DefaultSwatchChooserPanel, even the panel itself isn't accessible.
As you'll need some logic/bean which holds and resets the recent colors anyway (plus the extended mouse interaction), rolling your own is the way to go. For some guidance, have a look at the implementation of the swatch panel (cough ... c&p what you need and modify what you don't). Basically, something like
// a bean that keeps track of the colors
public static class ColorTracker extends AbstractBean {
private List<Color> colors = new ArrayList<>();
public void addColor(Color color) {
List<Color> old = getColors();
colors.add(0, color);
firePropertyChange("colors", old, getColors());
}
public void setColors(List<Color> colors) {
List<Color> old = getColors();
this.colors = new ArrayList<>(colors);
firePropertyChange("colors", old, getColors());
}
public List<Color> getColors() {
return new ArrayList<>(colors);
}
}
// a custom SwatchChooserPanel which takes and listens to the tracker changes
public class MySwatchChooserPanel ... {
ColorTracker tracker;
public void setColorTracker(....) {
// uninstall old tracker
....
// install new tracker
this.tracker = tracker;
if (tracker != null)
tracker.addPropertyChangeListener(.... );
updateRecentSwatchPanel()
}
/**
* A method updating the recent colors in the swatchPanel
* This is called whenever necessary, specifically after building the panel,
* on changes of the tracker, from the mouseListener
*/
protected void updateRecentSwatchPanel() {
if (recentSwatchPanel == null) return;
recentSwatchPanel.setMostRecentColors(tracker != null ? tracker.getColors() : null);
}
// the mouseListener which updates the tracker and triggers the doubleClickAction
// if available
class MainSwatchListener extends MouseAdapter implements Serializable {
#Override
public void mousePressed(MouseEvent e) {
if (!isEnabled())
return;
if (e.getClickCount() == 2) {
handleDoubleClick(e);
return;
}
Color color = swatchPanel.getColorForLocation(e.getX(), e.getY());
setSelectedColor(color);
if (tracker != null) {
tracker.addColor(color);
} else {
recentSwatchPanel.setMostRecentColor(color);
}
}
/**
* #param e
*/
private void handleDoubleClick(MouseEvent e) {
if (action != null) {
action.actionPerformed(null);
}
}
}
}
// client code can install the custom panel on a JFileChooser, passing in a tracker
private JColorChooser createChooser(ColorTracker tracker) {
JColorChooser chooser = new JColorChooser();
List<AbstractColorChooserPanel> choosers =
new ArrayList<>(Arrays.asList(chooser.getChooserPanels()));
choosers.remove(0);
MySwatchChooserPanel swatch = new MySwatchChooserPanel();
swatch.setColorTracker(tracker);
swatch.setAction(doubleClickAction);
choosers.add(0, swatch);
chooser.setChooserPanels(choosers.toArray(new AbstractColorChooserPanel[0]));
return chooser;
}
As to doubleClick handling: enhance the swatchChooser to take an action and invoke that action from the mouseListener as appropriate.
You can use the JColorChooser.createDialog method - one of the parameters is a JColorChooser. Use a static instance of the JColorChooser and make it the Dialog modal - that way, only one color chooser is displayed at a time.
The createDialog method also takes ActionListeners as parameters for the OK and Cancel button. Thus, don't really have to manage listeners. Of course, this doesn't persist the recent colors across invocations of the app, just persists recent colors in the current app.
Here's a workaround using reflection - it will work provided the underlying implementation doesn't change. Assuming you have a JColorChooser, add your recent colors to it like this:
final JColorChooser chooser = new JColorChooser(Color.white);
for (AbstractColorChooserPanel p : chooser.getChooserPanels()) {
if (p.getClass().getSimpleName().equals("DefaultSwatchChooserPanel")) {
Field recentPanelField = p.getClass().getDeclaredField("recentSwatchPanel");
recentPanelField.setAccessible(true);
Object recentPanel = recentPanelField.get(p);
Method recentColorMethod = recentPanel.getClass().getMethod("setMostRecentColor", Color.class);
recentColorMethod.setAccessible(true);
recentColorMethod.invoke(recentPanel, Color.BLACK);
recentColorMethod.invoke(recentPanel, Color.RED);
//add more colors as desired
break;
}
}

Categories