Is there a way to get the exact size computed by a label before laying it out.
In other words, let us say there is a label with a really long sentence:
Hi how are you doing, my name is bond, I have no name, I live in London, but yet the world is my Home. I am here to play and enjoy.
This is a single line. however if the window is not large enough, then the label wraps into two lines.
I want to find out the final height that it will take up, before laying it out (this is so that I can adjust the font size accordingly so that it displays in a single line).
However if I do label.computeSize(SWT.DEFAULT, SWT.DEFAULT) it only returns the size that it needs without wrapping.
If there is a way to do it that would be great.
Fist of all the Label must be created with the SWT.WRAP style. Otherwise it will never wrap its text.
Then you need to tell computeSize what width the label should have. Otherwise computeSize doesn't know where to wrap and computes the size for the unwrapped text.
If you specify the desired width of the label, computeSize will return the neccesary height.
For example
Label label = new Label( shell, SWT.WRAP );
label.setText( "Snippets are minimal stand-alone programs that demonstrate specific techniques or functionality." );
Point size = label.computeSize( 200, SWT.DEFAULT );
System.out.println( size ); // Point {202, 47}
The returned size is a Point whose x field is (almost) the desired width and the y field denotes the necessary height to display the wrapped text.
On my system, the size is { 202, 47 } (the text spans two lines) but this may vary depending on the platform and font size.
Agree with Rudiger Herrmann's answer.
I have done it previously for my purpose. But it was dependent on OS. I have adjusted size of the font to make label in a line in a Grid. Please find comments in code.
parent.setLayout(new GridLayout(1, false));
label = new Label( parent, SWT.BORDER | SWT.WRAP );
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
label.setTouchEnabled(true);
label.setToolTipText("LABEL");
label.setForeground(SWTResourceManager.getColor(SWT.COLOR_DARK_MAGENTA));
label.setBackground(SWTResourceManager.getColor(SWT.COLOR_GREEN));
label.setText( "Stack Overflow is a question and answer site for professional and enthusiast programmermers. It's built and run by you as part of the Stack Exchange network of Q&A sites." );
Point parentCompositeSize = parent.getShell().getSize();
System.out.println(parentCompositeSize);
// parentCompositeSize.x is width of parent window (Shell) width, if you have your desired width of (window / Composite) then you can give it direct in int
// Calculation of number of lines with default font ::
// Warning:: Calculations have some assumption as below.
//1. Spacing between two lines will be 1 unit.
//2. My Layout used is GRID Layout.
Point estimatedLabelSize = label.computeSize( parentCompositeSize.x, SWT.DEFAULT );
System.out.println( "Estimated Label Height " + estimatedLabelSize.y);
FontData[] fD = label.getFont().getFontData();
int defaultFontSize = fD[0].getHeight(); //Font Height is 11 in my case.
defaultFontSize += 1; //1 is spacing between two lines, According to assumption
System.out.println(defaultFontSize + "default size");
int lines = estimatedLabelSize.y / defaultFontSize;
System.out.println("Default fonts will print " + lines + " lines" );
int suggestedFontSize = defaultFontSize / lines;
System.out.println(suggestedFontSize +" suggested size ");
fD[0].setHeight(suggestedFontSize);
final Font newFont = new Font(parent.getDisplay(), fD);
label.setFont(newFont);
label.addDisposeListener(new DisposeListener() {
#Override
public void widgetDisposed(DisposeEvent e) {
newFont.dispose();
}
});
Related
"TRYING OUT AUTO SIZING"
Font size too large, so much so part of the string is cut off (when text is too large, a portion is cut off and replaced with ellipsis).
"test text"
Font size too small. The fontSize is a third of its respective view (estimating).
How to set the fontSize of an Element to the size of the Element (and or containing Views) width? Use the examples above as reference - "test text" would take up much more of the view and "TRYING OUT AUTO SIZING" would take up far less.
NOTE: Black boxes denote other elements.
The desired goal is an element (label and or containing view) that when text is changed at run-time, the fontSize is set according to the text assigned and width available to it (this remains constant after build). So that all text is viewable in the string and it uses the width available to it.
Purpose is to support multiple platforms on a variety of devices with widely different scaling.
Whats been tried? NamedSizes based on the idiom (phone/tablet/etc) and manipulating these with multiplication and division based on OS (platform, i.e., IOS, Android, etC). This can't be best practice and there must be a way to go about accomplish this.
Following Xamarin.Forms guide for "fitting text to available size" or "empirically fitting text" yields results that are not as expected.. "CH5: Dealing with sizes"
Please advise on best practice and/or next steps.
Struct
struct FontCalc
{
public FontCalc(Label label, double fontSize, double containerWidth)
: this()
{
// Save the font size.
FontSize = fontSize;
// Recalculate the Label height.
label.FontSize = fontSize;
SizeRequest sizeRequest =
label.Measure(containerWidth, Double.PositiveInfinity);
// Save that height.
TextHeight = sizeRequest.Request.Height;
}
public double FontSize { private set; get; }
public double TextHeight { private set; get; }
}
Implementation
Label label;
public EmpiricalFontSizePage()
{
label = new Label();
Padding = new Thickness(0, Device.RuntimePlatform == Device.iOS ? 30 : 0, 0, 0);
ContentView contentView = new ContentView
{
Content = label
};
contentView.SizeChanged += OnContentViewSizeChanged;
Content = contentView;
}
void OnContentViewSizeChanged(object sender, EventArgs args)
{
// Get View whose size is changing.
View view = (View)sender;
if (view.Width <= 0 || view.Height <= 0)
return;
label.Text =
"This is text displayed. Does it work?";
// Calculate the height of the rendered text.
FontCalc lowerFontCalc = new FontCalc(label, 10, view.Width);
FontCalc upperFontCalc = new FontCalc(label, 100, view.Width);
while (upperFontCalc.FontSize - lowerFontCalc.FontSize > 1)
{
// Get the average font size of the upper and lower bounds.
double fontSize = (lowerFontCalc.FontSize + upperFontCalc.FontSize) / 2;
// Check the new text height against the container height.
FontCalc newFontCalc = new FontCalc(label, fontSize, view.Width);
if (newFontCalc.TextHeight > view.Height)
{
upperFontCalc = newFontCalc;
}
else
{
lowerFontCalc = newFontCalc;
}
}
// Set the final font size and the text with the embedded value.
label.FontSize = lowerFontCalc.FontSize;
label.Text = label.Text.Replace("??", label.FontSize.ToString("F0"));
}
(implementation code from XF docs linked above)
One solution is to use the NuGet package: Forms9Patch
Using its Lines and AutoFit properties we can achieve our desired result. In our case, we want one line and we want our FontSize set to what is required to make our text fit within one line. Lines = 1, AutoFit = Forms9Patch.AutoFit.Width, and FontSize set to a large value (does not matter if it is well over our desired max as setting AutoFit to Width shrinks font till to what is required to make text fit within our specified number of lines) results in a Label that automatically adjusts its FontSize to the maximum space available to it given the text length.
I was able to create page x of y using the Building Blocks example of Chapter 7: Handling events; setting viewer preferences and writer properties Solving the "Page X of Y" problem. In the example, the texts of "page x of y" are alligned via a Canvas with the page border. But very often is that the "x of y" shall be put into a table like this:
In such cases, the text shall be alligned within the table, how to do this?
In my application, the table which includes the page x of y shall be shown on each page and still at a fixed position, i.e. at the right upper position of a page. And the table format and size will not change for the whole document.
First of all, in order to fit the whole table, you would want to increase the bottom margin of the Document:
Document document = new Document(pdf);
document.setBottomMargin(100);
After that, you can still use Canvas to add a table instead of a paragraph. I will base the answer on the PageXofY example you refer to.
First of all, create a usual Table:
Table table = new Table(UnitValue.createPercentArray(new float[] {50, 50}));
table.addCell(new Cell(4, 1));
table.addCell(new Cell().add("Filename: "));
table.addCell(new Cell().add("Issue date: "));
Paragraph pageXofY = new Paragraph().
add("Page " + String.valueOf(pageNumber) + " of ").
add(new Image(placeholder));
table.addCell(new Cell().add(pageXofY));
table.addCell(new Cell().add("Location: "));
Note that we still use a placeholder FormXObject to store the total number of pages.
Change the side to font size, it is 12 in our case. Create placeholder like this:
placeholder = new PdfFormXObject(new Rectangle(0, 0, 2 * side, side));
Make a slight change to the writeTotal() method. The y position of the text has been changed to -descent:
public void writeTotal(PdfDocument pdf) {
Canvas canvas = new Canvas(placeholder, pdf);
canvas.showTextAligned(String.valueOf(pdf.getNumberOfPages()),
0, -descent, TextAlignment.LEFT);
}
Now all you need to to is add this table to the proper place on the page:
float marginX = 36;
Canvas canvas = new Canvas(pdfCanvas, pdf, new Rectangle(marginX, 10, pageSize.getWidth() - marginX * 2, 100));
canvas.add(table);
pdfCanvas.release();
The result looks like this:
Sorry, I'll try to explain better.
I want to make a sliding menu where you can select a character. I want the character that is at the center increases in size to know that this is the current character. The effect can be seen in the game of Crossy Road when you want to select a character.
Sorry but I can't upload a imagen because i am new in the forum
I think I might be able to help you without needing too much borrowed code. There are two possibilities here:
You have a perspective camera so the "selected" item can just be closer to the camera.
You have an orthographic camera so you will have to scale things.
For perspective:
List<GameObject> characters; //contains all character.
int selectedIndex = 0; //index to the selected character.
float spacing = 10; //space between chars
void Update()
{
if(Input.GetKeyDown("RightArrow"))
{
selectIndex++;
ApplyChanges();
}
if(Input.GetKeyDown("LeftArrow"))
{
selectIndex--;
ApplyChanges();
}
}
void ApllyChanges()
{
// Make sure the selected index is within range and then space the characters.
selectedIndex = selectedIndex % character.Count();
SpaceCharacters();
}
void SpaceCharacters()
{
for(int i = 0; i < characters.Count(); ++i)
{
// characters on the left will have a negative spacing and so will be placed to the left and vice versa for characters on the right.
int offset = i - selectedIndex;
characters[i].transform.position = new Vector3(offset * spacing, 0, 0);
}
// Move the selected character closer.
characters[selectedIndex].transform.position = new Vector3(0,0,spacing);
}
For orthographic camera you will need to set the select characters transform.scale to a larger vector.
This won't animate anything or look cool. This code will just snap your characters into position.
The solution I adopted was to attach objects to the transparent buttons in a scrool rect, so as to manage 3d objects with the convenient of scrool rect interface.
Here you can find the official documentation for use scrool rect: http://docs.unity3d.com/Manual/script-ScrollRect.html
Maybe my assets can serve you ;)
https://www.assetstore.unity3d.com/en/#!/content/60233
I am trying to fit a sentence that changes often, in to a few jlabels. Widths of my 3 jlabels stay unchanged all the time. What I am doing is changing the font size so all the characters can fit with out non being out of the display range of the labels. What I do is call below code snippet when ever sentence is changed.
Here is my code
String sentence = "Some long sentence";
int SentenceLength = sentence.length();
int FontSize = 0;
// sum of widths of the three labels
int TotalLblLength=lbl_0ValueInWords.getWidth()+lbl_1ValueInWords.getWidth()+lbl_1ValueInWords.getWidth();
/*decide the font size so that all the characters can be displayed
with out exceeding the display renge(horizontal) of the 3 labels
Inconsolata -> monopace font
font size == width of the font*2 (something I observed, not sure
if this is true always) */
FontSize=(TotalLblLength/SentenceLength)*2;
// max font size is 20 - based on label height
FontSize=(FontSize>20)?20:FontSize;
lbl_0ValueInWords.setFont(new java.awt.Font("Inconsolata", 0,FontSize));
lbl_1ValueInWords.setFont(new java.awt.Font("Inconsolata", 0,FontSize));
lbl_2ValueInWords.setFont(new java.awt.Font("Inconsolata", 0,FontSize));
int CharCount_lbl0 = width_lbl0 / (FontSize / 2);
int CharCount_lbl1 = width_lbl1 / (FontSize / 2);
int CharsCount_lbl2 = width_lbl2 / (FontSize / 2);
/*Set texts of each label
if sentence has more than the number of characters that can fit in the
1st label, excessive characters are moved to the 2nd label. same goes
for the 2nd and 3rd labels*/
if (SentenceLength > CharCount_lbl0) {
lbl_0ValueInWords.setText(sentence.substring(0, CharCount_lbl0));
if (SentenceLength > CharCount_lbl0 + CharCount_lbl1) {
lbl_1ValueInWords.setText(sentence.substring(CharCount_lbl0, CharCount_lbl0 + CharCount_lbl1));
lbl_2ValueInWords.setText(sentence.substring(CharCount_lbl0 + CharCount_lbl1, SentenceLength));
} else {
lbl_1ValueInWords.setText(sentence.substring(CharCount_lbl0, SentenceLength));
}
} else {
lbl_0ValueInWords.setText(sentence);
}
But even after resetting font size sometimes the last character goes out of the display range. I have removed margines from the jlabels that may cause this. This happens for random length sentences. I can solve the problem for the application by reducing label width used for the calculations(hopefully)
Can anyone explain me the reason? Could be because of some defect in the fonts symmetry?
There is no such thing as font symmetry?
There are 2 types of fonts for what you are dealing with. Monospace fonts, and non-monospace fonts. Monospace fonts have the same exact width for every single character you can type. The others do not.
On top of that, fonts are rendered differently across different OS's. Something on windows will be around 10-20% longer on Mac because they space out the fonts differently.
Whatever it is you are trying to do with JLabels, stop. You should not be using 3 JLabels to show 3 lines of text because they dont fit. Scrap them and use a JTextArea. It has text wrap, you can set the font, and remove the margin/border/padding and make it non-editable. You can customize it very easily so it is indistinguishable from a JLabel, but it will save you a ton of work.
Pick the right tool for the right job.
Wee.
So I finally figured out how the iIntegral member of TVITEMEX works. The MSDN docs didn't think to mention that setting it while inserting an item has no effect, but setting it after the item is inserted works. Yay!
However, when using the TVS_HASLINES style with items of variable height, the lines are only drawn for the top part of an item with iIntegral > 1. E.g. if I set TVS_HASLINES and TVS
Here's what it looks like (can't post images WTF?)
Should I manually draw more of the lines in response to NM_CUSTOMDRAW or something?
Yes, Windows doesn't do anything with the blank space obtained from changing the height.
From the MSDN:
The tree-view control does not draw in the
extra area, which appears below the
item content, but this space can be
used by the application for drawing
when using custom draw. Applications
that are not using custom draw should
set this value to 1, as otherwise the
behavior is undefined.
Alright, problem solved.
I failed to find an easy answer, but I did work around it the hard way. It's basically just drawing the extra line segments in custom draw:
// _cd is the NMTVCUSTOMDRAW structure
// ITEMHEIGHT is the fixed height set in TreeView_SetItemHeight
// linePen is HPEN of a suitable pen to draw the lines (PS_ALTERNATE etc.)
// indent is the indentation size returned from TreeView_GetIndent
case CDDS_ITEMPREPAINT : {
// Expand line because TreeView is buggy
RECT r = _cd->nmcd.rc;
HDC hdc = _cd->nmcd.hdc;
HTREEITEM hItem = (HTREEITEM) _cd->nmcd.dwItemSpec;
if( r.bottom - r.top > ITEMHEIGHT ) {
HGDIOBJ oldPen = SelectObject( hdc, linePen );
// Draw any lines left of current item
HTREEITEM hItemScan = hItem;
for( int i = _cd->iLevel; i >= 0; --i ) {
// Line should be drawn only if node has a next sibling to connect to
if( TreeView_GetNextSibling( getHWnd(), hItemScan ) ) {
// Lines seem to start 17 pixels from left edge of control. But no idea
// where that constant comes from or if it is really constant.
int x = 17 + indent * i;
MoveToEx( hdc, x, r.top + ITEMHEIGHT, 0 );
LineTo( hdc, x, r.bottom );
}
// Do the same for the parent
hItemScan = TreeView_GetParent( getHWnd(), hItemScan );
}
SelectObject( hdc, oldPen );
}
}
The pattern from the PS_ALTERNATE brush sometimes doesn't align perfectly with line drawn by the control, but that's hardly noticeable. What's worse is that even though I have the latest common controls and all the service packs and hotfixes installed, there are still bugs in TreeView documented way back in 2005. Specifically, the TreeView doesn't update its height correctly. The only workaround I've found for that is to force some collapsing/expanding of nodes and do a few calls to InvalidateRect.
If the variable-height nodes are at the root level, though, there doesn't appear to be anything you can do. Luckily I don't need that.