C# Printing Inconsistent - c#

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.

Related

Chart is rescaling area for axis labels when long labels appear due to scrolling

I have some string labels that are associated with a number each.
I've created a Chart element with one ChartArea and one Series which is using the SeriesChartType.Bar type to show my labels on the x-axis (which, confusingly, is the vertical axis when using the Bar type, but anyway...) and show the number as a bar next to it.
Since I have many labels that don't fit on the screen at once, I "enabled" the scrollbar using the Zoom method in my Paint event handler like this:
private void chart1_Paint(object sender, PaintEventArgs e)
{
var scaleView = chart1.ChartAreas.First().AxisX.ScaleView;
var pos = double.IsNaN(scaleView.Position) ? 0.0 : scaleView.Position;
scaleView.Zoom(pos, pos + chart1.Height / 22.0);
}
I don't know if this is the proper way to do that, but it does (almost) what I want:
show the scrollbar if there are too many data points (labels) to fit on the screen
update the visible area properly when the window is resized
There is only one annoying thing: If due to scrolling a long label appears in the visible area or disappears, the area occupied by the labels is adjusted to the longest visible label. I hope these screenshots explain what I mean:
Here one long label is visible (at the bottom):
Here I scrolled up by one unit so that the long label is not visible any more:
This is super annoying during scrolling as everything gets rescaled whenver a long label appears or disappears.
How to fix the area occupied by the labels to always fit the longest label in the series, no matter if it is currently visible or not? I tried IsLabelAutoFit = false for both, x- and y-axis, but that doesn't help.
Ok, I've got it. I used
chartArea.InnerPlotPosition.Auto = false;
InnerPlotPosition.X = 33.333;
to give one third of the chart area to the labels and the other two thirds to the bars.
InnerPlotPosition.Auto = false makes this fixed so that it doesn't update while scrolling.

DrawString and TextBox same rendering

Inside OnPaint of a form I am rendering some text on top of an image. For that I call Graphics.DrawString with word wrapping enabled. In order to be able to edit the text I occasionally show (and hide again after editing) an additional TextBox occupying the same rectangle as my hand drawn text and also with word wrapping enabled.
My idea was that the TextBox ought to render the text exactly like the DrawString command. However there appear to be small deviations of text position (and probably text size?). Moreover these deviations seem to vary depending on the chosen font so it is impossible to tune them manually.
While the deviations are not so terrible as such, they lead to irritating consequences when it comes to the automatic word wrapping. For example in the TextBox a word might appear on the second line while it might appear on the first line when rendered with DrawString after accepting the edit. Most of the time it works but for some rectangle sizes it fails.
If transparency had been available for TextBox, I would have used it instead of rendering text manually, but none of the solutions I found has worked.
Is there any hope that I can find out what settings synchronize the rendering between DrawString and TextBox ? Or is the latter an undocumented implementation detail of the win32 textbox?
The essentials of my code (g is a Graphics object from the paint event args):
stringFormat = new StringFormat(StringFormat.GenericDefault);
stringFormat.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.NoClip;
stringFormat.Trimming = StringTrimming.None;
stringFormatAutomaticLinebreak = new StringFormat(StringFormat.GenericDefault);
stringFormatAutomaticLinebreak.FormatFlags = StringFormatFlags.NoClip;
stringFormatAutomaticLinebreak.Trimming = StringTrimming.None;
if (Data.IsAutomaticLinebreak)
{
Rectangle boundingRectangle = new Rectangle(Data.TextPosition.X, Data.TextPosition.Y,
Data.WindowSize.Width-Data.TextPosition.X-1, Data.WindowSize.Height-Data.TextPosition.Y-1);
g.DrawString(Data.Text, Data.TextFont, Data.TextBrush, boundingRectangle, stringFormatAutomaticLinebreak);
}
else
{
g.DrawString(Data.Text, Data.TextFont, Data.TextBrush, Data.TextPosition.X, Data.TextPosition.Y, stringFormat);
}
and
surrogateTextBox = new TextBox();
surrogateTextBox.BorderStyle = BorderStyle.None;
surrogateTextBox.Multiline = true;
surrogateTextBox.Text = Data.Text;
surrogateTextBox.Font = Data.TextFont;
surrogateTextBox.Location = new Point(Data.TextPosition.X,Data.TextPosition.Y);
surrogateTextBox.Size = new Size(Data.WindowSize.Width-Data.TextPosition.X-1, Data.WindowSize.Height-Data.TextPosition.Y-1);
surrogateTextBox.WordWrap = Data.IsAutomaticLinebreak;
Controls.Add(surrogateTextBox);

Check how many lines TextView will have before it's displayed

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.

Limiting size of input to the size of a TextBox in C#

I've seen quite a few questions about scaling a TextBox to the size of the text, but only found a single question which talked about the reverse here. That question is also from 2010, and I believe the language has evolved since then, and there might be better solutions.
I'll clarify that I do not want to limit my input to an arbitrary number of characters, as the input may include newlines/vertical space. (Which, if it contained a lot of vertical space, could stretch the text beyond the bounds.)
Here's the situation:
Form 1 has a textbox. I want this textbox to remain a fixed size. Any data beyond the size should be cut off from the input.
I want to save Form 1's textbox's contents to a file.
In Form 2, I want to open the file and pull what was Form 1's textbox's contents. These will be saved in a separate textbox local to Form 2.
My strategy right now is to find a way to limit the input to the dimensions of the textbox, so that the textboxes in Form 1 and Form 2 are equivalent, and do not overflow their respective dimensions.
So my question is: How would I go about doing that?
Edit: Sorry, it appears my question didn't provide enough information. I also mis-typed the situation, so I'll re-write it below.
I'll step back and describe more of what I'm trying to do.
Let's assume I have a single Form, with the following two objects:
Textbox
Label
Anything I type into the Textbox I want to see on the Label's text. Input can be any letters, numbers, or special characters, including spaces and newline characters.
For the sake of consistent sizing, I want the label to be of a fixed graphical size; regardless of the number of characters in the label's text, the label object should be no larger than (x, y), where x and y are arbitrary height and width sizes.
I do not want data in the Textbox that cannot fit within the bounds of the label's size. The user should be prevented from entering data into the Textbox that would extend beyond the label's size bounds.
Are there any strategies not mentioned in the linked question that can determine whether a Textbox's text meets or extends past an arbitrary width and height?
The properties of the textbox give you a max length, you can also do it in code like so
var tb = new TextBox();
tb.MaxLength = 10
if you don't want to use that then you should use
var str = tb.Text.Remove(0, 10)
this will only give the str variable the first 10 characters no matter the length of whats actually in the textbox.
For what you want on form two, you need to give me more information about what you want.
edit after OP's edit
if you want the text in the textbox to be matched at the label level you want add a TextChanged Event to the property of the textbox and then have something like this
private void TextChanged(object sender, EventArgs e)
{
label1.Text = textBox1.Text;
}
having the label to a fixed size no matter what is isn't going to be good, ive done it, but this also begs the question, why are you duplicating your textbox information into a label. Why not just have it in a textbox

Setting Width of Textbox according to maxlenth

I am using winforms application and i want to set that width of textbox which will show characters till max length,in short something like width = maxlength.Any predefined property is there? or we have to calculate it manually?
//I am looking for this type of logic
private void Form1_Load(object sender, EventArgs e)
{
//sample project
textBox2.Width = textBox2.MaxLength;
textBox3.Width = textBox3.MaxLength;
textBox4.Width = textBox4.MaxLength;
}
You have a Unit Mismatch: Width is in Pixels, MaxLength in characters.
So you need to measure the Font using e.g. Graphics.MeasureString.. Works best for fixed Fonts like Consolas.
You can measure the font e.g. like this, using 'x' as a medium width letter:
using (Graphics G = textBox2.CreateGraphics())
textBox2.Width = (int) (textBox2.MaxLength *
G.MeasureString("x", textBox2.Font).Width);
There are other Font measurement methods like TextRenderer.MeasureText you could use; also both methods have options to fine tune the measurement. The default above will include some leeway.
If you use a fixed Font the width will be OK, if you don't you'll need to decide whether you'd rather be on the safe side (use "W" or "M" to measure) or not. "X" is a likely compromise. Or you could adapt dynamically in the e.g. the TextChanged event..
Use the Anchor property to define how a control is automatically resized as its parent control is resized
Anchoring a control to its parent control ensures that the anchored edges remain in the same position relative to the edges of the parent control when the parent control is resized.
Try this:
textbox1.MaxLength = 0//The default value is 0, which indicates no limit;
Refer this msdn link for more info:
msdn link for textbox maxlength

Categories