I've currently got 108 auto generated jPanels, each containting a random number.
Is there a way to easily make each of these clickable?
Here's my code..
Creating JPanels:
for (int row = 0; row < numbers.length; row++)
{
for (int col = 0; col < numbers[row].length; col++)
{
int tempNumber = (int)(Math.random() * 9 + 1);
numbers[row][col] = tempNumber;
np1 = new NumberPanel(tempNumber);
np1.setLocation(row*np1.getWidth(), row*getWidth());
add(np1);
}
}
The number panel class:
public NumberPanel(int randomNumber)
{
String number = Integer.toString(randomNumber);
setPreferredSize(new Dimension(40, 40));
setBackground(Color.red);
JLabel label = new JLabel(number, JLabel.LEFT);
label.setFont(new Font("Serif", Font.BOLD, 35));
add(label);
}
Why are you creating a panel to contain a JLabel? Why not just add the label directly to the parent panel?
Instead of using a JLabel to display the random number use a JButton. Then you can add an ActionListener to each of the buttons.
You can make the button look like a label by using:
button.setBorderPainted( false );
So basically, instead of creating 108 panels that contain a JLabel, you just create 108 JButtons and add the buttons directly to the parent panel.
First of all, I think you should avoid using Absolute Position Layout (null layout). As you already know the number of rows and columns, it would be easier to have a GridLayout and keep adding components accordingly.
On the other hand, just add an ActionListener and use the getSource() from the Event to get whatever was clicked. With the panel (or label) clicked, you can get the Text to know whats its value.
Assuming the ActionListener was added to the JLabel, you can do:
if (evt.getSource() instanceof JLabel) {
Integer value = Integer.valueOf(((JLabel) evt.getSource()).getText());
}
I actually like more the idea to have everything decoupled, so I'll just send a FirePropertyChange and receive it wherever I need to process the value.
If NumberPanel extends from JPanel, inside the constructor you can add Mouse listener.
addMouseListener(new MouseListener() {
....
});
If you want to have clickable JPanel with saved "state" you can use JToggleButton:
public class NumberButton extends JToggleButton {
public NumberButton(int randomNumber) {
setBorder(BorderFactory.createEmptyBorder());
String number = Integer.toString(randomNumber);
setText(number);
setFont(new Font("Serif", Font.BOLD, 35));
setPreferredSize(new Dimension(40, 40));
setBackground(Color.red);
}
}
Related
So im writing a small test program for fun replicating a inventory from games like minecraft and runescape. Basically a frame with another one inside it, and pictures of your items in it, and a scroll bar to scroll down through all the stuff you have in your inventory. The "Stuff" i would have in my inventory would be buttons added later on with their own functionality, so you can scroll through vertically and see all the "stuff." Right now i have some test buttons being added to deomsntrate the error. Basically i want the buttons to be 100,100 and for them to be in a row of 4, and go onto the next column. I though GridLayout would be the best choice, but it seems to add more rows after being added into a scrollpane. Well heres the code skimmed down:
public class inventory extends JFrame{
public static void main(String[] args){
new inventory();
}
JPanel mainInv = new JPanel();
JScrollPane sp;
public inventory(){
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit tk = this.getToolkit();
setLocation(tk.getScreenSize().width/2-getWidth()/2, tk.getScreenSize().height/2-getHeight()/2);
setLayout(null);
mainInv.setSize(getWidth()-10, 1000);
mainInv.setBackground(Color.blue);
mainInv.setLayout(new GridLayout(8,4));
sp = new JScrollPane(mainInv, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sp.setMaximumSize(new Dimension(400,400));
sp.setBounds(5, 5, 500-10, 500-130);
JButton[] testButs = new JButton[100];
for(int i = 0; i < 50; i++){
testButs[i] = new JButton("Test Button " + i);
testButs[i].setSize(100,100);
mainInv.add(testButs[i]);
}
add(sp);
setVisible(true);
}
}
With GridLayout the number of rows is the dominating factor.
If you have 8 rows and 4 columns that can only fit 48 buttons, if you try to add a 49th button it will create a 5th column not a 9th row.
You can solve your problem by setting up the GridLayout with more rows.
I am dynamically generating a list of name boxes, sliders and labels, and am trying to figure out how to access the values of the sliders and change the labels. Other posts suggest using an array, but I have no idea where to begin with that.
My code is as such:
public Tailoring(int n) {
/*initComponents();*/
JPanel containerPanel = new JPanel();
containerPanel.setLayout(new BoxLayout(containerPanel, BoxLayout.PAGE_AXIS));
this.add(containerPanel);
JLabel Title = new JLabel("Tailoring:");
containerPanel.add(Title);
for(int i = 0; i < n; i++){
JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
JTextField NameBox = new JTextField("Guest " + (i+1));
JSlider TipSlider = new JSlider();
JLabel TipCost = new JLabel();
rowPanel.add(NameBox);
rowPanel.add(TipSlider);
rowPanel.add(TipCost);
containerPanel.add(rowPanel);
}
}
You can create a new class YourPanel which extends JPanel.
Instead of the statement
JPanel rowPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
you can use
YourPanel rowPanel = new YourPanel(new FlowLayout(FlowLayout.LEFT));
Define textfield, slider and label as the properties of this YourPanel class.
Provide getters/setters for each field. Then use an array or ArrayList of YourPanel objects in your application. You will be able to reach the nth panel's label with a call like:
panels.get(n).getJLabel();
It appears that you'd like to change the value displayed in the JLabel when the associated JSlider is modified, right? The best way to associate pairs of objects in Java is with a Map structure:
Map<Component, JSlider> sliderToLabel = new HashMap<Component, JSlider>();
for (int i = 0; i < n; i++) {
// after your loop code
sliderToLabel.put(TipSlider, TipCost); // map the slider to its label
}
You will be able to get a reference to the JSlider in the code that listens for changes on that component.
JLabel updateLabel = sliderToLabel.get(targetedSlider);
updateLabel.setText("updated text");
Notes
As a matter of convention, variable names should begin with lower case letters
The event listener I alluded to should also be attached in the loop. See Writing Event ListenersOracle
I wrote the code below:
public class Information extends JFrame{
private JComboBox comboBox1;
private JComboBox comboBox2;
private JTextField textField[];
private JTextField jtextField;
private JLabel label[];
public Information()
{
setLayout(new flowlayout());
Box box = Box.createVerticalBox();
for(int i = 0; i < 20; i++)//textfield
{
textField = new JTextField[20];
box.add(Box.createRigidArea(new Dimension(5,5)));
textField[i] = new JTextField(2);
textField[i].setAlignmentX(2f);
textField[i].setAlignmentY(2f);
box.add(textField[i]);
}
for(int i = 0; i < 22; i++ )//lable
{
}
add(box);
}
}
I want that text field showed in my favorite size, but it fills the whole screen.
I used
textField[i].setAlignmentX(2f);
textField[i].setAlignmentY(2f);
and setcolum(), but it didn't resize the text field. How can I decrease my text fields' sizes?
I use from
setMaximumSize(new Dimension(80, 70));
setPreferredSize(new Dimension(50, 50));
their resize the textfield but change it's location but i don't want to change their
location.is there any manner than i change textfield position?
i use from setlocation but it didn't work!!.
use setPreferredSize()
also setMinimumSize(), setMaximumSize()
I believe you want to use setBounds which will take a width and height as parameters.
The setAlignment methods change the alignment of a component in its container, not the component's actual size. I think you're looking for JTextField's setColumns() method. There's always the inherited setSize() method, too.
Try setPreferredSize(), this (along with setMinimum/MaximumSize()) tend to be used by a lot of LayoutManagers including FlowLayout to appropriately size a container's components.
Also, as a side note, looks like you're re-creating your array of JTextAreas each iteration in that for loop, so only textField[19] would exist...
I think you want to Set a specific size for your textfield.
To do this :
Firstly set the layout as null using the object of Information class
information.setLayout(null);
And set the bounds of the JTextField using setBounds method :
textField.setBounds(0,0,100,100);
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.
Problem: I have a method that creates a list from the parsed ArrayList. I manage to show the list in the GUI, without scrollbar. However, I am having problem setting it to show only the size of ArrayList. Meaning, say if the size is 6, there should only be 6 rows in the shown List. Below is the code that I am using. I tried setting the visibleRowCount as below but it does not work. I tried printing out the result and it shows that the change is made.
private void createSuggestionList(ArrayList<String> str) {
int visibleRowCount = str.size();
System.out.println("visibleRowCount " + visibleRowCount);
listForSuggestion = new JList(str.toArray());
listForSuggestion.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listForSuggestion.setSelectedIndex(0);
listForSuggestion.setVisibleRowCount(visibleRowCount);
System.out.println(listForSuggestion.getVisibleRowCount());
listScrollPane = new JScrollPane(listForSuggestion);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mouseEvent) {
JList theList = (JList) mouseEvent.getSource();
if (mouseEvent.getClickCount() == 2) {
int index = theList.locationToIndex(mouseEvent.getPoint());
if (index >= 0) {
Object o = theList.getModel().getElementAt(index);
System.out.println("Double-clicked on: " + o.toString());
}
}
}
};
listForSuggestion.addMouseListener(mouseListener);
textPane.add(listScrollPane);
repaint();
}
To summarize: I want the JList to show as many rows as the size of the parsed ArrayList, without a scrollbar.
Here is the picture of the problem:
Here's the link to the other 2 as the picture resolution is quite big I'm scared it will distort the view:
JList 1 & JList 2
The JList 1 and 2 pictures shows it clearly. The JList displays empty rows, which I do not want it to happen.
Any ideas? Please help. Thanks. Please let me know if a picture of the problem is needed in case I did not phrase my question correctly.
--
Edit:
JScrollPane scrollPane = new JScrollPane(textPane);
scrollPane.setPreferredSize(new Dimension(200, 200));
//Create the text area for the status log and configure it.
changeLog = new JTextArea(5, 30);
changeLog.setEditable(false);
JScrollPane scrollPaneForLog = new JScrollPane(changeLog);
//Create a split pane for the change log and the text area.
JSplitPane splitPane = new JSplitPane(
JSplitPane.VERTICAL_SPLIT,
scrollPane, scrollPaneForLog);
splitPane.setOneTouchExpandable(true);
//Create the status area.
JPanel statusPane = new JPanel(new GridLayout(1, 1));
CaretListenerLabel caretListenerLabel =
new CaretListenerLabel("Caret Status");
statusPane.add(caretListenerLabel);
//Add the components.
getContentPane().add(splitPane, BorderLayout.CENTER);
getContentPane().add(statusPane, BorderLayout.PAGE_END);
How the textPane is included into the container, if that helps
Another edit:
public void showSuggestionList(JScrollPane pane, Rectangle caretCoords) {
pane.setVisible(false);
pane.setBounds(caretCoords.x - 5, caretCoords.y + 25, 400, 250);
pane.setVisible(true);
repaint();
}
showSuggestionList() is being called my CaretListener, to show the JScrollPane when the caret moves.
I suspect it's the layout-management of textPane that is the issue. From what I can see, the listForSuggestions should not occupy more space than it needs to display those items, if it's preferred size is respected.
So the JTextPane is a Container, that is, you can add subcomponents to it. But how are those subcomponents layed out? That is up to the layout manager currently in use. If the layout manager respects the preferred dimension of the listForSuggestios I think you should be ok. Not sure though.
From what I can see, you get the "null-layout" by just instantiating a JTextPane, which means that unless you set another layout manager explicitly, you would need to take care of placement / resizing of the subcomponents yourself.
You could try to do something like
Dimension dim = listForSuggestions.getPreferredSize();
listForSuggestions.setBounds(xPos, yPos, dim.getWidth(), dim.getHeight());
Here is a complete example
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class FrameTest {
public static void main(String[] args) {
JFrame f = new JFrame("Frame Test");
ArrayList<String> str = new ArrayList<String>();
for (int i = 0; i < 20; i++)
str.add("number " + i);
JTextPane tp = new JTextPane();
int visibleRowCount = str.size();
System.out.println("visibleRowCount " + visibleRowCount);
JList listForSuggestion = new JList(str.toArray());
listForSuggestion.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
listForSuggestion.setSelectedIndex(0);
listForSuggestion.setVisibleRowCount(5);
System.out.println(listForSuggestion.getVisibleRowCount());
JScrollPane listScrollPane = new JScrollPane(listForSuggestion);
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent mouseEvent) {
JList theList = (JList) mouseEvent.getSource();
if (mouseEvent.getClickCount() == 2) {
int index = theList.locationToIndex(mouseEvent.getPoint());
if (index >= 0) {
Object o = theList.getModel().getElementAt(index);
System.out.println("Double-clicked on: " + o.toString());
}
}
}
};
listForSuggestion.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, Color.BLACK));
listForSuggestion.addMouseListener(mouseListener);
Dimension dim = listForSuggestion.getPreferredSize();
listForSuggestion.setBounds(20, 20, (int) dim.getWidth(), (int) dim.getHeight());
tp.add(listForSuggestion);
f.add(tp);
f.setSize(400, 400);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
I think the most elegant way of doing this is to roll your own layout-manager. (It's actually quite simple.) And then, instead of doing textPane.add(list), you do textPane.add(list, YourLayoutManager.POPUP_LIST). The layout-manager then remembers the fact that list was supposed to be layed out according to it's preferred size, and layes it out accordingly in its layoutContainer-method. (If you give the YourLayoutManager a reference to the JTextPane that it is attached to, you could probably even make it layout the list right beside the current caret location.)
If you are dynamically (via code) filling your list, it is bad idea not to use scrollbar. It might work as you want f.e. for 20 list items, but imagine what happens once you need use more data - like 2000. Your GUI will be ruined.