I want to zoom in/out vector graphics base on mouse pointer as center.
My code like that:
Matrix m_globalMatrix = new Matrix();
PointF m_scalePos;
float m_perZoom = 1.2f;
float m_zoom = 1f;
void ReCoord(){
m_globalMatrix.Reset();
m_globalMatrix.Translate(m_scalePos.X, m_scalePos.Y);
m_globalMatrix.Scale(m_zoom, m_zoom);
m_globalMatrix.Translate(-m_scalePos.X, -m_scalePos.Y);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
//PointF temp;
//temp = CoordTransform(e.Location);
m_scalePos = (PointF)ScreenToCoord(e.Location);
Console.WriteLine("m_scalePos:{0},Zoom:{1}", m_scalePos, m_zoom);
if (e.Delta < 0)
{
m_zoom /= m_perZoom;
}
else
{
m_zoom *= m_perZoom;
}
ReCoord();
Invalidate();
}
public CoordPoint ScreenToCoord(PointF screenPoint)
{
PointF[] points = new PointF[] { screenPoint };
Matrix mx = m_globalMatrix.Clone();
mx.TransformPoints(points);
/*
mx = m_coordMatrix.Clone();
mx.TransformPoints(points);
*/
return points[0];
/* I have struct like that:
struct CoordPoint{
float x,y;
public static implicit operator CoordPoint(System.Drawing.PointF p)
{
return new CoordPoint(p.X, p.Y);
}
}
*/
}
When the m_zoom arrived at 10 or more,it will be abnormal.
The mouseWheel scroll quickly,it will also be abnormal.
For example,when I slowly scroll mousewheel at point (50,50) before m_zoom < 10,it will print m_scalePos:(50,50).
The exception will not print m_scale:(50,50),even throw OverflowException.
There are my test paint Code:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (m_bmpBuffer == null)
{
ReSize(ClientRectangle.Width, ClientRectangle.Height);
}
m_graphics.FillRectangle(Brushes.Black, this.ClientRectangle);
PointF[] pts = new PointF[]{
new PointF(20,20),
new PointF(80,80),
new PointF(20,80),
new PointF(80,20),
new PointF(0,0)
};
for (int i = 0; i < pts.Length; i++)
{
pts[i] = (PointF)ScreenToCoord(pts[i]);
}
m_graphics.DrawLine(Pens.White, pts[0], pts[1]);
m_graphics.DrawLine(Pens.White, pts[2], pts[3]);
e.Graphics.DrawImage(m_bmpBuffer, 0, 0);
}
I aim at implementing as this picture:
enter image description here
Related
I would like to design a chess board and drag over pieces (shown in pictureBox Controls) all child of the main board (pictureBox1).
Problem I encounter is the transparency is only set to the Parent pictureBox1.
Which shows this effect: The square is showing.
private void CommonPiece_Mouse_Move(object sender, MouseEventArgs e)
{
if (Piece_Selected)
{
int MousePositionX = pictureBox1.PointToClient(Cursor.Position).X;
int MousePositionY = pictureBox1.PointToClient(Cursor.Position).Y;
(sender as PictureBox).Left = MousePositionX - 35;
(sender as PictureBox).Top = MousePositionY - 25;
}
}
What would be a good way to go about it?
There are several solutions for this problem. The one in the following screen recording, is based on drawing png images as movable shapes; it uses the idea that I've explained in How to drag and move shapes in C#. Basically there's only one control -the drawing surface, and all the other stuff are movable drawings.
You can use any image for the pieces by passing an Image to the ImageShape
You can modify the size of the Pieces by setting Height of the shape
It supports snapping to the grid
You can customize the texture, easily by setting the BackgroundImage of the drawing surface
You can change the grid size, by setting GridSize property of the drawing surface
You can change the Color of White and Grid grids, by assigning the color to WhiteColor and BlackColor
It's of course a quick example showing how to draw movable objects, including png images keeping their transparency. You know how to improve it :)
Drawing and moving shapes - Chess pieces
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
public interface IShape
{
bool HitTest(Point p);
void Draw(Graphics g);
void Move(int dx, int dy);
Point Location { get; set; }
}
public class ImageShape : IShape
{
public int Height { get; set; } = 100;
public Point Location { get; set; }
private Image _image;
public ImageShape(Image image)
{
_image = image;
}
public void Draw(Graphics g)
{
var r = new Rectangle(Location, new Size(Height, Height));
r.Inflate(-5, -5);
g.DrawImage(_image, r);
}
public bool HitTest(Point p)
{
return new Rectangle(Location, new Size(Height, Height)).Contains(p);
}
public void Move(int dx, int dy)
{
Location = new Point(Location.X + dx, Location.Y + dy);
}
}
public class DrawingSurface : Control
{
public List<IShape> Shapes { get; private set; }
public int GridSize { get; set; } = 100;
public Color WhiteColor = Color.FromArgb(200, Color.White);
public Color BlackColor = Color.FromArgb(120, Color.Black);
IShape selectedShape;
bool moving;
Point previousPoint = Point.Empty;
public DrawingSurface()
{
DoubleBuffered = true;
ResizeRedraw = true;
Shapes = new List<IShape>();
}
protected override void OnMouseDown(MouseEventArgs e)
{
for (var i = Shapes.Count - 1; i >= 0; i--)
if (Shapes[i].HitTest(e.Location))
{
selectedShape = Shapes[i];
break;
}
if (selectedShape != null)
{
moving = true;
previousPoint = e.Location;
Invalidate();
}
base.OnMouseDown(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (moving)
{
var dx = e.X - previousPoint.X;
var dy = e.Y - previousPoint.Y;
selectedShape.Move(dx, dy);
previousPoint = e.Location;
this.Invalidate();
}
base.OnMouseMove(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (moving)
{
int i = (e.X / GridSize) * GridSize;
int j = (e.Y / GridSize) * GridSize;
selectedShape.Location = new Point(i, j);
selectedShape = null;
moving = false;
this.Invalidate();
}
base.OnMouseUp(e);
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.InterpolationMode = InterpolationMode.High;
g.SmoothingMode = SmoothingMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
g.CompositingQuality = CompositingQuality.HighQuality;
foreach (var shape in Shapes.Except(new[] { selectedShape }))
shape.Draw(g);
if (selectedShape != null)
selectedShape.Draw(g);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
var g = e.Graphics;
using (var w = new SolidBrush(WhiteColor))
using (var b = new SolidBrush(BlackColor))
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
g.FillRectangle((i + j) % 2 == 0 ? b : w,
i * GridSize, j * GridSize, GridSize, GridSize);
}
}
To add pieces:
private void Form1_Load(object sender, EventArgs e)
{
this.drawingSurface1.Shapes.Add(new ImageShape(
Properties.Resources.KingWhite) { Location = new Point(0, 0) });
this.drawingSurface1.Shapes.Add(
new ImageShape(Properties.Resources.kingBlack) { Location = new Point(0, 100) });
}
Here's an example that makes the PictureBox Non-Rectangular. The PB will literally not exist where the transparent areas were:
using System.Runtime.InteropServices;
namespace CS_Scratch_WindowsFormsApp2
{
public partial class Form1 : Form
{
public const int HT_CAPTION = 0x2;
public const int WM_NCLBUTTONDOWN = 0xA1;
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern bool ReleaseCapture();
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
public Form1()
{
InitializeComponent();
pbChessPiece.MouseMove += PbChessPiece_MouseMove;
}
private void PbChessPiece_MouseMove(object sender, MouseEventArgs e)
{
PictureBox pb = (PictureBox)sender;
if (!DesignMode && e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(pb.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
}
}
private void button1_Click(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)pbChessPiece.Image;
Region rgn = new Region();
rgn.Union(new Rectangle(0, 0, bmp.Width, bmp.Height));
for(int x=0; x<bmp.Width; x++)
{
for(int y=0; y<bmp.Height; y++)
{
if (bmp.GetPixel(x, y).A == 0)
{
rgn.Exclude(new Rectangle(x, y, 1, 1));
}
}
}
pbChessPiece.Region = rgn;
}
}
}
Example run:
I did something similar, but I did not use Drag & Drop events
On MouseDown I assumed a drag operation started, I've opened a translucent unfocused window on top of the drop area, and started drawing dragged image on that form. Since the form is translucent it can show images with transparency on top of everything. I did not use images, but instead draw rectangles where users could drop. If my memory serves me correct, MouseMove events are forwarded to the dragged component, the original chess piece in your case, or the opened but unfocused form, so I can easily track the location. On MouseUp event I wrapped everything.
Since you can draw the image on the new form you can tilt image chess piece image to the left or right for a nice touch.
I developed a very strict forms designer application using this technique.
You can use the panel instead of using the pictureBox and display the image in the background of the controls. Remember that your images must be "png" and the surrounding of the image must be completely transparent. Also, the background color of the controls of the panels Set by events so that it becomes transparent during drag and returns to the cell color after drag and drop.
Good luck.
I'm trying to make a program that is able to read a dxf file and plot it's contents but when I try to draw the figures in the window's paint event, nothing is drawn unless I use this.Invalidate(); and this doesn't completely work because the objects appear to blink on the screen. The coordinates to draw the lines are stored in a list declared in the window class.
private void InitialWindow_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen blackPen = new Pen(Color.Black, 1);
if (entities.Count != 0)
{
for (int i = 0; i < entities.Count; i++)
{
for (int k = 0; k < entities[i].path.Count - 1; k++)
{
g.DrawLine(blackPen, D2F(entities[i].path[k]), D2F(entities[i].path[k + 1]));
}
g.DrawLine(blackPen, D2F(entities[i].path[0]), D2F(entities[i].path.Last()));
}
}
}
2DF is a function that converts a point-like type of data to PointF so it can be used in DrawLine. If I try to draw outside the for loops the lines are displayed correctly on the screen. Thanks in advance for any help with it.
I suggest you create a class to handle the model-to-pixel conversions (and in reverse) instead of a function D2F(). A class it going to give you a lot more flexibility and it will retain a state of the current scaling values
public class Canvas
{
public Canvas()
{
Target = new Rectangle(0, 0, 1, 1);
Scale = 1;
}
public Rectangle Target { get; set; }
public float Scale { get; set; }
public void SetModelBounds(float width, float height)
{
Scale = Math.Min(Target.Width / width, Target.Height / height);
}
public PointF ToPixel(Vector2 point)
{
var center = new PointF(Target.Left + Target.Width / 2, Target.Top + Target.Height / 2);
return new PointF(center.X + Scale * point.X, center.Y - Scale * point.Y);
}
public Vector2 FromPixel(Point pixel)
{
var center = new PointF(Target.Left + Target.Width / 2, Target.Top + Target.Height / 2);
return new Vector2((pixel.X - center.X) / Scale, -(pixel.Y - center.Y) / Scale);
}
}
This is setup for each paint event by calling for example
Canvas.Target = this.ClientRectangle;
Canvas.SetModelBounds(2f, 2f);
The above code is going to place coordinates (-1,-1) on the bottom left of the form surface, and (1,1) on the top right. The pixels per model unit are kept the same for x-axis and y-axis (see Canvas.Scale).
Now for the drawing, also use am Entity class to hold the drawing geometry, and various other properties such as color, and if the shape is closed or not. Note that if it defines a Render(Graphics g, Canvas canvas) method, then it can be called by the form and each entity can handle its own drawing (for the most modular design)
Here is an example:
public class Entity
{
Entity(bool closed, Color color, params Vector2[] path)
{
Color = color;
Path = new List<Vector2>(path);
Closed = closed;
}
public Color Color { get; set; }
public List<Vector2> Path { get; }
public bool Closed { get; set; }
public void Render(Graphics g, Canvas canvas)
{
using (Pen pen = new Pen(Color, 1))
{
var points = Path.Select(pt => canvas.ToPixel(pt)).ToArray();
if (Closed)
{
g.DrawPolygon(pen, points);
}
else
{
g.DrawLines(pen, points);
}
}
}
public static Entity Triangle(Color color, Vector2 center, float width, float height)
{
return new Entity(true, color, new Vector2[] {
new Vector2(center.X-width/2, center.Y - height/3),
new Vector2(center.X+width/2, center.Y - height/3),
new Vector2(center.X, center.Y+2*height/3) });
}
public static Entity Rectange(Color color, Vector2 center, float width, float height)
{
return new Entity(true, color, new Vector2[] {
new Vector2(center.X-width/2, center.Y-height/2),
new Vector2(center.X+width/2, center.Y-height/2),
new Vector2(center.X+width/2, center.Y+height/2),
new Vector2(center.X-width/2, center.Y+height/2) });
}
public static Entity Polygon(Color color, params Vector2[] path)
=> new Entity(true, color, path);
public static Entity Polyline(Color color, params Vector2[] path)
=> new Entity(false, color, path);
}
The above is used in the form as follows
public partial class Form1 : Form
{
public Canvas Canvas { get; }
public List<Entity> Entities { get; }
public Form1()
{
InitializeComponent();
Entities = new List<Entity>();
Canvas = new Canvas();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Resize += (s, ev) => Invalidate();
this.Paint += (s, ev) =>
{
ev.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Canvas.Target = ClientRectangle;
Canvas.SetModelBounds(2f, 2f);
foreach (var item in Entities)
{
item.Render(ev.Graphics, Canvas);
}
};
Entities.Add( .. )
}
}
As you can see the Paint event calls the Render() method for each entity.
In fact, you can generalize this model using an interface IRender. In the example below besides Entity that implements the interface, I define a class to draw the coordinate axis called Axes.
public interface IRender
{
void Render(Graphics g, Canvas canvas);
}
public class Axes : IRender
{
public void Render(Graphics g, Canvas canvas)
{
PointF origin = canvas.ToPixel(Vector2.Zero);
PointF xpoint = canvas.ToPixel(Vector2.UnitX);
PointF ypoint = canvas.ToPixel(Vector2.UnitY);
using (Pen pen = new Pen(Color.Black, 0))
{
pen.CustomEndCap = new AdjustableArrowCap(2f, 5f);
g.DrawLine(pen, origin, xpoint);
g.DrawLine(pen, origin, ypoint);
}
}
}
public class Entity : IRender
{
...
}
and now you can draw with quite a bit of varying things on the screen with the above framework. Here is an example that draws the axis (of unit size) and a few sample entities.
Entities.Add(Entity.Polygon(Color.Orange, Vector2.Zero, -Vector2.UnitX, -Vector2.One));
Entities.Add(Entity.Rectange(Color.Blue, new Vector2(0.5f, 0.5f), 0.25f, 0.25f));
Entities.Add(Entity.Triangle(Color.Red, new Vector2(0.5f, 0.75f), 0.25f, 0.25f));
Entities.Add(Entity.Polyline(Color.Magenta,
new Vector2(0f, -0.2f), new Vector2(0f, -0.4f), new Vector2(0.2f, -0.4f),
new Vector2(0.2f, -0.2f), new Vector2(0.4f, -0.2f), new Vector2(0.4f, -0.4f)));
I have a winforms app where I draw on an image in a picturebox. The drawing part works really well, except for lag when PictureBox.SizeMode = PictureBoxSizeMode.Zoom. The reason I set the SizeMode to Zoom is so I could zoom in and out of the image while preserving memory. Is there any way to speed up the drawing process?
The code for the PictureBox's Paint method looks like so:
pen = new Pen(color, 5);
solidBrush = new SolidBrush(solid);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.ScaleTransform(PictureScale, PictureScale);
foreach (List<Point> polygon in Polygons)
{
e.Graphics.DrawLines(pen, polygon.ToArray());
}
if (NewPolygon != null)
{
Pen pp = new Pen(color, 5);
if (NewPolygon.Count > 1)
{
e.Graphics.DrawLines(pp, NewPolygon.ToArray());
}
if (NewPolygon.Count > 0)
{
using (Pen dashed_pen = pp)
{
dashed_pen.DashPattern = new float[] { 3, 3 };
e.Graphics.DrawLine(dashed_pen, NewPolygon[NewPolygon.Count - 1], NewPoint);
}
}
}
The code allows the user to draw a series of points connected by some solid lines. After adding the first point, there is a dotted line going from the previous point to the mouse's current position. The program 'fills' in the line when the user adds a new Point NewPolygon is a List<Point> object, and the program adds a point every time the user clicks. Pol is a List<List<Point>> object which holds NewPolygon. I attached a GIF of the drawing process because an image is worth 1000 words. The lag in the gif is not noticeable at all in different size modes.
The if (NewPolygon.Count > 1) loop draws solid lines between at least 2 points. The if (NewPolygon.Count > 0) draws a dotted line between spot and NewPoint when there is at least one point.
EDIT : full drawing code
int x = 0;
int y = 0;
bool drag = false;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
Point spot = new Point((int)((float)(e.Location.X) / PictureScale), (int)((float)(e.Location.Y) / PictureScale));
if (e.Button == MouseButtons.Middle)
{
x = e.X;
y = e.Y;
drag = true;
}
else
{
if (NewPolygon != null)
{
if (e.Button == MouseButtons.Right)
{
if (NewPolygon.Count > 1)
{
int counter = NewPolygon.Count;
Polygons.Add(NewPolygon);
}
NewPolygon = null;
}
else if (e.Button == MouseButtons.Left)
{
if (NewPolygon[NewPolygon.Count - 1] != spot)
{
NewPolygon.Add(spot);
scaffolds.Add(new Rectangle(spot.X - 3, spot.Y - 3, 6, 6));
}
}
}
else
{
NewPolygon = new List<Point>();
NewPoint = spot;
NewPolygon.Add(spot);
scaffolds.Add(new Rectangle(spot.X - 3, spot.Y - 3, 6, 6));
}
}
//this.Capture = true;
pictureBox1.Refresh();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (drag)
{
pictureBox1.Top += e.Y - y;
pictureBox1.Left += e.X - x;
this.Cursor = Cursors.SizeAll;
}
else
{
if (NewPolygon == null)
return;
NewPoint = new Point((int)((float)(e.Location.X) / PictureScale), (int)((float)(e.Location.Y) / PictureScale));
pictureBox1.Refresh();
}
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.ScaleTransform(PictureScale, PictureScale);
foreach (Rectangle rect in scaffolds)
{
e.Graphics.DrawEllipse(pen, rect);
}
foreach (List<Point> polygon in Polygons)
{
e.Graphics.DrawLines(pen, polygon.ToArray());
}
if (NewPolygon != null)
{
Pen pp = new Pen(color, 5);
if (NewPolygon.Count > 0)
{
if (NewPolygon.Count > 1)
{
e.Graphics.DrawLines(pp, NewPolygon.ToArray());
}
using (Pen dashed_pen = pp)
{
dashed_pen.DashPattern = new float[] { 3, 3 };
e.Graphics.DrawLine(dashed_pen, NewPolygon[NewPolygon.Count - 1], NewPoint);
}
}
}
}
I have a pictureBox in c# and I have to move it by a vScrollBar.
It should be like this: (pseudo-code!)
if (scrollbar.ScrollUp)
{
int i = 0;
i += +1 per scroll
pictureBox.Location = new Point(0, i);
}
if (scrollbar.ScrollDown)
{
int k = 0;
k += -1 per scroll
pictureBox.Location = new Point(0, k);
}
I hope someone can understand my problem. Thanks
The example for the MSDN ScrollBar.Scroll event actually shows how to scroll a PictureBox.
Code from MSDN:
private void HandleScroll(Object sender, ScrollEventArgs e)
{
//Create a graphics object and draw a portion of the image in the PictureBox.
Graphics g = pictureBox1.CreateGraphics();
int xWidth = pictureBox1.Width;
int yHeight = pictureBox1.Height;
int x;
int y;
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
x = e.NewValue;
y = vScrollBar1.Value;
}
else //e.ScrollOrientation == ScrollOrientation.VerticalScroll
{
y = e.NewValue;
x = hScrollBar1.Value;
}
g.DrawImage(pictureBox1.Image,
new Rectangle(0, 0, xWidth, yHeight), //where to draw the image
new Rectangle(x, y, xWidth, yHeight), //the portion of the image to draw
GraphicsUnit.Pixel);
pictureBox1.Update();
}
Where HandleScroll is the event handler for the ScrollBar's Scroll event.
scrollBar1.Scroll += HandleScroll;
This is assuming you are trying to scroll the PictureBox. If you really just want to move it around, you could try the following:
private void HandleScroll(Object sender, ScrollEventArgs e)
{
var diff = scrollBar1.Value - e.NewValue;
if (e.ScrollOrientation == ScrollOrientation.HorizontalScroll)
{
pictureBox1.Location = new Point(diff, pictureBox1.Location.Y);
}
else //e.ScrollOrientation == ScrollOrientation.VerticalScroll
{
pictureBox1.Location = new Point(pictureBox1.Location.X, diff);
}
}
Warning, this code has not been tested.
I would like to try out a code in Microsoft Visual C# Express Edition and I'm getting this error:
The type or namespace name 'Properties' does not exist in the namespace 'EducationalSuite.Core' (are you missing an assembly reference?)
I right click the Reference but I didn't find the "Properties" either the "EducationalSuite.Core".
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Media;
using System.Resources;
namespace EducationalSuite.Core.Plugins
{
public delegate void RectangleItemClickedDelegate(Rectangle rect, int index);
public partial class GeoSafariItem : Control
{
protected List<Rectangle> lastFlashingItems = new List<Rectangle>();
protected int lastHeight = 0;
private Image imageFile = null;
protected List<Rectangle> hotspots = new List<Rectangle>();
protected Dictionary<int, string> textItems = new Dictionary<int, string>();
protected Dictionary<int, FileInfo> audioItems = new Dictionary<int, FileInfo>();
protected Rectangle lastRectangle;
protected int selectedIndex = 0;
protected int countItemsLeft = 6;
protected int countItemsRight = 6;
protected int imageOffsetTop = 0;
protected int imageOffsetBottom = 0;
protected bool paintHotSpots = false, colorSwitch = false, paintItemLabels = false;
protected Timer timer = new Timer();
public event RectangleItemClickedDelegate HotspotClick;
public event RectangleItemClickedDelegate QuestionItemClick;
public event RectangleItemClickedDelegate QuestionItemRightClick;
protected void OnHotspotClick(Rectangle rect, int index)
{
if (HotspotClick != null)
{
HotspotClick(this.RectangleToScreen(rect), index);
}
}
protected void OnQuestionItemRightClick(Rectangle rect, int index)
{
if (QuestionItemRightClick != null)
{
QuestionItemRightClick(this.RectangleToScreen(rect), index);
}
}
protected void OnQuestionItemClick(Rectangle rect, int index)
{
if (QuestionItemClick != null)
{
QuestionItemClick(this.RectangleToScreen(rect), index);
}
}
public GeoSafariItem()
{
this.imageFile = EducationalSuite.Core.Properties.Resources.singlepixel;
timer.Interval = 100;
timer.Tick += new EventHandler(timer_Tick);
timer.Enabled = true;
this.MouseUp += new MouseEventHandler(GeoSafariItem_MouseUp);
// Activates double buffering
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.ResizeRedraw, true);
this.DoubleBuffered = true;
//InitializeComponent();
}
public void SetItemText(int index, string text)
{
if (string.IsNullOrEmpty(text))
{
if (this.textItems.ContainsKey(index)) textItems.Remove(index);
}
else
{
this.textItems[index] = text;
}
if (PaintItemLabels)
{
this.Invalidate();
}
}
public string GetItemText(int index)
{
if (this.textItems.ContainsKey(index))
{
return this.textItems[index];
}
else
{
return string.Empty;
}
}
public void SetItemAudio(int index, FileInfo file)
{
if ((file == null) && !file.Exists)
{
if (this.audioItems.ContainsKey(index)) audioItems.Remove(index);
}
else
{
this.audioItems[index] = file;
}
}
public FileInfo GetItemAudio(int index)
{
if (this.audioItems.ContainsKey(index))
{
return this.audioItems[index];
}
else
{
return null;
}
}
#region Recording Regions
bool isRecording = false;
int recordingIndex = 0;
Point recordTopLeft = Point.Empty;
Point recordBottomRight = Point.Empty;
List<Rectangle> recordedRectangles = new List<Rectangle>();
public void StartRecording()
{
isRecording = true;
recordingIndex = 0;
selectedIndex = 0;
recordedRectangles.Clear();
this.MouseUp += new MouseEventHandler(GeoSafariItemRecord_MouseUp);
this.Invalidate();
}
public List<Rectangle> FinishRecording()
{
isRecording = false;
this.MouseUp -= new MouseEventHandler(GeoSafariItemRecord_MouseUp);
this.Invalidate();
this.Hotspots.Clear();
foreach (Rectangle r in recordedRectangles)
{
this.Hotspots.Add(r);
}
return recordedRectangles;
}
private void GeoSafariItemRecord_MouseUp(object sender, MouseEventArgs e)
{
if (isRecording)
{
Rectangle size = SizeRect;
double ratio = (double)imageFile.Height / (double)size.Height;
if (recordTopLeft == Point.Empty)
{
recordTopLeft = new Point(
(int)(((double)e.Location.X - (double)size.Left) * ratio),
(int)(((double)e.Location.Y - (double)size.Top) * ratio)
);
}
else
{
recordBottomRight = new Point(
(int)(((double)e.Location.X - (double)size.Left) * ratio),
(int)(((double)e.Location.Y - (double)size.Top) * ratio)
);
Rectangle r = new Rectangle(recordTopLeft,
new Size(recordBottomRight.X - recordTopLeft.X, recordBottomRight.Y - recordTopLeft.Y));
this.recordedRectangles.Add(r);
recordingIndex++;
selectedIndex++;
recordTopLeft = Point.Empty;
recordBottomRight = Point.Empty;
}
}
this.Invalidate();
}
#endregion
void timer_Tick(object sender, EventArgs e)
{
colorSwitch = !colorSwitch;
if (lastRectangle.Width > 0)
{
this.Invalidate(lastRectangle);
}
else
{
this.Invalidate();
}
}
private Rectangle SizeRect
{
get
{
int rw, rh,
cw = (this.Width - 42),
ch = (this.Height - 2),
ox = 21,
oy = 1;
rw = cw;
rh = ch;
double imageRatio = (double)imageFile.Width / (double)imageFile.Height;
double controlRatio = (double)cw / (double)ch;
if (controlRatio > imageRatio)
{
rw = (int)Math.Round((double)rh * imageRatio);
ox += Math.Abs(rw - cw) / 2;
}
else if (controlRatio < imageRatio)
{
rh = (int)Math.Round((double)rw / imageRatio);
oy += Math.Abs(rh - ch) / 2;
}
return new Rectangle(ox, oy, rw, rh);
}
}
void GeoSafariItem_MouseUp(object sender, MouseEventArgs e)
{
Rectangle size = SizeRect;
for (int i = 0; i < hotspots.Count; i++)
{
Rectangle hotspot = hotspots[i];
double ratio = (double)size.Height / (double)imageFile.Height;
Rectangle adjustedRectange = new Rectangle(
size.Left + (int)(hotspot.X * ratio),
size.Top + (int)(hotspot.Y * ratio),
(int)(hotspot.Width * ratio),
(int)(hotspot.Height * ratio));
if (adjustedRectange.Contains(e.Location))
{
OnHotspotClick(hotspot, i);
return;
}
}
for (int i = 0; i < lastFlashingItems.Count; i++)
{
if (lastFlashingItems[i].Contains(e.Location))
{
if (e.Button == MouseButtons.Right)
OnQuestionItemRightClick(lastFlashingItems[i], i);
else
OnQuestionItemClick(lastFlashingItems[i], i);
return;
}
}
}
public List<Rectangle> Hotspots
{
get { return hotspots; }
}
public Image ImageFile
{
get { return imageFile; }
set
{
imageFile = value;
lastFlashingItems.Clear();
this.Invalidate();
}
}
public int SelectedIndex
{
get { return selectedIndex; }
set { selectedIndex = value; this.Invalidate(); }
}
public int CountItemsLeft
{
get { return countItemsLeft; }
set
{
countItemsLeft = value;
lastFlashingItems.Clear();
this.Invalidate();
}
}
public int CountItemsRight
{
get { return countItemsRight; }
set
{
countItemsRight = value;
lastFlashingItems.Clear();
this.Invalidate();
}
}
public int ImageOffsetTop
{
get { return imageOffsetTop; }
set
{
imageOffsetTop = value;
lastFlashingItems.Clear();
this.Invalidate();
}
}
public int ImageOffsetBottom
{
get { return imageOffsetBottom; }
set
{
imageOffsetBottom = value;
lastFlashingItems.Clear();
this.Invalidate();
}
}
public bool PaintHotSpots
{
get { return paintHotSpots; }
set { paintHotSpots = value; this.Invalidate(); }
}
public bool PaintItemLabels
{
get { return paintItemLabels; }
set { paintItemLabels = value; this.Invalidate(); }
}
protected override void OnPaint(PaintEventArgs pe)
{
Graphics g = pe.Graphics;
string itemText;
SizeF sizeItemText;
double topOffset = imageOffsetTop;
double bottomOffset = imageOffsetBottom;
double topOffsetPct = (double)topOffset / (double)imageFile.Height;
double bottomOffsetPct = (double)bottomOffset / (double)imageFile.Height;
Rectangle size = SizeRect;
SolidBrush brush = new SolidBrush(this.BackColor);
g.FillRectangle(brush, 0, 0, this.Width - 1, this.Height - 1);
g.FillRectangle(Brushes.Ivory, size.X - 25, size.Y, size.Width + 50, size.Height);
g.DrawRectangle(Pens.DarkKhaki, size.X - 25, size.Y - 1, size.Width + 50, size.Height + 1);
g.DrawImage(imageFile, size.X, size.Y, size.Width, size.Height);
Rectangle rect, rectItemText;
Brush selectedColor = (colorSwitch ? Brushes.Crimson : Brushes.Red);
topOffset = topOffsetPct * size.Height;
bottomOffset = bottomOffsetPct * size.Height;
int tmpHeight = (size.Height - (int)topOffset - (int)bottomOffset) / countItemsLeft;
if (size.Height != this.lastHeight || this.lastFlashingItems.Count == 0)
{
lastHeight = size.Height;
lastFlashingItems.Clear();
int actualIndex = 0;
for (int i = 0; i < countItemsLeft; i++)
{
int yy = size.Y + (tmpHeight * i) + (int)topOffset;
int xx = size.X - 18;
rect = new Rectangle(xx, yy, 16, 8);
this.lastFlashingItems.Add(rect);
g.FillRectangle((actualIndex == selectedIndex ? selectedColor : Brushes.Khaki), rect);
g.DrawRectangle(Pens.DarkKhaki, rect);
if (actualIndex == selectedIndex)
{
lastRectangle = rect;
}
itemText = this.GetItemText(actualIndex);
if (PaintItemLabels && !string.IsNullOrEmpty(itemText))
{
// Draw Text next to each notch
sizeItemText = g.MeasureString(itemText, this.Font);
int xxx = size.X + 10;
rectItemText = new Rectangle(xxx, yy, Convert.ToInt32(sizeItemText.Width), Convert.ToInt32(sizeItemText.Height));
PaintHotspot(g, Color.White, rectItemText, 200);
g.DrawString(itemText, this.Font, Brushes.Black, (float)xxx, (float)yy);
}
actualIndex++;
}
tmpHeight = (size.Height - (int)topOffset - (int)bottomOffset) / countItemsRight;
for (int i = 0; i < countItemsRight; i++)
{
int yy = size.Y + (tmpHeight * i) + (int)topOffset;
int xx = size.X + size.Width + 2;
rect = new Rectangle(xx, yy, 16, 8);
this.lastFlashingItems.Add(rect);
g.FillRectangle((actualIndex == selectedIndex ? selectedColor : Brushes.Khaki), rect);
g.DrawRectangle(Pens.DarkKhaki, rect);
if (actualIndex == selectedIndex)
{
lastRectangle = rect;
}
itemText = this.GetItemText(actualIndex);
if (PaintItemLabels && !string.IsNullOrEmpty(itemText))
{
// Draw Text next to each notch
sizeItemText = g.MeasureString(itemText, this.Font);
int xxx = size.X + size.Width - 10 - Convert.ToInt32(sizeItemText.Width);
rectItemText = new Rectangle(xxx, yy, Convert.ToInt32(sizeItemText.Width), Convert.ToInt32(sizeItemText.Height));
PaintHotspot(g, Color.White, rectItemText, 200);
g.DrawString(itemText, this.Font, Brushes.Black, (float)xxx, (float)yy);
}
actualIndex++;
}
}
else
{
lastHeight = size.Height;
for (int i = 0; i < lastFlashingItems.Count; i++)
{
g.FillRectangle((i == selectedIndex ? selectedColor : Brushes.Khaki), lastFlashingItems[i]);
g.DrawRectangle(Pens.DarkKhaki, lastFlashingItems[i]);
if (i == selectedIndex)
{
lastRectangle = lastFlashingItems[i];
}
}
if (PaintItemLabels)
{
int actualIndex = 0;
for (int i = 0; i < countItemsLeft; i++)
{
itemText = this.GetItemText(actualIndex);
if (!string.IsNullOrEmpty(itemText))
{
int yy = size.Y + (tmpHeight * i) + (int)topOffset;
// Draw Text next to each notch
sizeItemText = g.MeasureString(itemText, this.Font);
int xxx = size.X + 10;
rectItemText = new Rectangle(xxx, yy, Convert.ToInt32(sizeItemText.Width), Convert.ToInt32(sizeItemText.Height));
PaintHotspot(g, Color.White, rectItemText, 200);
g.DrawString(itemText, this.Font, Brushes.Black, (float)xxx, (float)yy);
}
actualIndex++;
}
tmpHeight = (size.Height - (int)topOffset - (int)bottomOffset) / countItemsRight;
for (int i = 0; i < countItemsRight; i++)
{
itemText = this.GetItemText(actualIndex);
if (!string.IsNullOrEmpty(itemText))
{
int yy = size.Y + (tmpHeight * i) + (int)topOffset;
// Draw Text next to each notch
sizeItemText = g.MeasureString(itemText, this.Font);
int xxx = size.X + size.Width - 10 - Convert.ToInt32(sizeItemText.Width);
rectItemText = new Rectangle(xxx, yy, Convert.ToInt32(sizeItemText.Width), Convert.ToInt32(sizeItemText.Height));
PaintHotspot(g, Color.White, rectItemText, 200);
g.DrawString(itemText, this.Font, Brushes.Black, (float)xxx, (float)yy);
}
actualIndex++;
}
}
}
// Calling the base class OnPaint
base.OnPaint(pe);
if (this.isRecording)
{
for (int i = 0; i < this.recordedRectangles.Count; i++)
{
rect = recordedRectangles[i];
double ratio = (double)size.Height / (double)imageFile.Height;
Rectangle adjustedRectange = new Rectangle(
size.Left + (int)(rect.X * ratio),
size.Top + (int)(rect.Y * ratio),
(int)(rect.Width * ratio),
(int)(rect.Height * ratio));
PaintHotspot(g, Color.LightBlue, adjustedRectange, (i + 1).ToString());
}
}
else if (this.paintHotSpots)
{
for (int i = 0; i < hotspots.Count; i++)
{
Rectangle hotspot = hotspots[i];
double ratio = (double)size.Height / (double)imageFile.Height;
Rectangle adjustedRectange = new Rectangle(
size.Left + (int)(hotspot.X * ratio),
size.Top + (int)(hotspot.Y * ratio),
(int)(hotspot.Width * ratio),
(int)(hotspot.Height * ratio));
PaintHotspot(g, Color.LightGreen, adjustedRectange, (i + 1).ToString());
}
}
}
protected virtual void PaintHotspot(Graphics g, Color c, Rectangle hotspot, int alpha)
{
PaintHotspot(g, c, hotspot, alpha, null);
}
protected virtual void PaintHotspot(Graphics g, Color c, Rectangle hotspot, string txt)
{
PaintHotspot(g, c, hotspot, 100, txt);
}
protected virtual void PaintHotspot(Graphics g, Color c, Rectangle hotspot, int alpha, string txt)
{
SolidBrush brush = new SolidBrush(Color.FromArgb(alpha, c));
g.FillRectangle(brush, hotspot);
if (!string.IsNullOrEmpty(txt))
g.DrawString(txt, this.Font, Brushes.DarkGreen, hotspot.Location);
}
}
}
Update
I imagine the following line is causing the error.
this.imageFile = EducationalSuite.Core.Properties.Resources.singlepixel;
The code is referring to a image resource "singlepixel". This image must be in the default resource file of the EducationalSuite.Core assembly. First confirm that you are currently editing the said assembly by opening Project Properties and checking the Default Namespace on the Application page. This should state "EducationalSuite.Core". If this isn't the case, you are most likely missing a reference to the said assembly.
If you have the EducationalSuite.Core project open the easiest way to add the singlepixel resource is to open project properties, Resources tab and creating a new default resource file. From the top open the Add Resource drop down and select existing file or new image depending on whether you have the file already or if you need to create it. Name the resource "singlepixel".
Visual Studio will generate Resources helper class under Properties namespace for you so you can access the resource through the Properties.Resources.singlepixel under EducationalSuite.Core in your code.
Old answer
In general Properties namespace is the namespace which contains application or user specific settings. You can add these settings (and the namespace) by navigating to the Settings tab in the Properties of the project.
Unfortunately it's kind of hard to say more based on this information. Could you provide the piece of code that causes this error?
If you double click the error message the IDE will take you to the line which is causing the error.
Most likely the piece of code is expecting a setting variable which is not added to the project.
Looks like you are missing the Reference. If it is not under References in solution explorer than I would do a file search in windows for "EducationalSuite.Core" to see where it is on the system and add it. You may also be missing the "using" statement? If you hover over the "Properties" text you should get a small drop down that will add the using's for you.
If this does not help, more information would be helpful?
Hope this helps!