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.
Related
Good afternoon!
Tell me, is it possible to place msgbox in the center of the panel on the form? or is it easier to create a form as a message and call it centered?
You might be able to center a MessageBox in your Panel, but it's much easier to create a custom one. This might help you, you can play around with the Location, the Size and the other properties.
var myMessageBox = new Form
{
StartPosition = FormStartPosition.Manual,
ShowInTaskbar = false,
Size = new Size(400, 180),
Location = new Point(this.Location.X + panel1.Location.X + panel1.Width / 2 - 200, this.Location.Y + panel1.Location.Y + panel1.Height / 2 - 90),
Text = "MessageBox",
ShowIcon = false,
};
Label label = new Label
{
Name = "label",
Text = "Some text.",
AutoSize = true,
MaximumSize = new Size (myMessageBox.Width - 30, myMessageBox.Height),
Location = new Point(10, 65)
};
myMessageBox.Controls.Add(label);
myMessageBox.ShowDialog();
I have the below code to draw a button(s) onto a panel for each monitor that is currently connected to the PC.
var padding = 5;
var buttonSize = new Size(95, 75);
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), 14),
BackgroundImageLayout = ImageLayout.Stretch,
BackgroundImage = 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);
}
For devices with one or more monitors attached, the code works just fine and this is the end result:
However, while it works, I'd like to (if possible) order them as they appear in the Windows display view:
In the first screenshot, they are ordered as 2 | 3 | 1 instead of 3 | 2 | 1.
Is what I'm after possible?
Multiple screens in Windows are handled as one, big, "glued" working area. Based on that, order of screens in configuration is according to their position in the new working area. Assuming that all of your screens are in one line, you can just use
screen.Bounds.X
as ordering property. If the screens are layed out in multiple rows, then ordering will also have to consider Y component.
EDIT:
You could just use Linq for sorting, specifically OrderBy().
Example usage for case when screens are in one row and collection will be iterated once.
Change
for (int i = 0; i < Screen.AllScreens.Length; i++)
{
var screen = Screen.AllScreens[i];
to
foreach(var screen in Screen.AllScreens.OrderBy(i => i.Bounds.X))
{
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);
Good day all
Problem:
When creating the panel component, and assigning controls to it, with the
autosize = true
the width property does not change at all, the size remains the same (X:200,Y:100 like a drag 'n drop panel size)
this panel is
panel p
the panel's width changes when displayed (visually the width is different) but placing messagebox's displaying the width on designtime shows the panel with is 200.
What am I doing wrong?
public void AddMessage(position pos, string owner, string _message)
{
/// <summary>
/// Add's a label message panel to a parent panel
/// </summary>
/// <param name="pos">Use enum position, left is for message sent by you, right is message recieved.</param>
/// <param name="_message">Message to display</param>
owner += " :";
Panel p = new Panel()
{
MaximumSize = new Size(((int)Math.Round(this.Width * 0.8, 0)), int.MaxValue),
BackColor = (pos == position.left) ? Color.LightGreen : Color.LightSkyBlue,
AutoSize = false
};
Font bold = new Font(this.Font.FontFamily, float.Parse((this.Font.Size*1.1).ToString()), FontStyle.Bold);
Label O = new Label()
{
Location = new Point(_LABEL_MARGIN, _LABEL_MARGIN),
AutoSize = true,
Margin = new Padding(_LABEL_MARGIN),
MaximumSize = new Size((int)Math.Round(p.MaximumSize.Width * 0.38, 0), int.MaxValue),
Size = TextRenderer.MeasureText(owner, bold, new Size((int)Math.Round((p.MaximumSize.Width) * 0.38, 0), int.MaxValue), TextFormatFlags.EndEllipsis),
Font = bold,
Text = owner
};
MultiLineLabel l = new MultiLineLabel()
{
Location = new Point(O.Width + 5, _LABEL_MARGIN),
AutoSize = false,
Margin = new Padding(_LABEL_MARGIN),
MaximumSize = new Size(p.MaximumSize.Width - p.Margin.All, p.MaximumSize.Height - p.Margin.All),
Size = TextRenderer.MeasureText(_message, this.Font, new Size(p.MaximumSize.Width - _LABEL_MARGIN - O.Width - O.Left, int.MaxValue), TextFormatFlags.WordBreak),
Top = Top +3,
Text = _message
};
p.Controls.Add(O);
p.Controls.Add(l);
p.Location = new Point((pos == position.left) ? 10 :(this.Width - (p.Width + 10)), lastTop);
lastTop = _OBJEcT_BUFFER + p.Top + p.Height;
this.Controls.Add(p);
}
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)