In my app, I need text in myTextView to display single line without the three dots at the end. I need to show a little differently formatted text when it's too long, so something like setting maxHeight won't help since it just crops it.
My approach was to check how many lines the TextView has, and make the text in shorter if it has more than 1. This is exactly the approach I want, but since the View has to be drawn first to check LineCount, two-line layout flashes briefly before cutting the text to one-line:
myTextView.Post(() =>
{
if (myTextView.LineCount > 1)
{
// make text shorter here to fit 1 line
}
});
So my question is, is there any way to check how many lines the View will have before it is displayed to the user? I could force it based on character count in a string, but that seems wrong.
Firstly, set TextView Visibility to Invisible so that it takes up its space and then populate it.
There is a method that you can use to get the line count.
TextView txt = (TextView)findViewById(R.id.txt);
txt.getLineCount();
This returns an "int".
Use that int in your textChangedListener to play with the visibility of TextView.
This way you will know that how many line break does the TextView has.
Cheers.
So I came to a solution that works for me. It requires getting the screen width, calculating the width of the TextView and checking text length, everything in dp. So:
// get the screen width
var metrics = Resources.DisplayMetrics;
var widthInDp = (int)((metrics.WidthPixels) / metrics.Density);
// this line is very specific, it calculates the real usable space
// in my case, there was padding of 5dp nine times, so subtract it
var space = widthInDp - 9 * 5;
// and in this usable space, I had 7 identical TextViews, so a limit for one is:
var limit = space / days.Length;
// now calculating the text length in dp
Paint paint = new Paint();
paint.TextSize = myTextView.TextSize;
var textLength = (int)Math.Ceiling(paint.MeasureText(myTextView.Text, 0, myTextView.Text.Length) / metrics.Density);
// and finally formating based of if the text fits (again, specific)
if (textLength > limit)
{
myTextView.Text = myTextView.Text.Substring(0, myTextView.Text.IndexOf("-"));
}
It's pretty simple approach now that I look at it, but I'll just leave it here and maybe someone will find it useful.
Related
I would like to customize the Y axis labels of a graph plotted with Microsoft ReportViewer.
What I want is to have a logic like the following:
If (value>1000000)
return value/1000000 & "M"
else
return value
For example if the value of the label is 12000000 then the label value will be 12M, otherwise if the label value is 1200 the value will remain 1200.
I have tried to customize the numeric format to obtain this kind of behaviour tring something like:
= iif(value>1000000,value/1000000 'M',value)
(to help contextualize my question, i'm talking about this window=> https://dotnetblurb.files.wordpress.com/2012/05/3.jpg)
but, as expected, it didn't work.
Googling didn't help much as well, it seems like this kind of customization is just not possible. Or is it?
Thank you very much!
I solved this issue using both the expressions window and altering the graph's datasource content.
In the method filling the data source I added the logic converting big numbers into smaller numbers:
reportModel.MillionsSymbol = "";
if (reportModel.TotalValue > 1000000)
{
reportModel.TotalValue /= 1000000;
reportModel.MillionsSymbol = "M ";
}
I also added the new MillionsSymbol field to my data source and I change its content based on the TotalValue.
Then, I can use this new field in the dialog Vertical Axis Properties -> Number -> Category[custom]
="0.00" & Fields!MillionsSymbol.Value
The trick here is that I wrote an expression that is returning a string containing the characters mask needed by the function that is formatting the axis numbers' label. In this string I can put anything as long as it contains the mask (0.00, #.##,...).
This method allows me to concatenate a variable to the value that is going to appear as a label for every tick of the vertical axis of the graph. It doesn't allow me to work on that value, since I didn't find any way to get access to it. This is why I altered the values in the data source. In this way, though, I'm changing the value of the graph points and then conseguently the vertical axis ticks' values.
Final result:
*Image edited for clarity
I am writing a C# desktop application that requires a graphical representation (XoY) of some values (Y - value, X - (in) time).
chart1.Series[0].Points.AddXY(time, new Random().Next(-325, 531)); //this operation occurs at a set interval
The operation does its job, adding up values; however, in time the chart has the tendency to
"squeeze" itself which makes interpreting it a much harder task.
I want to make the graphic generate a better output, despite the number of points.
Notes
I consider that a good example of graphical representation would be one generated by an oscilloscope.
The chart is an spline.
The point addition is triggered upon a tick of a timer.
Depending on what you want there are several choices. My guess is that you want to keep all data points and simply want to add a scrollbar. To do you can write:
ChartArea A1 = chart1.ChartAreas["yourChartAreaByNameOrNumber"];
A1.AxisX.ScrollBar.Size = 12;
// show either just the center scroll button..
A2.AxisX.ScrollBar.ButtonStyle = ScrollBarButtonStyles.SmallScroll;
// .. or include the left and right buttons:
A1.AxisX.ScrollBar.ButtonStyle =
ScrollBarButtonStyles.All ^ ScrollBarButtonStyles.ResetZoom;
// looks better inside, but ymmv
A1.AxisX.ScrollBar.IsPositionedInside = true;
A1.AxisX.ScrollBar.Enabled = true;
A1.AxisX.ScaleView.Size = 100; // number (!) of data points visible
You may want to play with the size and placement. Please pick the number of data points you want to have visible at any time..
If you want the visible area to follow the new data like in an oscilloscope, you can set the scroll position :
Series S1 = chart1.Series["yourSeriesByNameOrNumber"];
A1.AxisX.ScaleView.Position = S1.Points.Count - A1.AxisX.ScaleView.Size;
Note that you need to set it again after adding any data!
If you also want to let the users adapt the zoom range set
A1.AxisX.CursorX.IsUserSelectionEnabled = true;
When the Microsoft chart control is zoomed in, the values of the labels and grid lines often looks like 38.2, 39.2, 40.2, 41.2 ... rather than 38,39,40,41. I tried to set the interval offset to correct this by using the code shown below without success.
myChart.ChartAreas[0].AxisX.MinorGrid.IntervalOffset = myChart.ChartAreas[0].AxisY.ScaleView.ViewMinimum % 1;
myChart.ChartAreas[0].AxisX.IntervalOffset = myChart.ChartAreas[0].AxisY.ScaleView.ViewMinimum % 1;
What is the proper way to get the major and minor grid-lines and labels to be drawn starting at a specific value?
Your problems might be caused by margins being added. Make sure you set
myChart.ChartArea[0].AxisX.IsMarginVisible = false;
My problem is to calculate the data (string) that can fit into the given page size (in inches).
I have an application which creates plain vanilla HTML report without using any reporting controls. Now I have to provide paging support in this report. the report is dynamic in nature i.e. columns are decided at run time.
Depending upon the page width, I want to wrap columns in multiple lines. For example, if the page width is 8", i want to fit only first 'n' columns in first line and rest columns can be displayed in second line (or more lines if required). For this I need to calculate how much data can fit in a 8" wide line.
Similarly, I want to calculate the height of data that can fit into the given height of page.
To summarize, how can I calculate how much data can fit into the given page size in inches.
Note: The calculation should also consider the font as it is decided at run time.
I have written a function to get the width of a span as rendered by the browser by adding it to the DOM checking for OffsetWidth and then removing it again. You could probably adapt the principle for other html elements although i doubt that going down that road will be very efficient. My application required this and i only used it to find the longest rendered pixelwidth in a list of strings. If i was you i would consider other approaches for large tables.
Nonetheless here's the function:
function GetTextWidth(text, font, fontSize) {
var size = 0;
var spanWidthTestEle = document.createElement("span");
spanWidthTestEle.id = "spanWidthTest";
spanWidthTestEle.style.fontFamily = font;
spanWidthTestEle.style.fontSize = fontSize;
spanWidthTestEle.innerText = text;
document.body.appendChild(spanWidthTestEle);
var spanWidthTest = document.getElementById("spanWidthTest");
size = spanWidthTest.offsetWidth;
document.body.removeChild(spanWidthTest);
return size;
}
I have a form on which I have a number of textboxes. I wish to print the text from these textboxes in the locations they are on the form. It is printing at the moment using the code below. However, the text prints differently on different printers (on some it prints just right, on some too high, etc). It is being printed on a pre-printed form with spaces for the text so it needs to be fairly exact. What am I missing to make it print the same on every printer?
public void printDocument_PrintPage(object sender, PrintPageEventArgs e)
{
Panel curPanel = this.FormPanel;
Graphics g = (Graphics)e.Graphics;
Pen aPen = new Pen(Brushes.Black, 1);
// Cycle through each control. Determine if it's a checkbox or a textbox and draw the information inside
// in the correct position on the form
int xLocation, yLocation;
for (int j = 0; j < curPanel.Controls.Count; j++)
{
// Check if its a TextBox type by comparing to the type of one of the textboxes
if (curPanel.Controls[j] is TextBox)
{
// Unbox the Textbox
TextBox theText = (TextBox)curPanel.Controls[j];
// Draw the textbox string at the position of the textbox on the form, scaled to the print page
xLocation = theText.Bounds.Left;
yLocation = theText.Bounds.Top;
g.DrawString(theText.Text, theText.Font, Brushes.Black, xLocation, yLocation);
}
}
}
The problem is that you ignoring how the text is aligned inside the control. Default alignment is roughly equal to StringFormat.Alignment = StringAlignment.Center, it can be changed for buttons and check boxes with their TextAlign property. You'll need to use the DrawString() overload that takes a Rectangle and a StringFormat. Note that TextBox is tricky, you might still be off by a few pixels.
Take a look at Control.DrawToBitmap() for a completely different approach.
I'm wondering if maybe the problem is discrepencies in how different printers pull in the paper. The text is off by a maximum of half an inch between printers. I was hoping this wasn't the case because if so I will just have to tailor my application to the client's particular printer (not ideal). Has anyone else run into this situation?
This is most likely a combination of two things:
You need to explicitly set up the page margins/boundaries. Various printers will have default margin and page size settings. Use a PageSetupDialog to help you out. If you want consistent printing, you can make the margins constant, but page size should be the responsibility of the user (and then check to make sure your margins actually fit on the page!).
The text needs to be placed on the page in relation to the page boundaries. I know your comment says that it will be, but it doesn't look like that it is actually implemented in your code. Setting the OriginAtMargins (on your PrintDocument control) to true helps immensely with this.