I am begin to study in Wpf, I want to use slider but I want to custom the slider control like image below:
The value of slider will be some of column with height increase like chart, and default column background color is black. When User drag and move from left to right, the column background of left side will be green color and opposite, the color will be black again. Please let me know if my question is not clear.
I found the solution by myself. I have two image stack up together, green background image is at bottom and black background image is at top. I have two event: MouseMove and MouseDown on image will get the position of mouse and set the opacity mask of top image. Opacity mask will set a part of image to transparent background. Of course, the bottom image will be display. See code below .
private void imgMusicBlack_MouseDown(object sender, MouseButtonEventArgs e)
{
var img = sender as Image;
SetOpacityMask(img, e.GetPosition(img).X);
}
private void imgMusicBlack_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
var img = sender as Image;
SetOpacityMask(img, e.GetPosition(img).X);
}
}
private void SetOpacityMask(Image img, double pointX, double offset = -1)
{
if (offset == -1)
offset = Math.Round(pointX / img.ActualWidth, 2);
LinearGradientBrush linear = new LinearGradientBrush();
linear.StartPoint = new Point(0, 0.5);
linear.EndPoint = new Point(1, 0.5);
linear.GradientStops = new GradientStopCollection();
linear.GradientStops.Add(new GradientStop(Colors.Transparent, offset));
linear.GradientStops.Add(new GradientStop(Colors.Black, offset));
img.OpacityMask = linear;
}
Related
I post this before and it was remove for being a duplicate. It is not. My problem is different then what that other people is doing. He is not doing zoom nor pan, and does not have a boarder.
I am using Stretch="Fill" to place my entire picture in the borders of an Image box. I am using a Border so that I can do Zoom and Pan. I am using the Canvas to draw rectangles around giving click areas. I want to map the left mouse click coordinates of the Canvas with zoom and pan back to the original image. here is my XAML code :
`
<Border x:Name="VideoPlayerBorder" ClipToBounds="True" Background="Gray" >
<Canvas x:Name="CanvasGridScreen" MouseLeftButtonDown="VideoPlayerSource_OnMouseLeftButtonDown" >
<Image x:Name="VideoPlayerSource" Opacity="1" RenderTransformOrigin="0.5,0.5" MouseLeftButtonUp="VideoPlayerSource_OnMouseLeftButtonUp" MouseWheel="VideoPlayerSource_OnMouseWheel" MouseMove="VideoPlayerSource_OnMouseMove" Width="{Binding Path=ActualWidth, ElementName=CanvasGridScreen}" Height="{Binding Path=ActualHeight, ElementName=CanvasGridScreen}" Stretch="Fill" >
</Image>
</Canvas>
`
here is my C# code:
`private void VideoPlayerSource_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
VideoPlayerSource.CaptureMouse();
var tt = (TranslateTransform)((TransformGroup)VideoPlayerSource.RenderTransform).Children.First(tr => tr is TranslateTransform);
start = e.GetPosition(VideoPlayerBorder);
origin = new Point(tt.X, tt.Y);
_stIR = start;
_stIR2 = start;
addRemoveItems(sender, e);
}
private void addRemoveItems(object sender, MouseButtonEventArgs e)
{
// this is the event that will check if we clicked on a rectangle or if we clicked on the canvas
// if we clicked on a rectangle then it will do the following
if (e.OriginalSource is Rectangle)
{
// if the click source is a rectangle then we will create a new rectangle
// and link it to the rectangle that sent the click event
Rectangle activeRec = (Rectangle)e.OriginalSource; // create the link between the sender rectangle
CanvasGridScreen.Children.Remove(activeRec); // find the rectangle and remove it from the canvas
}
// if we clicked on the canvas then we do the following
else
{
// generate a random colour and save it inside the custom brush variable
Custombrush = new SolidColorBrush(Color.FromRgb((byte)r.Next(1, 255),
(byte)r.Next(1, 255), (byte)r.Next(1, 233)));
// create a re rectangle and give it the following properties
// height and width 50 pixels
// border thickness 3 pixels, fill colour set to the custom brush created above
// border colour set to black
Rectangle newRec = new Rectangle
{
Width = 50,
Height = 50,
StrokeThickness = 3,
Fill = Custombrush,
Stroke = Brushes.Black
};
// once the rectangle is set we need to give a X and Y position for the new object
// we will calculate the mouse click location and add it there
Canvas.SetLeft(newRec, Mouse.GetPosition(CanvasGridScreen).X); // set the left position of rectangle to mouse X
Canvas.SetTop(newRec, Mouse.GetPosition(CanvasGridScreen).Y); // set the top position of rectangle to mouse Y
CanvasGridScreen.Children.Add(newRec); // add the new rectangle to the canvas
}
}
private void VideoPlayerSource_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
TransformGroup transformGroup = (TransformGroup)VideoPlayerSource.RenderTransform;
ScaleTransform transform = (ScaleTransform)transformGroup.Children[0];
double zoom = e.Delta > 0 ? .2 : -.2;
double transformScaleX = Math.Round((transform.ScaleX + zoom), 2);
double transformScaleY = Math.Round((transform.ScaleY + zoom), 2);
if (transformScaleX <= 8.2 && transformScaleX >= 1)
{
transform.ScaleX = Math.Round(transform.ScaleX + zoom, 2);
transform.ScaleY = Math.Round(transform.ScaleY + zoom, 2);
zoomFactor2 = zoomFactor2 + zoom;
zoomFactor = zoomFactor2;
}
}
void PanMethod(MouseEventArgs e)
{
var tt = (TranslateTransform)((TransformGroup)VideoPlayerSource.RenderTransform).Children.First(tr => tr is TranslateTransform);
Vector v = start - e.GetPosition(VideoPlayerBorder);
if (zoomFactor > 1.0)
{
tt.X = origin.X - v.X;
tt.Y = origin.Y - v.Y;
}
}
is there a function that would give me this information ? is there a way of using TransformGroup or ScaleTransform to return the actual location in the picture that was clicked? again the Image with possible zoom and/or pan
Check out: https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.visual.transformtovisual
The right way to translate coordinates back to the original pre-transforms control is to use the TransformToVisual helper. It's probably a good idea to do that regardless since transforms could be applied higher up in the stack.
In your case you want to call:
GeneralTransform transform = CanvasGridScreen.TransformToVisual(VideoPlayerSource);
Point normalizedPoint = transform.Transform(new Point(0, 0));
private void Side_pictureBox_Paint(object sender, PaintEventArgs e)
{
if (doubleclicked == true)
{
Side_pictureBox.Refresh();
for (int numbering_for_digram = 1; numbering_for_digram <= No_of_circle; numbering_for_digram++)
{
//MessageBox.Show(numbering_for_digram.ToString());
String drawString = numbering_for_digram.ToString();
// Create font and brush.
Font drawFont = new Font("Calibri (Body)", 20);
SolidBrush drawBrush = new SolidBrush(Color.Blue);
// Create point for upper-left corner of drawing.
//float x = 0;
//float y = 0;
doubleclicked = false;
// Draw string to screen.
e.Graphics.DrawString(drawString, drawFont, drawBrush, lastPoint);
Side_pictureBox.Update();
//MessageBox.Show("passed graphics draw");
}
}
}
}
private void Side_pictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (isMouseDown == true && Edit_Variables.add_remark_now==false)//check to see if the mouse button is down
{
if (lastPoint != null)//if our last point is not null, which in this case we have assigned above
{
if (Side_pictureBox.Image == null)//if no available bitmap exists on the picturebox to draw on
{
//create a new bitmap
Bitmap bmp = new Bitmap(Side_pictureBox.Width, Side_pictureBox.Height);
Side_pictureBox.Image = bmp; //assign the picturebox.Image property to the bitmap created
}
using (Graphics g = Graphics.FromImage(Side_pictureBox.Image))
{//we need to create a Graphics object to draw on the picture box, its our main tool
//when making a Pen object, you can just give it color only or give it color and pen size
g.DrawLine(new Pen(Color.DarkRed, 2), lastPoint, e.Location);
g.SmoothingMode = SmoothingMode.AntiAlias;
//this is to give the drawing a more smoother, less sharper look
}
Side_pictureBox.Invalidate();//refreshes the picturebox
lastPoint = e.Location;//keep assigning the lastPoint to the current mouse position
}
}
This is how the whole process works, firstly I will draw using a "Pen" on an image. This drawing process starts with mousedown and ends with mouseup event. Once mouseup is detected, I am to required to click on a point within the image and it suppose to drawstring(draws "1" on the image) on the image itself. For the first drawstring event it turns out fine. However, once I trigger the mousedown event, it will remove the previous drawstring("1"). Can someone help how can i prevent the "previous" drawstring to be remove? Thank you all alot!
Don't draw directly in the paint box. Draw in the Image of the PaintBox instead. And do this at the end of the your MouseMove event, before calling Side_pictureBox.Invalidate();
I try to draw an image from a image list in a ComboBox when the item is selected.
I am able to draw the image, but when the onSelctedIndexChanged event finish, I lost my image.
My ComboBox already have the DrawMode.OwnerDrawFixed.
I have a ListImage control named ImageList with 10 pictures.
For my short example I just need to draw in my ComboBox the image at position 1 of my ImageList, it's the reason why I get this.ImageList.Draw(g, 0, 0, **1**);
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
if (this.SelectedIndex > -1)
{
var g = this.CreateGraphics();
this.ImageList.Draw(g, 0, 0, 1);
}
}
Probably I am not subscribing to the right event. Any suggestion?
See the picture below with a breakpoint in SelectedIndexChanged after the image is drawn. It works, but I lose my image after the event.
Change your ComboBox DrawMode to OwnerDrawVariable.
Use the DrawItem event to draw the images from your source (an ImageList, in this case) inside the ComboBox item Bounds.
If the ComboBox DropDownStyle is set to DropDownList, the image will be shown in the selection box; if it's set to DropDown, only the text will be drawn.
Here, the Focus rectangle is only drawn when the mouse point hovers the ListControl's items, while it's not used when an item is selected, which is determined by:
(e.State.HasFlag(DrawItemState.Focus) && !e.State.HasFlag(DrawItemState.ComboBoxEdit)).
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0) return;
var cbo = sender as ComboBox;
Color foreColor = e.ForeColor;
if (e.State.HasFlag(DrawItemState.Selected) && !(e.State.HasFlag(DrawItemState.ComboBoxEdit))) {
e.DrawBackground();
e.DrawFocusRectangle(); // <= could be removed for a cleaner rendering
}
else {
using (var brush = new SolidBrush(cbo.BackColor)) {
var rect = e.Bounds;
rect.Inflate(1, 1);
e.Graphics.FillRectangle(brush, rect);
}
foreColor = cbo.ForeColor;
}
TextRenderer.DrawText(e.Graphics, cbo.GetItemText(cbo.Items[e.Index]), e.Font,
new Point(e.Bounds.Height + 10, e.Bounds.Y), foreColor);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawImage(imageList1.Images[e.Index],
new Rectangle(e.Bounds.Location,
new Size(e.Bounds.Height - 2, e.Bounds.Height - 2)));
}
The Magic Numbers here (10, -2) are just offsets:
e.Bounds.Height + 10 => 10 pixels to the right of the image.
e.Bounds.Height -2 => 2 pixels less than the item.Bounds.Height.
so am implementing a project that can read image pan it, zoom it and do other stuff.. everything was going well until i tried implementing a draw with right mouse button.
the problem is when i draw a line, the line that appears on the image does not correspond to the line i drew on screen, meaning its shifted and i know its because of the re-sizing and zooming of the image, but when i draw lines on the image with its original size(the image) and with panning also ; i have no problem.
here's the code.
so first here is how i load the image when i click browse and select image
Myimage = new Bitmap(ImagePath);
resized = myImage.Size;
imageResize();
pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox_Paint);
pictureBox.Invalidate();
the imageResize function does the following:
void imageResize()
{
//calculated the size to fit the control i will draw the image on
resized.Height = someMath;
resized.Width = someMath;
}
then in the event handler for the pictureBox_Paint event i wrote:
private void pictureBox_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// Create a local version of the graphics object for the PictureBox.
Graphics PboxGraphics = e.Graphics;
PboxGraphics.DrawImage(myImage, imageULcorner.X, imageULcorner.Y, resized.Width, resized.Height);
}
as you can see the resized size is not the original image size i did this because i wanted the image to show on the picturebox control centralized and filled now the next part IS WHERE MY PROBLEM BEGINS
i have to draw lines on image using right mouse button so i implemented pictureBox_MouseDown & pictureBox_MouseUp event handlers
// mouse down event handler
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
else if (mouse.Button == MouseButtons.Right)
{
mouseDown = mouse.Location;
mouseDown.X = mouseDown.X - imageULcorner.X;
mouseDown.Y = mouseDown.Y - imageULcorner.Y;
draw = true;
}
}
here is the mouse up event handler
//Mouse UP
private void pictureBox_MouseUp(object sender, MouseEventArgs e)
{
else if (mouse.Button == MouseButtons.Right)
{
if (draw)
{
mouseLocationNow.X = mouse.X - imageULcorner.X;
mouseLocationNow.Y = mouse.Y - imageULcorner.Y;
//
// get graphics object of the image ( the original not the resized)
// as the resized image only appears when i draw on the graphics of the
// pictureBox control
// i know the problem lies here but how can i fix it
//
Graphics image = Graphics.FromImage(myImage);
Pen pen = new Pen(Color.Red, 2);
image.DrawLine(pen, mouseLocationNow, mouseDown);
pictureBox.Invalidate();
}
draw = false;
}
so in the end i want to be able to draw on the re-sized image and make it correspond to the real image and also to the screen where i draw the line
thanks and sorry for the long post but this problem has been driving me crazy.
Here is a PictureBox subclass that supports the ability to apply zooming not only to the Image but also to graphics you draw onto its surface.
It includes a SetZoom function to zoom in by scaling both itself and a Matrix.
It also has a ScalePoint function you can use to calculate the unscaled coordinates from the pixel coordinates you receive in the mouse events.
The idea is to use a Transformation Matrix to scale any pixels the Graphics object will draw in the Paint event.
I include a little code for the form for testing.
public partial class ScaledPictureBox : PictureBox
{
public Matrix ScaleM { get; set; }
float Zoom { get; set; }
Size ImgSize { get; set; }
public ScaledPictureBox()
{
InitializeComponent();
ScaleM = new Matrix();
SizeMode = PictureBoxSizeMode.Zoom;
}
public void InitImage()
{
if (Image != null)
{
ImgSize = Image.Size;
Size = ImgSize;
SetZoom(100);
}
}
public void SetZoom(float zoomfactor)
{
if (zoomfactor <= 0) throw new Exception("Zoom must be positive");
float oldZoom = Zoom;
Zoom = zoomfactor / 100f;
ScaleM.Reset();
ScaleM.Scale(Zoom , Zoom );
if (ImgSize != Size.Empty) Size = new Size((int)(ImgSize.Width * Zoom),
(int)(ImgSize.Height * Zoom));
}
public PointF ScalePoint(PointF pt)
{ return new PointF(pt.X / Zoom , pt.Y / Zoom ); }
}
Here is the code in the Form that does the testing:
public List<PointF> somePoints = new List<PointF>();
private void scaledPictureBox1_MouseClick(object sender, MouseEventArgs e)
{
somePoints.Add(scaledPictureBox1.ScalePoint(e.Location) );
scaledPictureBox1.Invalidate();
}
private void scaledPictureBox1_Paint(object sender, PaintEventArgs e)
{
// here we apply the scaling matrix to the graphics object:
e.Graphics.MultiplyTransform(scaledPictureBox1.ScaleM);
using (Pen pen = new Pen(Color.Red, 10f))
{
PointF center = new PointF(scaledPictureBox1.Width / 2f,
scaledPictureBox1.Height / 2f);
center = scaledPictureBox1.ScalePoint(center);
foreach (PointF pt in somePoints)
{
DrawPoint(e.Graphics, pt, pen);
e.Graphics.DrawLine(Pens.Yellow, center, pt);
}
}
}
public void DrawPoint(Graphics G, PointF pt, Pen pen)
{
using (SolidBrush brush = new SolidBrush(pen.Color))
{
float pw = pen.Width;
float pr = pw / 2f;
G.FillEllipse(brush, new RectangleF(pt.X - pr, pt.Y - pr, pw, pw));
}
}
Here are the results after drawing a few points showing the same points in four different zoom settings; the ScaledPictureBox is obviously placed in an AutoScroll-Panel. The lines show how to use the regular drawing commands..
I loaded the jpg to picture box (in SizeMode as Zoom).
I drew a rectangle on the picture box and took the coordinate.
I opened the jpg in paint and observed the coordinate (where I drew the rectangle on the picture box).
When I compared the rectangle coordinates (x and y) with paint coordinates, they were not the same.
I changed the SizeMode to Normal and observed that the coordinates became the same, but the image size was too large so it was display partially, so I want to use Zoom SizeMode property.
Say image with size 2825x3538 and keep the picture box size mode as Normal, the image shows partially in picture box. So I changed picture box mode to Zoom (to fit the System screen resolution), and the coordinates missmatched when comparing it with Normal mode with SizeMode.
How can I achieve the same coordinates?
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
OpenFD.FileName = "";
OpenFD.Title = "open image";
OpenFD.InitialDirectory = "C";
OpenFD.Filter = "JPEG|*.jpg|Bmp|*.bmp|All Files|*.*.*";
if (OpenFD.ShowDialog() == DialogResult.OK)
{
file = OpenFD.FileName;
image = Image.FromFile(file);
pictureBox1.Image = image;
svc = Screen.PrimaryScreen;
pictureBox1.Width = svc.Bounds.Width;
pictureBox1.Height = svc.Bounds.Height - 100;
mybitmap1 = new Bitmap(pictureBox1.Image);
mybitmap1.SetResolution(300, 300);
pictureBox1.Image = mybitmap1;
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (mybitmap == null)
{
mybitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
mybitmap.SetResolution(300, 300);
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (g = Graphics.FromImage(mybitmap))
{
using (Pen pen = new Pen(Color.Green, m))
{
e.Graphics.DrawRectangle(pen, r);
e.Graphics.DrawString(lab[c].ToString(), new Font(lab[c].ToString(), 8F), new SolidBrush(label1.ForeColor), r);
}
}
}
You can use two scale factors between the actual image and the picture box, one with height and the other with width.