I have a JPanel in which I need to add bunch of JLabels at a required coordinates. These JLabels will have key Listeners assigned to them that will determine new position using arrow keys.
To be more specific I know how to do it when there is only one JLabel but whenever I put a more of them the things mess up. while I use arrow key the first JLabel moves but all other JLabel disappears.
Can Anyone give me some hints to write a method to put a JLabel in a specific coordinate and also move them using arrow key later without making other JLabels dissapear?
Huge Thanks in Advance
You can try using JDesktopPane or JLayeredPane, it works the same as the JPanels, but you won't use layouts, with these you will use Bounds, you always have to set the bound of a jlabel like this.
JLabel label = new JLabel("Hello");
label.setBounds(0, 0, 100, 20);
//label.setBounds(x, y, width, height);
pane.add(label)
if you need to move that label, then you can use something like
int xx = label.getBounds().getX();
int yy = label.getBounds().getY();
int ww = label.getBounds().getWidth();
int hh = label.getBounds().getHeight();
//to the right 10 units
xx+=10;
label.setBounds( xx, yy, ww, hh );
I assume you are using repaint() to update the UI. Btw, upon which component you are calling repaint()?
Related
I'm relatively new to java and have been working on a simple Blackjack program using Java Swing, but I'm having trouble getting setAlignmentX to work in OverlayLayout.
Basically the idea is to have two cards generate on the left side of the play area (the red rectangle), then add another card (on top and to the right of the previous cards) when the player clicks "Draw".
Picture Link because I'm too new to Stack Overflow
I try to do this by adding a card (JLabel with image icon) with a .setAlignmentX that is greater than the previous card.
However, there are two problems. The first is that when a single card is generated, it is able to stick all the way to the left of the rectangle. However, when two cards are generated, they both generate further to the right, away from the side.
The second is that the new card is adding itself below, and to the left, of the previous cards (instead of above and to the right). Furthermore, as per the two cards, the whole chunk is moving rightwards on every draw.
Another Picture Link
Here is the relevant code:
ArrayList<JLabel> tuCardsPanelList = new ArrayList<>();
...
for(int i = 0; i < 9; i++){
tuCardsPanelList.add(new JLabel());
}
tuCardsPanel = new JPanel(new BorderLayout());
tuCardsPanel.setBackground(new Color(130, 30, 40));
tuCardsPanel.setBorder(new LineBorder(Color.yellow));
tuCardsPanel.setPreferredSize(new Dimension(400, 200));
tuCardsPanel.setLayout(new OverlayLayout(tuCardsPanel));
...
//display first two cards
ImageIcon image = new ImageIcon(getClass().getResource(activePlayer.hand.get(0).imageLocation));
tuCardsPanelList.get(0).setIcon(new ImageIcon(image.getImage().getScaledInstance(121, 185, Image.SCALE_SMOOTH)));
tuCardsPanelList.get(0).setPreferredSize(new Dimension(121, 185));
tuCardsPanelList.get(0).setAlignmentX(0.0f);//SETALIGNMENTX HERE
tuCardsPanelList.get(0).setAlignmentY(0.5f);
ImageIcon image1 = new ImageIcon(getClass().getResource(activePlayer.hand.get(1).imageLocation));
tuCardsPanelList.get(1).setIcon(new ImageIcon(image1.getImage().getScaledInstance(121, 185, Image.SCALE_SMOOTH)));
tuCardsPanelList.get(1).setPreferredSize(new Dimension(121, 185));
tuCardsPanelList.get(1).setAlignmentX(0.16f); //SETALIGNMENTX HERE
tuCardsPanelList.get(1).setAlignmentY(0.5f);
tuCardsPanel.add(tuCardsPanelList.get(0));
tuCardsPanel.add(tuCardsPanelList.get(1));
...
//when "Draw" button is pressed
activePlayer.drawFrom(deck);
tuLabel3.setText("Total: " + activePlayer.valueOfHand());
int currentNewCard = activePlayer.hand.size() - 1;
ImageIcon image = new ImageIcon(getClass().getResource(activePlayer.hand.get(currentNewCard).imageLocation));
tuCardsPanelList.get(currentNewCard).setIcon(new ImageIcon(image.getImage().getScaledInstance(121, 185, Image.SCALE_SMOOTH)));
tuCardsPanelList.get(currentNewCard).setPreferredSize(new Dimension(121, 185));
tuCardsPanelList.get(currentNewCard).setAlignmentY(0.5f);
tuCardsPanelList.get(currentNewCard).setAlignmentX(0.32f); //SETALIGNMENTX HERE
If it helps, one really weird thing I found was that the second card (with .setAlignmentX(0.16f)) is actually on the left of the first card (which has a .setAlignmentX(0f)!)
I think they are all symptoms of a property of .setAlignmentX or OverlayLayout that I'm misusing, but I just can't figure it out. Google didn't help either.
Any help will be greatly appreciated! :)
i have done a small test on LibGdx, on Multi-line Label, it seems that i cant get the wrapped line's height. Following is the code. Theoretically, height for aLebel should be > bLabel. But the result appear the same.
code:
aLabel.setText("this is a super long long long text that need wrapping."); // line wrapped into 3 lines
aLabel.setWrap(true);
aLabel.setWidth(470);
doLog("aLabel.getHeight(): " + aLabel.getHeight());
bLabel.setText("this is short."); // unwrapped line
bLabel.setWrap(true);
bLabel.setWidth(470);
doLog("bLabel.getHeight(): " + bLabel.getHeight());
result:
aLabel.getHeight(): 45.0
bLabel.getHeight(): 45.0
Do anyone have any idea how to get the actual multi-line height in LibGdx? Thanks in advance.
I had this issue for years and accidentally solved it by setting the width and packing the label twice. Note that multiline labels were never intended to figure out their own width, so you have to set them externally, preferably from it's parent.
public Label createLabel() {
// Create label and set wrap
Label label = new Label("Some long string here...", skin);
label.setWrap(true);
// Pack label
label.pack(); // This might not be necessary, unless you're changing other attributes such as font scale.
// Manual sizing
label.setWidth(textWidth); // Set the width directly
label.pack(); // Label calculates it's height here, but resets width to 0 (bug?)
label.setWidth(textWidth); // Set width again
return label;
}
LibGDX version used: 1.6.4
Pack sizes the widget to its pref size, nothing more. Pref width of a label with wrapping is 0.
Label label = new Label(...);
label.setWrap(true);
label.setWidth(123);
label.setHeight(label.getPrefHeight());
I had the same issue and it seems there doesn't exist a method in Label class to solve this. Also, I agree with you, the getHeight() method should return the real height of the Actor, so I don't know if that's a bug or there is a reasoning behind that behaviour.
Anyways, how I solved the issue is by using BitmapFont's getWrappedBounds method. It's not short, but for your example it would be the following:
doLog("aLabel.getHeight(): " + aLabel.getStyle().font.getWrappedBounds(aLabel.getText(), aLabel.getWidth()).height);
This could be done by adding a restriction to the cell that contains the Label in the Table:
Label label = new Label("Example", new Label.LabelStyle(font, Color.WHITE));
label.setWrap(true);
Table table = new Table();
table.add(label).width(WITH);
For more information about how to use Table go to: https://github.com/libgdx/libgdx/wiki/Table
I'm making a Matrix calculator in Java using a two-dimensional array of JTextFields on a JPanel to input a given Matrix. Since the panel that this matrix is placed on has a fixed size, I want to scale down the text size to accommodate how long the number is as it's being typed in.
For example:
If it's one digit long, font size = 18. If it's two digits long, font size = 14. Etc.
I want this to dynamically occur as the user is entering the text, and I want repainting to occur everytime the user interacts with the JTextField, not only after the user presses "enter". This is because the field is transparent and currently looks sloppy (numbers overlapping) until the user presses enter.
What's the most straightforward and reliable way to do this? Here's my current code if it helps anyone answer my question:
public class MatrixPanel extends JPanel implements ActionListener
{
float[][] matrice = new float[3][3];
JTextField[][] parameter = new JTextField[3][3];
Font font = new Font("SansSerif", Font.BOLD, 40);
public MatrixPanel(String title)
{
setLayout(null);
setOpaque(false);
for (int width = 0; width < 3; width++){
for (int height = 0; height < 3; height++){
matrice[width][height] = 0;
parameter[width][height] = new JTextField();
parameter[width][height].setHorizontalAlignment(JTextField.CENTER);
parameter[width][height].setFont(font);
parameter[width][height].setText("0");
parameter[width][height].setLocation((50*width), (50*height));
parameter[width][height].setSize(50,50);
parameter[width][height].setOpaque(false);
parameter[width][height].setBorder(null);
parameter[width][height].addActionListener(this);
add(parameter[width][height]);
}
setSize(150,150);
}
}
I want to scale down the text size to accommodate how long the number
is as it's being typed in.
Take a look to How to Write a DocumentListener to achieve your goal.
Some useful tips:
About setSize(150,150) and setLocation((50*width), (50*height)): please have a look to this topic Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing? (yes we should). Components size and location should be handled by layout managers.
You may want to try GridLayout to place the text fields in a grid and forget about the fixed size/location. See How to Use GridLayout and Laying Out Components Within a Container tutorials for a better understanding on this subject.
If you want to input floats (or doubles) in your matrix then maybe formatted text fields or spinners are a better choice than plain text fields. Take a look to How to Use Formatted Text Fields and How to Use Spinners tutorials.
I am wishing to draw a number onto a JTextField by overwriting the paint method. So that when the user edits the text field the number doesn't disappear. However, at the moment, the number isn't appearing at all, I have tried:
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(number != 0){
g.setColor(Color.RED);
g.drawString(String.valueOf(number),0,0);
}
}
Any ideas, is this even possible?
Try to play with Y position in the g.drawString(String.valueOf(number),0,0); call. E.g. use getHeight()/2
..when the user edits the text field the number doesn't disappear.
As pointed out by #mKorbel, there is no need to override a JTextField in order to get red numbers, simply configure it using the public methods. OTOH..
g.drawString(String.valueOf(number),0,0);
If this is really all about numbers, perhaps the best approach is to use a JSpinner with a SpinnerNumberModel, and set a custom SpinnerUI.
Why don't you just add a small JLabel to the front of the JTextField? The JLabel could contain the number, and because it isn't editable it will always be there no matter what the user changes in the JTextField. You could also format the JLabel to make it red by calling setForeground(Color.RED);. This might be a much simpler solution?
For example, instead of doing this...
JPanel panel = new JPanel(new BorderLayout());
JTextField textfield = new JTextField("Hello");
panel.add(textfield,BorderLayout.CENTER);
You might do something like this...
JPanel panel = new JPanel(new BorderLayout());
JTextField textfield = new JTextField("Hello");
panel.add(textfield,BorderLayout.CENTER);
JLabel label = new JLabel("1.");
label.setForeground(Color.RED);
panel.add(label,BorderLayout.WEST);
Which adds a red JLabel to the left of the JTextField, and because you're using BorderLayout for the JPanel then it automatically makes the JLabel the smallest it can possibly be.
maybe there no reason override paintComponent() for JTextField, instead of use
JTextField.setBackground()
JTextField.setForeground()
JTextField.setFont()
JTextField.setHorizontalAlignment(javax.swing.SwingConstants.LEFT)
some hacks are possible by put there Html colored or special formatted text
EDIT
maybe this question is about
filtering KeyEvents in the Document / DocumentListener
or
JFormattedTextField with Number Formatter
Let's say I have a JButton, and I want it to be big enough to fit a string of 8 "M" characters, regardless of the string that is actually assigned to it and the font size, without using elipsis.
The JButton has to have precisely this size, no more, no less. Layout manager in use is GridBagLayout.
I tried overwriting the getPreferredSize() method and perform a calculation using the string and the current font of the system. The calculation gives me back some sensible value, however, I have no idea how to set the preferred size in such a way that the borders are also considered.
I tried to get the insets of the component, but they are all 0's.
This is the code of my method:
public void getPreferredSize() {
Dimension d = super.getPreferredSize();
// Geometry width indicates how many characters must fit
char[] pad = new char[propGeometryWidth];
Arrays.fill(pad, 'M');
String tmpTemplateString = new String(pad);
FontMetrics tmpMetrics = getFontMetrics(getFont());
Rectangle2D tmpR2D = tmpMetrics.getStringBounds(tmpTemplateString, getGraphics());
int tmpWidth = (int)tmpR2D.getWidth();
int tmpHeight = (int)(tmpR2D.getHeight() * propGeometryHeight + tmpR2D.getHeight());
// We need to take into consideration borders and padding!
Insets insets = getInsets();
Dimension tmpSize = new Dimension(tmpWidth + insets.left + insets.right, tmpHeight + insets.top + insets.bottom);
return tmpSize;
}
I get the feeling that this might be related to the fact that my component is not realized yet, but I am completely unsure how I could solve this issue. Am I approaching this problem from the wrong perspective?
I think you may actually be doing it right already. From the Javadoc for getInsets():
If a border has been set on this component, returns the border's insets; otherwise calls super.getInsets.
A freshly-created JButton for me shows insets of java.awt.Insets[top=5,left=17,bottom=5,right=17] with the default look and feel, and java.awt.Insets[top=4,left=16,bottom=4,right=16] with the Windows look and feel. Are you using a custom look and feel, perhaps?
I found the reason for my problem. The problem is that I had a panel with a JButton inside, and I overwrote the method on the panel (There is a relatively complex hierarchy of classes). Then, of course, the insets for the Panel are all set to 0. After getting the insets for the button, as stated by Mr. Mmyers, it all works great.