I want to get the height of a string. Here is what i mean:
Say I have string : Hi , then I want the height(Hi) as the max height among all the characters in that string, so it will be the height of H. I saw few posts which said to use graphics to measure it, but i am not printing it, but i just want the height!
If I can get the height of character then i will write a loop to see which is the highest height!
So either of the two is fine:
Get height of string(max height among all letters in string) or
Get height of specified letter!
Just use the method GC#textExtent() to get a Point with the height and width of the text:
public static void main(String[] args)
{
final Display display = Display.getDefault();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
GC gc = new GC(display);
System.out.println(gc.textExtent("Hi").y);
gc.dispose();
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Javadoc:
Returns the extent of the given string. Tab expansion and carriage return processing are performed.
The extent of a string is the width and height of the rectangular area it would cover if drawn in a particular font (in this case, the current font in the receiver).
Related
I am using Java JDK 1.6 and have a problem using JTextPane to show text with a monospaced font. As soon as I add a UTF8-character like 😂, the line height in the textpane is reduced (for all the text already in the pane and also all text added later). How can I avoid this? I would like to have the normal line height.
Here is some sample code:
class AttributedTextPane extends JTextPane
{
private DefaultStyledDocument defaultStyledDocument;
protected AttributedTextPane()
{
this.defaultStyledDocument = new DefaultStyledDocument();
this.setDocument(defaultStyledDocument);
this.setContentType("text/plain");
...
}
}
...
This pane is integrated into an JInternalFrame. Creating the panel and setting the desired monospaced font:
Font font = new Font("DejaVu Sans Mono", Font.PLAIN, 11);
AttributedTextPane pane = new AttributedTextPane();
pane.setFont(font);
To display the desired text, I call pane.setText(...); As soon as I add the UTF8 character, the line height changes, see screenshot at http://i.imgur.com/Fq7XBJB.png. Is there a way to avoid that the line height is changed?
Thanks, Deejay
You could try setting/forcing a line height like so:
MutableAttributeSet jTextPaneSet = new SimpleAttributeSet(pane.getParagraphAttributes());
StyleConstants.setLineSpacing(jTextPaneSet, 1.5f); //replace float 1.5f with your desired line spacing/height
Source:
http://docs.oracle.com/javase/8/docs/api/javax/swing/JTextPane.html#setParagraphAttributes(javax.swing.text.AttributeSet,%20boolean)
https://docs.oracle.com/javase/7/docs/api/javax/swing/text/StyleConstants.html#setLineSpacing(javax.swing.text.MutableAttributeSet,%20float)
Old question but I have been struggling with it for some time, though with a JTextArea. The solution is to have either a VM param -Di18n=true or put the i18n property in the document.
My test code:
import javax.swing.JTextArea;
public class Test {
public static void main(String[] argv) {
JTextArea ta = new JTextArea();
//ta.getDocument().putProperty("i18n", Boolean.TRUE);
ta.setText("A");
System.out.println(ta.getPreferredSize()); // - height 16 without i18n and using default font, 15 with i18n
ta.setText("\ud8ff\udc05"); // surrogate pair
System.out.println(ta.getPreferredSize()); // - height 15
ta.setText("A");
System.out.println(ta.getPreferredSize()); // - height 15
}
}
When i18n is not enabled and the document is appended, the elements that are created are PlainView/WrappedPlainView that return the height based on the FontMetrics height.
When i18n is enabled the elements are PlainParagraph that contain GlyphView that calculates the height differently.
When i18n is not enabled and the document is appended with a surrogate pair then due to SwingUtilities2.isComplexLayout returning true, the i18n property is automatically set to true for the document and then all elements are created as PlainParagraph containing GlyphView that return the different (always smaller?) height.
I have a simple SWT program like this:
public static void main(String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
shell.setMinimumSize(300, 300);
// table
final Table table = new Table(shell, SWT.BORDER);
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.heightHint = 0; // "hack"
table.setLayoutData(gridData);
// example data
for (int i = 0; i < 50; i++) {
final TableItem item = new TableItem(table, SWT.NONE);
item.setText("item no." + i);
}
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
What I expect - I want the table to completely fill out the shells space without changing it's size. (Screenshot 1 and 3)
Problem - If I add rows to the table, the table automatically gets resized (and so also the shell). (Screenshot 2)
Workaround - To avoid this behaviour I added the line gridData.heightHint = 0; to the code. But this seems like a hack to me.
Question - What would be the correct way to avoid the enlargement of the table (and the shell) when data is added?
Regards, winklerrr
Screenshot 1
Without data, table and shell don't get resized, correct behaviour, in both versions
Screenshot 2
With data, table and shell are getting enlarged, wrong behaviour, only without the hack
Screenshot 3
With data, table and shell don't get resized, scrollbar is added, correct behaviour, only with the hack
call shell.setSize(int width, int height) at some point before adding data to the table?
You usually expect the table to have a certain logical height, say 20 rows. At least that's an approach I often choose.
To achieve that, I compute the expected initial height in pixels like this and use it as a height hint.
gridData.heightHint = table.getItemHeight() * 20;
To be more accurate, you would also want to add the table's trim.
shell.setSize(int width, int height)
add this code after the data to your table.
I have JLabel which I would like to change its size while I resize the window. When JLabel contains String which is too big, the String should be shortened, with right part visible and adds dots on the left hand side of the String.
My JLabel is inside innerPanel which is a header in middlePanel which is added to outerPanel. So when I resize window I use listener on outerPanel in that way:
outerPanel.addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent evt) {
int width = ((JPanel) evt.getSource()).getWidth();
windowSize = width;
refresh();
}
// [...] other not used override methods
});
refresh() repaints view and creates new middlePanel where is called class which creates innerPanel where is located my JLabel:
Public class InnerPanel extends JPanel {
private int maxSize;
String string = "<VERY_LONG_STRING>";
private static final int DEFAULT_INDEND_PIXEL = 70;
public InnerPanel(int windowSize) {
maxSize = windowSize - DEFAULT_INDENT_PIXEL;
createPanel();
}
private createPanel() {
// [...] gridbag and GridBagConstraints implementation
String shortString = countString();
JLabel label = new JLabel(shortString);
add(label,gc);
}
private String countString() {
int index = 0;
boolean toBig = true;
StringBuilder sb = new StringBuilder(string);
while(toBig) {
Rectangle2d rect = // [...] code which creates rectangle around text from sb.toString()
// I have no access to repo at home but if it's important I can paste it tomorrow
if(rect.getWidth() > maxSize)
sb.deleteCharAt(0);
else
toBig = false;
}
return sb.toString();
}
}
That's works fine in general, bacause it do resize JLabel in one step when I enlarge window in width. But the problem is appear when I try to reduce the window in width. In this case componentResized() calculate width step by step (and it's called multiple times), gradually decreases width by some amount of pixels till it reach real window size. It's behave in that way even thow I change window size in one step from maximum size to 800. Whole process is so slow, that it takes around a second to fit string to window size. So it looks bit like an animation.
The problem is very rare to me, bacause width in componentResized() method is calculeted step by step only when I assign windowSize variable.
When I give windowSize fixed size like for example 500 - componentResized() is called only onces - with correct width indicated real window size (!!) - and there's no its step by step decrease!
It's look like width variable which is assigned by ((JPanel) evt.getSource()).getWidth() knows that windowSize is used to dynamically change size of JLabel component even before first call of refresh() method.
If anyone have an idea what is going on here - I will be very appreciate for help.
You may be able to adapt one of the approaches shown here to better effect. As shown here, the ellipsis is supplied by the label's UI delegate via a call to SwingUtilities2.clipString(), which appends the clipString. Rather than re-invent the label UI, use TextLayout to determine the required geometry, prepend the ellipsis, and handle the alignment in a table or list renderer, as shown here.
Is there any way to set maximal size of composite? Only what i have found methods
setMinimumSize(Point point)
setSize(Point point)
which allow me to set minimal and prefered size.
As far as I know, there is no Layout, that has a setting for maximal size, which is a good thing in my opinion.
Consider the following szenario: You set the maximal size of a Widget/Composite to a value that you think "looks good". Depending on the screen resolution and text size of the end-user, the chosen maximal size might just look wrong. This is why the layouts usually adapt to the available space.
Nevertheless, here is some code, that restricts the size:
public static void main(String[] args)
{
Display display = new Display();
final Shell shell = new Shell(display);
shell.setText("StackOverflow");
shell.setLayout(new GridLayout(1, false));
final Button left = new Button(shell, SWT.PUSH);
left.setText("Restricted width");
left.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
left.addListener(SWT.Resize, new Listener()
{
#Override
public void handleEvent(Event arg0)
{
Point size = left.getSize();
if(size.x > 200)
{
left.setSize(200, size.y);
}
}
});
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Before resizing:
After resizing:
i am curious about why you want to set a maximum size. can you give a concrete example? i had a situation where i wanted this option, but i came up with a solution, that was even better. just think of a widget in a layout that has a preferred size based on its contents, e.g. a text widget. now you want that widget to be as big as the available space allows it. but since that widget is claiming space based on its contents, it might claim more space than necessary. so what i needed was a maximum size, but if more space is available, that widget will still be able to take the space without claiming more.
but lets have a look at an example:
public static void main(final String[] args) {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
final Text text = new Text(shell, SWT.WRAP | SWT.MULTI | SWT.V_SCROLL);
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
text.setText(getLongText());
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
the call to shell.pack() will make the shell use the preferred size to display its contents. the layout will then ask the text widget to compute its preferred size. the text widget does not know, that the shell will be expanded as well and does not have a fixed size.
well this problem can be solved if we could give the text widget a maximum size. but it will cause another problem with the grid layout, since we don't want the text widget to be smaller in case that the shell has a minimum size which is bigger than the preferred size of the text widget. i cannot give you a code example of this case, since there is no maximum size, but just imagine the shell be of a fixed size, and the the text widget inside has a maximum size that is smaller.
the solution is to limit the preferred size computed by the widget to be of a maximum preferred size. i didn't find yet a method to set this value, but you can achieve this effect by overriding the computeSize method of the widget:
final Text text = new Text(shell, SWT.WRAP | SWT.MULTI | SWT.V_SCROLL) {
/** The maximum preferred size. */
private final Point maxSize = new Point(500, 400);
#Override
public Point computeSize(final int wHint, final int hHint, final boolean changed) {
final Point preferredSize = super.computeSize(wHint, hHint, changed);
return new Point(Math.min(maxSize.x, preferredSize.x), Math.min(maxSize.y, preferredSize.y));
}
#Override
protected void checkSubclass() {
// noop, allow subclassing, since we know what we are doing
}
};
now you are still able to increase the shells size by a user drag operation and the widget will still we able to grab more space above the maximum size.
I must be missing something stupid. The docs clearly state that the RowData object for the RowLayout layout lets you specify a minimum size (width and height), which makes sense. However, when the underlying widget exceeds this size, the size does not increases and the widget is cropped. Is it really a minimum?
Example
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Example");
shell.setBounds(100, 100, 325, 200);
shell.setLayout(new FillLayout());
Composite comp = new Composite(shell, SWT.BORDER);
comp.setLayout(new RowLayout(SWT.VERTICAL));
Label label1 = new Label(comp, SWT.CENTER);
label1.setLayoutData(new RowData(20,20));
label1.setText("Trying with bounded rowdata...");
Label label2 = new Label(comp, SWT.CENTER);
label2.setText("Trying with no rowdata...");
comp.layout(true,true); // no difference
shell.pack();
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
Result:
The javadoc of the constructor RowData(int, int) must be wrong! If you read carrefully the header of the RowData javadoc, it is said that RowData are used to set an initial size for Controls, not the minimum. That's why your Labelis croped by a square of 20x20 px!
Try turning packing off on the layout:
Composite comp = new Composite(shell, SWT.BORDER);
RowLayout layout = new RowLayout(SWT.VERTICAL);
layout.pack = false;
comp.setLayout(layout);
On the other hand you can also consider using a GridLayout if you want the controls to resize with respect to their parents but not less than a minimum width. The minimum width works with GridData.