I am trying to rotate a label through 90 degrees. At the moment I can take the text from the label and rotate that, but what I want to do is actually rotate a label of my choice, or if I were to be really flashy, lets say a button control. So using the code below, how can I modify it so that I can feed it a control and get it to rotate it?
protected override void OnPaint(PaintEventArgs e)
{
Graphics graphics = e.Graphics;
string text = label4.Text;
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.Trimming = StringTrimming.None;
Brush textBrush = new SolidBrush(this.ForeColor);
//Getting the width and height of the text, which we are going to write
float width = graphics.MeasureString(text, this.Font).Width;
float height = graphics.MeasureString(text, this.Font).Height;
//The radius is set to 0.9 of the width or height, b'cos not to
//hide and part of the text at any stage
float radius = 0f;
if (ClientRectangle.Width < ClientRectangle.Height)
{
radius = ClientRectangle.Width * 0.9f / 2;
}
else
{
radius = ClientRectangle.Height * 0.9f / 2;
}
int rotationAngle = 90;
double angle = (rotationAngle / 180) * Math.PI;
graphics.TranslateTransform(
(ClientRectangle.Width + (float)(height * Math.Sin(angle)) - (float)(width * Math.Cos(angle))) / 2,
(ClientRectangle.Height - (float)(height * Math.Cos(angle)) - (float)(width * Math.Sin(angle))) / 2);
graphics.RotateTransform((float)rotationAngle);
graphics.DrawString(text, this.Font, textBrush, 0, 0);
graphics.ResetTransform();
}
Standard windows forms controls (such as a label and button) are rendered by the operating system itself, windows forms doesn't do the actual drawing.
Therefore, unfortunately, you have no control over aspects such as rotation and scaling with these sorts of controls. This is just a limitation of Windows Forms itself and is one of the major reasons Microsoft created WPF.
WPF controls are entirely rendered by WPF (using DirectX behind the scenes). WPF supports all the standard 2D (and 3D) transaformations such as scaling, rotation and translation.
Altrrnatively in windows forms you could create a custom control that you render using GDI+ and can rotate and scale as required. Of course now you're doing all the work yourself which it seems is not what you want.
You could use WPF instead of WinForms...then its a simple transform ;)
Related
I have a Visual Basic PowerPacks Oval Shape control, displayed as a Circle on the form and I want to increase its size from the center of the last position, so that I can increase it from all sides i.e. the center, how can I do it, I tried this.
//This code to draw circle on the clicked area.
MouseEventArgs clickArgs = (MouseEventArgs)e; Graphics graphics = this.CreateGraphics();
float circlesize = 100;
int x = Convert.ToInt32(clickArgs.X - circlesize / 2);
int y = Convert.ToInt32(clickArgs.Y - circlesize / 2);
ovalShape1.Location = new Point(x, y);
//To increase its size
ovalShape1.Width = ovalShape1.Width + 10;
ovalShape1.Height = ovalShape1.Height + 10;
The Current code is increasing the size from the last X,Y Position which is not correct. :(
I have a custom shape in WPF that creates two rectangles in the DefiningGeometry override and returns both as a GeometryGroup as follows:
protected override System.Windows.Media.Geometry DefiningGeometry
{
get
{
System.Windows.Media.GeometryGroup group = null;
System.Windows.Media.RectangleGeometry rectangle = null;
group = new System.Windows.Media.GeometryGroup();
if (this.Rectangle.IsEmpty)
{
group.Children.Add(System.Windows.Media.Geometry.Empty);
}
else
{
rectangle = new System.Windows.Media.RectangleGeometry(new System.Windows.Rect(this.Width * 0.1, this.Height - (this.Height * 0.1), this.Width * 0.8, this.Height * 0.1), 10, this.Height * 0.1);
group.Children.Add(rectangle);
rectangle = new System.Windows.Media.RectangleGeometry(new System.Windows.Rect(this.Width * 0.1, this.Height - (this.Height * 0.1), this.Width * 0.8, this.Height * 0.1), 10, this.Height * 0.1);
rectangle.Transform = new System.Windows.Media.RotateTransform(this.Tilt, this.Width / 2D, this.Height / 2D);
group.Children.Add(rectangle);
}
return (group);
}
}
The problem is I only want to apply a transform on the second rectangle but when I do that as illustrated above, it transforms other geometries in the group as well.
This is supposed to represent an animation with one static bar and one rotating (thus the transform). Any advice would be helpful.
UPDATE: I was wrong about the rotation transformation happening on both rectangles. Rotation is only happening on one. But due to that rotation, the canvas seems to translate due to which the first rectangle also moves (without rotating through). any idea what's going on here?
Here is an animated GIF. Wait for both sliders to go up and down on at a time.
The only thing changing here is the value of this.Tilt from -45 to +45 degrees.
I want to scale an image so that the image is always the size of the screen no matter how it is rotated. Does anyone have any ideas on going about this? By the way I am programing this in C# with xna.
Perhaps something similiar to this, although I'm unsure how you expect to draw the texture. It would be easiest by using triangles and texture wrapping them.
This is how I got the new width and new height after rotating:
Matrix origin = Matrix.CreateTranslation(0, 0, 0);
Matrix scale = Matrix.CreateScale(1f);
Matrix rotation = Matrix.CreateRotationZ(MathHelper.ToRadians(rotate));
Matrix translation = Matrix.CreateTranslation(0, 0, 0);
Vector2 pos1 = Vector2.Transform(new Vector2(Texture.Width / 2, Texture.Height / 2), origin * scale * rotation * origin);
Vector2 pos2 = Vector2.Transform(new Vector2(Texture.Width, Texture.Height), origin * scale * rotation * translation);
int width = (int)Math.Abs(pos2.X - pos1.X) * 2;
int height = (int)Math.Abs(pos2.Y - pos1.Y) * 2;
float scaleX = (graphics.PreferredBackBufferWidth / width);
float scaleY = (graphics.PreferredBackBufferHeight / height);
You will probably figure out the best way to draw this, because an image flipped 45 degrees will look weird drawn on the screen so you probably have to scale it up so it fits the screen but still be rotated. That you left out, an image rotated 180 degrees or 90 degrees should work better.
You can apply a RotateTransform to transform the image, then enclose that in a LayoutTransform to fill the dimensions of the container (the screen in this case).
I'm seeing strange behaviour when drawing a line with a scale transform (Graphics.ScaleTransform() - see MSDN) in my OnPaint() method.
When using a large y-scale factor for the ScaleTransform method, then if the x-scale is set above 1x, the line suddenly becomes much larger.
Setting the width of pen with which the line is drawn to -1 seems to get round the problem, but I do not want to draw a very thin line (the line must be printed later, 1px is too thin).
Here's some sample code to demonstrate the problem:
public class GraphicsTestForm : Form
{
private readonly float _lineLength = 300;
private readonly Pen _whitePen;
private Label _debugLabel;
public GraphicsTestForm()
{
ClientSize = new Size(300, 300);
Text = #"GraphicsTest";
SetStyle(ControlStyles.ResizeRedraw, true);
_debugLabel = new Label
{
ForeColor = Color.Yellow,
BackColor = Color.Transparent
};
Controls.Add(_debugLabel);
_lineLength = ClientSize.Width;
_whitePen = new Pen(Color.White, 1f); // can change pen width to -1
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
float scaleX = ClientSize.Width / _lineLength;
const int ScaleY = 100;
e.Graphics.Clear(Color.Black);
_debugLabel.Text = #"x-scale: " + scaleX;
// scale the X-axis so the line exactly fits the graphics area
// scale the Y-axis by scale factor
e.Graphics.ScaleTransform(scaleX, ScaleY);
float y = ClientSize.Height / (ScaleY * 2f);
e.Graphics.DrawLine(_whitePen, 0, y, _lineLength, y);
e.Graphics.ResetTransform();
}
}
I would like the line/pen to scale gracefully, without jumping in size so dramatically.
(Additionally, I noticed that when the line is very large, it is not drawn continuously across multiple monitors. Perhaps this is related?)
Try to change the pen width according to the scale:
_whitePen = new Pen(Color.White, 1f / ScaleY);
e.Graphics.DrawLine(_whitePen, 0, y, _lineLength, y);
I just compensated for the overall scaling in the pens line geometry;-
m_Pen->SetWidth(1.0f);
m_Pen->ScaleTransform(1.0f / ZoomX, 1.0f / ZoomY);
How to accomplish this simple functionality (simple in Winforms) in WPF?
Image is displayed with Stretch = "Uniform". After clicking on the image the coordinates (with respect to the source image) are saved and the clicking point is shown (small rectangle) over the image.
In winforms I did it by finding zoom and offsets of the sourceimage within PictureBox and than easily converted the image coordinates.
Next thing is in winforms I used GetGraphics() function so the marks were not persistent and could have been redrawn from the saved ones on every resize, the rectangles added in WPF stay ot their locations.
What is the best way to do this? Or is it better to use a WinForm control within the WPF window?
Edit:
Scale computing - copied from Winforms and updated
private void ComputeScale ()
{
if (image1.Source == null)
{
this.imageScale = 1;
this.offsetX = 0;
this.offsetY = 0;
return;
}
//todo: picture has to be bigger than PictureBox
decimal imW = (decimal)image1.Source.Width;
decimal imH = (decimal)image1.Source.Height;
decimal pbW = (decimal)image1.ActualWidth;
decimal pbH = (decimal)image1.ActualHeight;
decimal scaleX = pbW / imW;
decimal scaleY = pbH / imH;
decimal scale = Math.Min (scaleX, scaleY);
decimal offsetX = Math.Round ((pbW - Math.Round (imW * scale)) / 2);
decimal offsetY = Math.Round ((pbH - Math.Round (imH * scale)) / 2);
this.imageScale = scale;
this.offsetX = (int)offsetX;
this.offsetY = (int)offsetY;
}
Painting Rectangles
Point p = e.GetPosition(image1);
decimal x = ((decimal)(p.X - offsetX)) / imageScale;
decimal y = ((decimal)(p.Y - offsetY)) / imageScale;
System.Drawing.Point ClickedSample = new System.Drawing.Point((int)Math.Round(x), (int)Math.Round(y));
Samples.Add(ClickedSample);
//PaintSampleMark
Rectangle r = new Rectangle();
r.StrokeThickness=1;
r.Stroke= Brushes.Blue;
r.Width = sampleRadius*2;
r.Height= sampleRadius*2;
r.Margin = new Thickness ((double)(offsetX - sampleRadius + x), (double)(offsetY - sampleRadius + y), 0, 0);
canvas1.Children.Add(r);