I want to display two numbers in a full-screen manner,
above each other,
as regardless of actual screen size as possible.
//getting screen size and setting window to maximized
Rectangle screenEdge = Screen.PrimaryScreen.Bounds;
this.Width = screenEdge.Width;
this.Height = screenEdge.Height;
this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
this.WindowState = FormWindowState.Maximized;
//using 90% of width and 40% (times two) of height
int lWidth = (int)(this.Width * 0.9);
int lHeight = (int)(this.Height * 0.4);
//horiz. spacing: remainder, divided up for left and right
int lLeft = ( this.Width - lWidth ) / 2;
//vert. spacing: remainder divided for top, bottom and between
int lTop = ( this.Height - (2 * lHeight)) / 3 ;
//the labels holding the numbers
lSoll = new Label();
lIst = new Label();
//setting label lSoll to calc'd dimensions, adding & aligning text
lSoll.Left = lLeft;
lSoll.Width = lWidth;
lSoll.Top = lTop;
lSoll.Height = lHeight;
Font sollFont = new Font(FontFamily.GenericSansSerif, lSoll.Height);
Font sFSized = new Font(sollFont.FontFamily, lSoll.Height);
lSoll.Font = sFSized;
lSoll.TextAlign = ContentAlignment.MiddleCenter;
lSoll.ForeColor = Color.Blue;
lSoll.BackColor = Color.White;
updateSollText(42);
//same as above, just a bit lower
lIst.Left = lLeft;
lIst.Width = lWidth;
lIst.Top = lTop * 2 + lSoll.Height;
lIst.Height = lHeight;
Font istFont = new Font(FontFamily.GenericSansSerif, lIst.Height);
Font iFSized = new Font(istFont.FontFamily, lIst.Height);
lIst.Font = iFSized;
lIst.TextAlign = ContentAlignment.TopCenter;
lIst.ForeColor = Color.Red;
lIst.BackColor = Color.White;
updateIstText(39);
Issue with this code (besides clumsyness):
The text on the labels is displayed partly below the labels' lower bounds, i.e. invisible,
see screenshot at the bottom.
I double checked my calculations and found that other than a rounding error of 1 pt (tops) it all should work.
I also tried making the fontsize less than label height, which helped a little but was certainly not a fix.
I actually though the textalign should cover this, because that is what it is for.
Also chaning the height-comp(low middle top) of textalign did not change anything, whereas left / center / right do make the difference expected
What could be causing this?
The default unit of measurement for a font is points, not pixels. For example, with a default DPI setting of 96, a 9 point font takes up 9 * 96 / 72 = 12 pixels. So the font you ask for is too big and doesn't fit.
The workaround is simple, you can specify the unit of measurement you prefer with a Font constructor overload that takes a GraphicsUnit argument. Fix:
Font sollFont = new Font(FontFamily.GenericSansSerif, lSoll.Height, GraphicsUnit.Pixel);
Font sFSized = new Font(sollFont.FontFamily, lSoll.Height, GraphicsUnit.Pixel);
Related
I have a Windows form where I am adding a button control for each monitor attached to a computer. Naturally as the number of displays very from PC to PC, I want to automatically add a button per display and add them so they are displayed in a row.
Currently my code is as so:
foreach (var screen in Screen.AllScreens)
{
Button monitor = new Button
{
Name = "Monitor" + screen,
AutoSize = true,
Size = new Size(100, 60),
Location = new Point(12, 70),
ImageAlign = ContentAlignment.MiddleCenter,
Image = Properties.Resources.display_enabled,
TextAlign = ContentAlignment.MiddleCenter,
Font = new Font("Segoe UI", 10, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent,
Text = screen.Bounds.Width + "x" + screen.Bounds.Height
};
monitorPanel.Controls.Add(monitor);
}
This is working however, it's simply placing each button on top of each other where there is more than one display (as I expected it would):
What I want to achieve is that each button is added, but in a row next to each other. I've tried various threads, searches on Google etc to no avail. Could anyone point me in the right direction please?
IIRC AllScreens can be indexed, so:
var padding = 5;
var buttonSize = new Size(100, 60);
for (int i = 0; i < Screen.AllScreens.Length; i++)
{
var screen = Screen.AllScreens[i];
Button monitor = new Button
{
Name = "Monitor" + screen,
AutoSize = true,
Size = buttonSize,
Location = new Point(12 + i * (buttonSize.Width + padding), 70),
ImageAlign = ContentAlignment.MiddleCenter,
Image = Properties.Resources.display_enabled,
TextAlign = ContentAlignment.MiddleCenter,
Font = new Font("Segoe UI", 10, FontStyle.Bold),
ForeColor = Color.White,
BackColor = Color.Transparent,
Text = screen.Bounds.Width + "x" + screen.Bounds.Height
};
monitorPanel.Controls.Add(monitor);
}
That ought to do it.
Advantages of this over the other answers: counter/indexer is built into the loop.
I couldn't try but shouldn't you set the Location different per button?
Location = new Point(12, 70),
to e.g.
Location = new Point(12 + (100 + gap) * screen_index, 70),
where 100 is the width of the screen
gap is the gap between two screens
and screen_index the index from left to right
You are in control of setting the position. You are actually setting it yourself:
Size = new Size(100, 60),
Location = new Point(12, 70)
I'd suggest you increase location with the size of each button, and additional padding:
Location = new Point(screenNumber * (100 + 5), 70)
Or something. Of course screenNumber is a counter you have to declare, initialize and increment upon each iteration.
I using following code, When I run below code, Half of the text only displayed in label box. I want display full line in label box text? How to do it?
Label dynamiclabel1 = new Label();
dynamiclabel1.Location = new Point(280, 90);
dynamiclabel1.Name = "lblid";
dynamiclabel1.Size = new Size(150, 14);
dynamiclabel1.Text="Smith had omitted the paragraph in question (an omission which had escaped notice for twenty years) on the ground that it was unnecessary and misplaced; but Magee suspected him of having been influenced by deeper reasons.";
dynamiclabel1.AutoSize = true;
dynamiclabel1.Font = new Font("Arial", 10, FontStyle.Regular);
panel1.Controls.Add(dynamiclabel1);
Label dynamiclabel = new Label();
dynamiclabel.Location = new Point(38, 30);
dynamiclabel.Name = "lbl_ques";
dynamiclabel.Text = question;
//dynamiclabel.AutoSize = true;
dynamiclabel.Size = new System.Drawing.Size(900, 26);
dynamiclabel.Font = new Font("Arial", 9, FontStyle.Regular);
You have used AutoSize and explicit label size setting at the same time, this makes no sense.
If you want to enable word wrapping in your label text - you have to set dynamiclabel1.AutoSize = false; first and then increase its Height. Currently it has only 14 pixels of height so it is impossible to make text multiline. Increase it to something about 200 pixels and all the text will be placed inside the label in a few lines.
If you increase the height, and want less rows, set the Width property to something bigger;
dynamiclabel1.Width = 150;
If you want to select the number of lines depending on font/text size, you can do something like this:
Label dynamiclabel1 = new Label();
dynamiclabel1.Location = new Point(280, 90);
dynamiclabel1.Name = "lblid";
dynamiclabel1.Size = new Size(150, 100);
dynamiclabel1.Text = "Smith had omitted the paragraph in question (an omission which had escaped notice for twenty years) on the ground that it was unnecessary and misplaced; but Magee suspected him of having been influenced by deeper reasons.";
dynamiclabel1.Font = new Font("Arial", 10, FontStyle.Regular);
int lines = 3; //number of lines you want your text to display in
using (Graphics g = CreateGraphics())
{
SizeF size = g.MeasureString(dynamiclabel1.Text, dynamiclabel1.Font);
float w=size.Width / lines;
dynamiclabel1.Height = (int)Math.Ceiling(size.Height*lines);
dynamiclabel1.Width = (int)Math.Ceiling(w);
}
panel1.Controls.Add(dynamiclabel1);
Edit
If what you know is the width you have available and you want your label to adjust height to show all the content, can do this:
Label dynamiclabel1 = new Label();
dynamiclabel1.Location = new Point(280, 90);
dynamiclabel1.Name = "lblid";
dynamiclabel1.Size = new Size(150, 100);
dynamiclabel1.Text = "Smith had omitted the paragraph in question (an omission which had escaped notice for twenty years) on the ground that it was unnecessary and misplaced; but Magee suspected him of having been influenced by deeper reasons.";
dynamiclabel1.Font = new Font("Arial", 10, FontStyle.Regular);
int width = 600; //Width available to your label
using (Graphics g = CreateGraphics())
{
SizeF size = g.MeasureString(dynamiclabel1.Text, dynamiclabel1.Font);
lines = (int)Math.Ceiling(size.Width / width);
dynamiclabel1.Height = (int)Math.Ceiling(size.Height * lines);
dynamiclabel1.Width = width;
}
panel1.Controls.Add(dynamiclabel1);
I want to add text(say, annotations) in MS chart(winforms) like (10, 20) , (30, 40) where I already have a scroll bar.
I can able to draw strings(graphics.drawstring) in Chart, but on scrolling the horizontal scroll bar, the text which I have drawn remains static and immovable.
On scrolling the scrollbar, the text which I have drawn also should move along with my horizontal scrolling.
My code follows:
chart2.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
chart2.BorderlineColor = System.Drawing.Color.FromArgb(26, 59, 105);
chart2.BorderlineWidth = 3;
chart2.BackColor = Color.White;
chart2.ChartAreas.Add("chtArea");
chart2.ChartAreas[0].AxisX.Title = "Category Name";
chart2.ChartAreas[0].AxisX.TitleFont =
new System.Drawing.Font("Verdana", 11, System.Drawing.FontStyle.Bold);
chart2.ChartAreas[0].AxisY.Title = "UnitPrice";
chart2.ChartAreas[0].AxisY.TitleFont =
new System.Drawing.Font("Verdana", 11, System.Drawing.FontStyle.Bold);
chart2.ChartAreas[0].BorderDashStyle = ChartDashStyle.Solid;
chart2.ChartAreas[0].BorderWidth = 2;
chart2.ChartAreas["chtArea"].AxisX.ScrollBar.Enabled = true;
chart2.ChartAreas["chtArea"].CursorX.IsUserEnabled = true;
chart2.ChartAreas["chtArea"].CursorX.IsUserSelectionEnabled = true;
chart2.ChartAreas["chtArea"].AxisX.ScaleView.Zoomable = false;
chart2.ChartAreas["chtArea"].AxisX.ScrollBar.IsPositionedInside = true;
chart2.ChartAreas["chtArea"].AxisX.ScaleView.Size = 20;
chart2.ChartAreas[0].AxisX.ScaleView.SmallScrollSizeType = DateTimeIntervalType.Seconds;
chart2.ChartAreas[0].AxisX.ScaleView.SmallScrollSize = 1;
chart2.Legends.Add("UnitPrice");
chart2.Series.Add("UnitPrice");
chart2.Series[0].ChartType = SeriesChartType.Line;
Random rand = new Random();
var valuesArray = Enumerable.Range(0, 500).Select(x => rand.Next(0, 100)).ToArray();
for (int i = 0; i < 500; i++)
{
chart2.Series["UnitPrice"].Points.AddXY(i+10, valuesArray[i]);
}
I tried TextAnnotaions, Line annotations, etc Nothing helped me.
Then I tried drawing dynamic labels inside MS chart also. Labels remain immovable while scrolling horizontal scroll bar.
This code works perfectly in your machine also.
Sounds a lot as if you want to add TextAnnotations.
If you want them to stick with your data points you should anchor them to the points they shall stay with.
Here are a few examples:
// directly anchored to a point
TextAnnotation TA1 = new TextAnnotation();
TA1.Text = "DataPoint 222";
TA1.SetAnchor(chart2.Series["UnitPrice"].Points[222]);
chart2.Annotations.Add(TA1);
// anchored to a point but shifted down
TextAnnotation TA2 = new TextAnnotation();
TA2.Text = "DataPoint 111";
TA2.AnchorDataPoint = chart2.Series["UnitPrice"].Points[111];
TA2.AnchorY = 0;
chart2.Annotations.Add(TA2);
// this one is not anchored on a point:
TextAnnotation TA3 = new TextAnnotation();
TA3.Text = "At 50% width BC";
TA3.AnchorX = 50; // 50% of chart width
TA3.AnchorY = 20; // 20% of chart height, from top!
TA3.Alignment = ContentAlignment.BottomCenter; // try a few!
chart2.Annotations.Add(TA3);
By default they either anchor to DataPoints or are positioned in % of the chart size.
It is also possible to set the positions according to pixel coordinates, but for this you need to calculate the positions each time the chart changes its view!
See here for an example how to transform chart data positions to chart control coordinates and vice versa.. (Not really recommended, though)
I have been pulling my hair out on this one for ages now, so thought I'd try to get some help...
I'm working with PDFsharp (may or may not be significant) and trying to put a watermark into a pdf document when it gets downloaded via my asp.net web app.
My problem comes with that the user needs to be able to define the text in the watermark, so I can't use a fixed text size, also, the pdf page size can change.
Assuming that I'm using Arial and bold, and can find the page width in cm/mm/inch/pt, how do I calculate the font's emSize that is needed so that whatever text is entered grows/shrinks to fill the width?
The PDFsharp XFont constructor takes font name and emSize.
Edit:
Many thanks for the suggestions guys, this is what I implemented in the end:
PdfDocument doc = PdfReader.Open(stream, PdfDocumentOpenMode.Modify);
foreach (PdfPage page in doc.Pages)
{
double watermarkWidth = (Math.Sqrt(Math.Pow(page.Height.Point, 2) + Math.Pow(page.Width.Point, 2)));
//reduce by 10% so that the wording doesn't go right into the corners
watermarkWidth -= (watermarkWidth / 10);
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);
double emSize = 150;
XFont font = new XFont("Arial", emSize, XFontStyle.Bold);
XSize size = gfx.MeasureString(watermark, font);
while (size.Width > watermarkWidth && emSize > 10)
{
emSize -= 5;
font = new XFont("Arial", emSize, XFontStyle.Bold);
size = gfx.MeasureString(watermark, font);
}
gfx.TranslateTransform(page.Width / 2, page.Height / 2);
gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI);
gfx.TranslateTransform(-page.Width / 2, -page.Height / 2);
XGraphicsPath path = new XGraphicsPath();
path.AddString(watermark, font.FontFamily, XFontStyle.Bold, emSize,
new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2),
XStringFormats.Default);
XPen pen = new XPen(XColor.FromArgb(75, 255, 0, 0), 2);
gfx.DrawPath(pen, path);
}
doc.Save(stream, false);
Is the length of the watermark (in characters) limited? If so, you can take the allowed number of characters and calculate the width of strings like "###...", "WWW..." and "MMM..." in a loop with decreasing font sizes until it fits.
Then you will have a single font size that can be used for all texts.
The watermark will then be smaller - if you calculate the width for 30 "#" and the user just enters "Top Secret" ...
Better method: let the user enter the watermark, then use a loop with decreasing font sizes until the desired text fits into the available space.
Maybe this way (i dont know how PDFsharp works exactly, but in a normal Forms or Wpf this code would deliver the biggest possible Font)
public Font GetFont(Panel Wathermark, string textToPaint)
{
Font result = new Font("Bold", 1);
using (Graphics measure = Wathermark.CreateGraphics())
{
SizeF tempSize;
tempSize = measure.MeasureString(textToPaint, result);
while (tempSize.Width < Wathermark.Width && tempSize.Height < Wathermark.Height)
{
tempSize = measure.MeasureString(textToPrint, result);
var tempSizeToIncrease = result.Size; //writeprotected
result = new Font(result.Name, tempSizeToIncrease += 0.1f);
}
}
return result;
}
I'm developing a desktop application in C#, which shows pop-up messages every X quantity of time. For this, I'm using a library called PopupNotify, and I'd like the label that contains the message(called NotifyMessage) to have a fixed width, and vertically enlarge on overflow.
There is an event in which they set this up, but I can't modify it to make it work. Here is the event's code:
private void SetLayout()
{
int padding = 8;
int iconRightPadding = 0;
int border = 1;
iconBox.Left = padding + border;
iconBox.Top = padding + border;
iconBox.Width = IconWidth;
iconBox.Height = IconHeight;
this.Height = iconBox.Height + 2 * padding + 2 * border;
closeButton.Left = Width - padding - border - closeButton.Width + 3;
closeButton.Top = padding + border - 3;
NotifyTitle.Top = iconBox.Top - 5; //fudge factor
NotifyTitle.Left = iconBox.Right + iconRightPadding;
NotifyMessage.Left = NotifyTitle.Left + 1; //fudgy
NotifyMessage.Width = Width - NotifyMessage.Left - padding - border;
NotifyMessage.Top = NotifyTitle.Bottom;
NotifyMessage.Height = Height - NotifyMessage.Top - padding - border;
}
I've tried modifying it's logic, and the way it calculates its height by adding the NotifyMessage's height, and some other things, but none of them worked.
I'll appreciate any help on this.
You'll need to use TextRenderer.MeasureText to calculate required height of the label. This should be close:
public static int CalcLabelHeight(Label lbl) {
Size sz = new Size(lbl.ClientSize.Width, Int32.MaxValue);
sz = TextRenderer.MeasureText(lbl.Text, lbl.Font, sz, TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);
int height = sz.Height;
if (height < lbl.Font.Height) height = lbl.Font.Height;
return height + lbl.Padding.Vertical;
}
From there, set the form's ClientSize property to fit the label.
From my comment:
try docking that beautiful label
Something like this:
Graphics g = wnd.CreateGraphics();
String s = "Your string";
SizeF size = g.MeasureString(Font, s);
myHeight = size.Height + padding + border;
Use StringFormat as an argument to MeasureString to specify wrapping options when calculating the correct height.