Suppose I have 2 text fields in a Java Swing file. I need to add a third field on top of the other two, then modify the alignment of the original two fields.
I am looking for some script or runtime classes which will dynamically change the alignment according to this requirement.
a1.setBounds(264,619+132,200,n);
a2.setBounds(264,641+132,200,n);
a3.setBounds(264,663+132,200,n);
If I want to add one field on top then I need to change all the below coordinates. So I need something like a script that will pass the X or Y coordinates value (suppose n) and the fields below will modify accordingly.
Note that I never user setBounds(...) since I always use a LayoutManager. However, I don't know your situation so I won't judge. Okay. maybe a little: USE A LAYOUT MANAGER!
Anyhoo, changing the magic numbers to something like this and you'll be able to add as many as you like w/o having to renumber everything.
[Untested, but you should get the idea]
const int yOffset = 22;
int yStart = 619;
int row = 0;
a1.setBounds(264, (yStart + (yOffset * row++)) + 132, 200, n);
a2.setBounds(264, (yStart + (yOffset * row++)) + 132, 200, n);
a3.setBounds(264, (yStart + (yOffset * row++)) + 132, 200, n);
Related
I am currently making a program for school where I have to lock the ratio while adjusting JSliders.
I could not figure out how to make one slider change with the same value while changing the first slider.
I want to change the sliders at a 1:1 ratio, so if I slide width up 5, the length will also go up 5, but I couldn't figure out how to find a constant difference to calculate when I change the value.
In your code you are setting length value based on length.getValue, but you want length to be set as width changes and vise versa. So I suggest that you set length like length.setValue(width.getValue());
if(lkRatio.isSelected() !=true){
tempw = width.getValue();
templ = length.getValue();
diff = width.getValue() - length.getValue();
}
if(lkRatio.isSelected()){
if(source == width){
length.setValue(width.getValue() - diff);
}
if(source == length){
width.setValue(length.getValue() + diff);
}
}
To answer "how can you create 2 sliders with same model" :
DefaultBoundedRangeModel brm = new DefaultBoundedRangeModel();
brm.setMaximum(100);
width = new JSlider(brm);
length = new JSlider(brm);
I have a JTextPane with content type "text/html". It is integrated in a JScrollPane.
The user can scroll down in this JTextPane and hits a button. At this moment I want to compute the topmost actual visible line of the JTextPane!
What I found in another post here where these lines:
public Integer getActualDisplayedRows() {
int y1 = jtextpane.getVisibleRect().y;
int lineHeight = jtextpane.getFontMetrics(jtextpane.getFont()).getHeight();
int topMostRow = (int) Math.ceil((double) y1 / lineHeight);
return topMostRow;
}
But this does not compute correct.. The number in lineHeight is too small. So, if I scroll to the 20th row -for example- the method returns more then 20..
I tried to set the height of the line via stylesheet (like here):
StyleSheet sh = editorKit.getStyleSheet();
sh.addRule("body {line-height: 50px}");
But doesn't matter what pixel number I set there, the resulting JTextPane has always the same height (and I am using the body tag)..
Do you have any suggestions??
Thank you very much for your help!
If I understand your requirement you just want to know the line number at the top of the viewport?
Here is some code for getting the line at the caret position:
public static int getLineAtCaret(JTextComponent component)
{
int caretPosition = component.getCaretPosition();
Element root = component.getDocument().getDefaultRootElement();
return root.getElementIndex( caretPosition ) + 1;
}
Don't know if this will work for HTML with all kinds of weird tags with images and tables etc. In this case I'm not sure what the meaning of "line" would be.
Now obviously the caret will not be at the top of the viewport, so you need to modify the logic to get an "offset" of the text at the top of the viewport.
So you should be able to use the viewToModel(...) method of the text pane. Something like:
int y = textPane.getVisibleRect().y;
Point p = new Point(5, y);
int offset = textPane.viewToModel( p );
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
In all the examples that I can find that use a JTextArea, the height & width is known before constructing the JTextArea, and if the JTextArea would require more height, then it is put inside of a JScrollPane. Obviously, the height of JTextArea is dependent on the width and the text contents.
Now, my situation requires that I do not use a JScrollPane, but instead that the JTextArea be just tall enough to display all the text. When I create the JTextArea, I know the text contents and how much width it will have to work with; I don't know the height - I want that to be as small as possible without cutting off any of the text. This seems very difficult to accomplish.
As a side note, the JTextArea will be added to a JPanel that does not have a layout manager - it uses absolute positioning based on the added component's preferred size. This requires that my JTextArea would return the correct dimensions on getPreferredSize(). The correct dimensions should be the width that I provided when I constructed it, and the minimum height that is required to display all the text with the provided width.
I've found some similar threads that discuss the oddities/bugs involved with the JTextArea that are sometimes solved by calling pack() twice on the parent container. This is not an option for me. I'm tempted to basically create my own JTextArea that takes a width and String and computes the necessary minimum height based on the width and font settings, but I figured I would ask around first before spending the time to do that.
Hopefully my question is clear. Thank you all for your help!
it uses absolute positioning based on the added component's preferred size.
Sounds like the job of a layout manager.
This requires that my JTextArea would return the correct dimensions on getPreferredSize().
JTextArea textArea = new JTextArea();
textArea.setLineWrap( true );
textArea.setWrapStyleWord( true );
textArea.setText("one two three four five six seven eight nine ten");
System.out.println("000: " + textArea.getPreferredSize());
textArea.setSize(100, 1);
System.out.println("100: " + textArea.getPreferredSize());
textArea.setSize( textArea.getPreferredSize() );
import java.awt.*;
import javax.swing.*;
class FixedWidthLabel {
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
String pt1 = "<html><body width='";
String pt2 =
"px'><h1>Label Height</h1>" +
"<p>Many Swing components support HTML 3.2 &" +
" (simple) CSS. By setting a body width we can cause the " +
" component to find the natural height needed to display" +
" the component.<br><br>" +
"<p>The body width in this text is set to " +
"";
String pt3 =
" pixels." +
"";
JPanel p = new JPanel( new BorderLayout() );
JLabel l1 = new JLabel( pt1 + "125" + pt2 + "125" + pt3 );
p.add(l1, BorderLayout.WEST);
JLabel l2 = new JLabel( pt1 + "200" + pt2 + "200" + pt3 );
p.add(l2, BorderLayout.CENTER);
JOptionPane.showMessageDialog(null, p);
}
};
SwingUtilities.invokeLater(r);
}
}
The solution described in FixedWidthLabel , using <html><body width="..."
will require the programmer to provide the message as part of the html string.
If the message is something like invalid integer: i<0 not allowed ,
then the < will have to be escaped (encoded?), otherwise there is no telling how JLabel will interpret the html.
This adds complexity to this solution.
Only if you know that the message doesn't contain any such characters, you will be allright.
Well perhaps if you know your width you could run some tests and work out how wide each character of text is, that way you could use a loop to determine how many characters fit on each line and total the characters that are to be shown, then you could set the height based on how many lines there are to be.
Say your text has 1000 characters including blank spaces, and the width of a character is equivalent to 4pixels, then you can work out if the width is 400 that 100 characters fit on each line, subsequently you will need 10 lines. Now say the height is 10 for the font size, you now know you need 10 x 10 == 100 pixels, so your TextArea should be 400x100
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.