Referencing hashMap values - swing

I am working on Swing code that has a bunch of radio buttons associated with a hashmap of their hex values. It will then display (in a display area) the color (in the background) along with some text of the hex value of that color.
I'd like it to do this by referencing the values stored in my hashMap and populating these fields accordingly but don't know quite how to do it. I could hard-code individual ActionListeners (20 in all) but what's the point of coding if you have to do everything the hard way?
Below is my ActionListener & a couple entries in my hashMap. Thanks in advance!
//---- Action Listener
jrbRed.addActionListener(new ActionListener() {//<---Reference whichever button is selected instead of just 'jrbRed'
#Override
public void actionPerformed(ActionEvent e) {
jlblMessage.setForeground(Color.decode("#000000"));
jlblMessage.setText("FF0000");//<---Reference hashmap value
getContentPane().setBackground(Color.red);//<---Reference hashmap value
}
});
// ...my color map of hex values for referencing...
hashMap.put("Blue", "#0000FF");
hashMap.put("Purplish", "#DF01D7");
hashMap.put("Red", "#FF0000");
// ...etc...

What if you're map looked like this?
JButton blueButton = new JButton("Blue");
hashMap.put(blueButton, "#0000FF");
MyActionListener listener = new MyActionListener();
for(JButton button : hashMap.keySet()) {
button.addActionListener(listener);
}
Then to get the value depending on the button in your listener:
jbliMessage.setText(hashMap.get((JButton)e.getSource());

You can subclass your radio buttons to have foreground, background, and text Color variables, and reference them in your ActionListener:
private class ColorSettingListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
ColorRadioButton crb = (ColorRadioButton) e.getSource();
jlblMessage.setForeground(crb.getForegroundColor());
jlblMessage.setText(crb.getColortext());
getContentPanel().setBackground(crb.getBackgroundColor());
}
}
If you think this is too obtrusive, you can use JComponent.getClientProperty(Object) and JComponent.setClientProperty(Object, Object) to do the same thing. Then you don't have to subclass.

Related

Returing the String of difficulty and clearing a txtArea, when selecting a JComboBox option

I have some code which is used to change a txtArea in a program when certain buttons are clicked then an ActionListener performs an action.
reset.addActionListener(new ButtonsAction());
hint.addActionListener(new ButtonsAction());
solve.addActionListener(new ButtonsAction());
newPuzzle.addActionListener(new ButtonsAction());
public class ButtonsAction implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {//implements actionPerformed
Object button=e.getSource();
if(button.equals(hint))
{
jtxtar.setText("Hint button clicked!");
}
else if(button.equals(reset))
{
jtxtar.setText("Reset button clicked!");
}
else if(button.equals(solve))
{
jtxtar.setText("Solve button clicked!");
}
else
{
jtxtar.setText("New Puzzle button clicked!");
}
}
}
However I also have a JComboBox which when selecting one of it's three option should also clear the field, but then add a message like, "Difficulty changed to ...." .
Looking up how JComboBox works, I believe I need to use an ItemListener rather than ActionListener. Looking at the tutorials has not helped me glean much from this however. But I did find something that said I needed a whole new Listener class to implement it.
diffBox.addItemListener(new CBoxAction());
public class CBoxAction implements ItemListener{
#Override
public void itemStateChanged(ItemEvent event) {
if(event.getStateChange() == ItemEvent.SELECTED) {
diffBox.getSelectedItem();
jtxtar.setText();
}
The problem here is I am not sure what I should have it do to tell the jtxtar clear and tell the user they changed to that difficulty.
After re-looking at Oracle's JComboBox Demo, I got my answer. I add this to my else statements, appending the last statement as else if, then adding the code that sets the jtxtar to tell the use their difficulty. No need for another class as it uses the ActionListener also.
else if(button.equals(newPuzzle))
{
jtxtar.setText("New Puzzle button clicked!");
}
else {
JComboBox diffBox = (JComboBox)e.getSource();
String difficulties = (String)diffBox.getSelectedItem();
jtxtar.setText(difficulties);
}
And now when you click the ComboBox and choose a new difficulty, the jtxtar clears and says that difficulty.

Is it possible to take a void as argument in processing

I am making a button class and I would like it to take a void as an argument(in the constroctor) so that the void gets called when the user clicks it. So that I don't have to void mouseClicked() {if (button.mouseIsIn()) {doIt();} and it automatically gets called when the user clicks it. Like Button button = new Button(x,y,width,height,handleMouseClick());. Thanks in advance.
First of all, there's no such thing as "a void" - you can have a function with a void return type, but it doesn't make sense to call them voids.
That being said, this depends on whether you're using Java or JavaScript mode. Assuming you're using Java mode, then the answer is no, you can't pass functions as parameters. What you can do instead is pass an instance of a class, and then call the functions of that class. Something like this:
class MyAction{
void doIt(){
//whatever
}
}
Once you have this class defined, you can create an instance of it using the new keyword:
MyAction myAction = new MyAction();
Which you can then pass into your Button constructor:
Button button = new Button(x, y, width, height, myAction);
Then in your Button class, you can simply call myAction.doIt() whenever you want to call the function:
void mouseClicked() {
if (button.mouseIsIn()) {
myAction.doIt();
}
}
You can combine this approach with anonymous inner classes to allow you to create MyAction instances on the fly with their own implementation of doIt(). Something like this:
MyAction actionOne = new MyAction(){
void doIt(){
doThingOne();
}
}
Button buttonOne = new Button(1, 2, 3, 4, actionOne);
MyAction actionTwo = new MyAction(){
void doIt(){
doThingTwo();
}
}
Button buttonTwo = new Button(1, 2, 3, 4, actionTwo);
If you're using JavaScript mode, then you can just pass functions as arguments directly.
More info can be found by googling "Java pass function as parameter" or "JavaScript pass function as parameter".

Post overriding the paint method of the components in java

In java awt or swing when you want to change painting of some component you usually have to override the method paint(Graphics g) (in awt) or paintComponent(Graphics g) (in swing).
This is usually (maybe allways - I'm not sure) done when you are creating the component for example:
JPanel jPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//... my implementation of paint, some transfromations, rotation, etc
}
};
Imagine that you have container of components which could for example consists of some JLabels, some JTextFields, some image. Which will be all put on one component.
By container I mean you have some list or map with ids or some similar structure in which are all components you will put on one JFrame.
The question is if I can change the painting method after creating with all of the components which are in this list in the moment when all of them are already created. For example I want do the rotation action (rotate), which is defined in Graphisc2D, with all of them.
So basicaly what I want is that I throught the list of componets I have and say:
"All of you (components) which are in the list will be rotated by some angle". Is that possible? If yes how?
Edit:
This is my not correctly working solution:
graphicalDisplayPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g2d = (Graphics2D) g;
g2d.rotate(Math.PI, anchorx, anchory);
}
#Override
public void paintChildren(Graphics g) {
super.paintChildren(g);
Graphics2D g2d2 = (Graphics2D) g;
g2d2.rotate(Math.PI, anchorx, anchory);
}
};
JFrame jFrame = JFrame();
// ... setting dimension, position, visible etc for JFrame, it works correctly nonrotated
jFrame.setContentPane(graphicalDisplayPanel);
I have not tested this, but it seems like it would work. A JComponent's paint() method calls:
paintComponent(co);
paintBorder(co);
paintChildren(co);
where co is a Graphics object. In theory you create an image, retrieve the graphics object and then pass that into paintChildren(). you will have to call paintComponent() and paintBorder() yourself, if you do this. Then, just rotate the image and draw it into your component. You may have to crop the image or resize your component accordingly for this to work. It might look something like this:
BufferedImage myImage;
#Override
public void paint(Graphics g){
myImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
//using a transparent BufferedImage might not be efficient in your case
Graphics myGraphics = myImage.getGraphics();
super.paintComponent(g);
super.paintBorder(g);
super.paintChildren(myGraphics);
//rotation code here
// ...
//draw children onto your component
g.drawImage(myImage, 0, 0,getWidth(), getHeight(), null);
}
I hope I didn't make any mistakes, please let me know if this works.
So basicaly what I want is that I throught the list of componets I have and say: "All of you (components) which are in the list will be rotated by some angle".
If you want to rotate panel and therefore all the components on the panel as a single using then you need to do the custom painting in the paintComponent() method.
If you want to rotate, for example, individual images that each have a different angle of rotation then you can again do this in the paintComponent(...) method and change the angle for each component.
Or, in this second case you can use the Rotated Icon class. In this case the Icon is just added to a JLabel. Then you can change the degrees of rotation and repaint the label, so there is no custom painting (except in the Icon itself).

Canvas repaint should be called by itself

I have an application with jTabbedPane. There are two tab (JPanel) in jTabbedPane. First tab includes canvas and second one includes simple JLabel. Button draws rectangle into canvas.
Every thing is fine until then. However, when switching tabs, canvas would lose everything. It should be repainted by itself.
Rectangle should exist after changing tabs. Do you have any idea about the problem?
My button code is here:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Graphics g = canvas1.getGraphics();
g.drawRect(10, 10, 100, 100);
}
Thanks in advance.
First of all, you shouldn't put AWT components inside Swing components. Use JComponent or JPanel instead of Canvas.
Second, no, it shouldn't repaint itself. When the button is clicked, you should simply store what should be painted in some variable, and the paintComponent() method should be overridden in order to paint what is stored in this variable. This way, every time the component is repainted, it will repaint what has been stored last in this variable.
For example:
public class RectangleComponent extends JComponent {
private boolean shouldPaintRectangle = false;
public void setShouldPaintRectangle(boolean b) {
this.shouldPaintRectangle = b;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (shouldPaintRectangle) {
g.drawRect(10, 10, 100, 100);
}
}
}
In general, you should never ask the Graphics of a component and paint on it. Instead, you should override paintComponent() and paint the component using the Graphics passed as argument.

Better choice: TextLayout or JTextComponent for an "ellipse with editable text" component?

If you've ever used Visio or a UML class diagram editor, you have an idea of what I'm trying to accomplish: Within a JFrame, users can add ellipses that enclose a small editable text field. These ellipses can be repositioned within the frame when the user drags them. Clicking on an ellipse causes the text to become editable: a carat appears, highlighting a substring is possible, etc.
I've got the basic structure set up: the 'ellipse' is a self-contained component, with methods called on it from the containing JFrame and its listeners. I've tried two approaches:
in the component's draw() method, use a TextLayout to find bounds, position the contained text within the ellipse, and draw it to the frame using TextLayout's draw(). This is fast. Dragging the components around in the JFrame, mouse-over and mouse-click behavior are all straightforward. However for the editing functionality it looks like I will need to write a lot of custom code to handle hit testing, carat positioning, text highlighting, line wrapping, etc.
having the component contain a reference to the containing JFrame, and adding or repositioning a TextComponent in that JFrame after drawing the ellipse. This has the advantage of all the built-in TextComponent behavior for editing and line wrapping. But the logistics are really sloppy, and positioning the TextComponent becomes messy too - especially when the user drags the component around.
I'm quite possibly thinking about this all wrong. Can anyone suggest a simple way to do this that I haven't yet stumbled across?
Why don't you combine both your approaches. As long as you are editing, display the text component, otherwise paint all text using a TextLayout. The following example code shows such an approach extending a simple JComponent. It draws a rectangular shape with some text in it and if you click inside it shows an editing possibility. As soon as you click outside again, the component vanished. Note that all the edit-handling functionality is missing in this basic example.
class TestComponent extends JComponent {
JTextArea jta = new JTextArea("12345");
public TestComponent() {
setPreferredSize(new Dimension(400, 400));
setLayout(null);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
if (e.getX() >= 40 && e.getX() <= 200 && e.getY() >= 40 && e.getY() <= 80) {
TestComponent.this.add(jta);
jta.setBounds(42, 42, 156, 36);
} else {
TestComponent.this.remove(jta);
}
repaint();
}
});
}
});
}
#Override
public void paintComponent(Graphics _g) {
Graphics2D g = (Graphics2D) _g;
g.drawRect(40, 40, 160, 40);
TextLayout layout = new TextLayout("12345", g.getFont(), g.getFontRenderContext());
layout.draw(g, 42, 42 + layout.getAscent());
}
}