Circular RadioButton List in Windows Forms - c#

I have designed the circular button list in web application using a jquery plugin and html. In this design user at a time select one day only like radio button list. The design is shown below:
How can I implement the the same design and functionality in windows form? Please help me, from where I am going to started to achieve this one.

There are multiple options to perform this in windows forms. As an option you can start with customizing RadioButton and Panel controls. You can create a new class derived from Panel and a new class derived from RadioButton, then override OnPaint method of those classes and draw the desired presentation.
Here is the result of a sample implementation which I shared in this post:
Custom Panel
public class MyPanel : Panel
{
public MyPanel()
{
this.Padding = new Padding(2);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
using (var path = new GraphicsPath())
{
var d = this.Padding.All;
var r = this.Height - 2 * d;
path.AddArc(d, d, r, r, 90, 180);
path.AddArc(this.Width - r - d, d, r, r, -90, 180);
path.CloseFigure();
using (var pen = new Pen(Color.Silver, d))
e.Graphics.DrawPath(pen, path);
}
}
}
Custom Radio Button
public class MyRadioButton : RadioButton
{
public MyRadioButton()
{
this.Appearance = System.Windows.Forms.Appearance.Button;
this.BackColor = Color.Transparent;
this.TextAlign = ContentAlignment.MiddleCenter;
this.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.FlatAppearance.BorderColor = Color.RoyalBlue;
this.FlatAppearance.BorderSize = 2;
}
protected override void OnPaint(PaintEventArgs e)
{
this.OnPaintBackground(e);
using (var path = new GraphicsPath())
{
var c = e.Graphics.ClipBounds;
var r = this.ClientRectangle;
r.Inflate(-FlatAppearance.BorderSize, -FlatAppearance.BorderSize);
path.AddEllipse(r);
e.Graphics.SetClip(path);
base.OnPaint(e);
e.Graphics.SetClip(c);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (this.Checked)
{
using (var p = new Pen(FlatAppearance.BorderColor,
FlatAppearance.BorderSize))
{
e.Graphics.DrawEllipse(p, r);
}
}
}
}
}
Required usings
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

Hii Gopal you can achive this functionality using custom control.Goodluck
please refer these links
How to customize Button Control like this one?
https://msdn.microsoft.com/en-us/library/h4te2zh2(v=vs.90).aspx
How do I create button with rounded corners/edges on Winform C#?

You can start with a list view or list box
Change the item template as a button and add style to your button as you need.
Make the selection mode of the list view as Single.

Related

In C# Winforms is there a way to put dotted border around all controls and show grip points upon selection of specific controls at runtime?

I work in a team working on a IDE similar to Visual Studio to develop custom Winform code for our local clients. In our code we have User Controls overridden to make our tasks easier but most of our controls are derived from basic C# Winform Controls.
I currently need help in implementing dotted border around all our controls, with the type of grip points as provided by Visual Studio.
Unselected Controls
Selected Controls
This feature is highly demanded as it can help in aligning without compensation on visual guidelines.
We have currently implemented a dark border around all controls, using
this.BackColor = Color.Black;
this.Height = ComboBox.Height + 4;
Which puts a black border around the generated Controls, which in the above code snippet is a ComboBox.
One member pointed us towards using Margins and Padding as shown in the Microsoft documentation: https://msdn.microsoft.com/library/3z3f9e8b(v=vs.110)
But this is mostly theory and does not seem to help much. the closest thing that has come to solve this problem so far has been an online CodeProject link:
public class MyGroupBox : GroupBox
{
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset,
Color.Black, BORDER_SIZE, ButtonBorderStyle.Inset);
}
}
I am surprized to not find a close match to my search so far, perhaps i am using the wrong terminology, as I recently got into programming in this domain.
I believe that future online searches are going to be benifitted, if this problem gets solved. Looking forward for pointers form those with experience in this problem. Really appreciate any help in this direction.
I work in a team working on a IDE similar to Visual Studio ....
Developing a custom form designer is not a trivial task and needs a lot of knowledge and a lot of time and I believe the best solution which you can use, is hosting windows forms designer.
It's not just about drawing selection borders:
Each control has it's own designer with specific features, for example some controls like MenuStrip has it's own designer which enables you to add/remove items on designer.
Controls may have some specific sizing and positioning rules. For example some of them are auto-sized like TextBox or docked controls can not be reposition by mouse and so on.
Components are not visible on your form which you may need to edit them.
Some properties are design-time properties.
Some properties are added using extender providers and you need to perform additional tasks to provide a way to change them in your custom designer.
And a lot of other considerations.
Solution 1 - Hosting Windows Forms Designer
To learn more about design time architecture, take a look at Design-Time Architecture. To host windows forms designer in your application, you need to implement some interfaces like IDesignerHost, IContainer, IComponentChangeService, IExtenderProvider, ITypeDescriptorFilterService, IExtenderListService, IExtenderProviderService.
For some good examples you can take a look at:
Hosting Windows Forms Designers by Tim Dawson
Tailor Your Application by Building a Custom Forms Designer with .NET by Sayed Y. Hashimi
You may find this post useful:
Hosting Windows Forms Designer - Serialize and Deserialize designer at runtime
The post contains a working example on how to host windows forms designer at run-time and generate code:
Solution 2 - Drawing selection border over a transparent panel
While I strongly recommend using the first solution, but just for learning purpose if you want to draw selection border around controls, you can add the forms which you want to edit as a control to the host form, then put a transparent panel above the form. Handle Click event of transparent Panel and find the control under mouse position and draw a selection border around it on transparent panel like this:
In the example, I just created a transparent panel and drew selection border. It's just an example and performing sizing and positioning is out of scope of the example. It's just to show you how you can draw selection border around controls. You also can use the idea to create a SelctionBorder control and encapsulate sizing and positioning logic in the control and instead of drawing the borders, add an instance of SelectionBorder control to transparent panel and in its sizing and positioning events, change corresponding control coordinates.
Please pay attention it's just an example and in a real designer environment you should consider a lot of important things.
Transparent Panel
using System.Windows.Forms;
public class TransparentPanel : Panel
{
const int WS_EX_TRANSPARENT = 0x20;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
}
}
Host Form
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
public partial class HostForm : Form
{
private Panel containerPanel;
private TransparentPanel transparentPanel;
private PropertyGrid propertyGrid;
public HostForm()
{
this.transparentPanel = new TransparentPanel();
this.containerPanel = new Panel();
this.propertyGrid = new PropertyGrid();
this.SuspendLayout();
this.propertyGrid.Width = 200;
this.propertyGrid.Dock = DockStyle.Right;
this.transparentPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.transparentPanel.Name = "transparentPanel";
this.containerPanel.Dock = System.Windows.Forms.DockStyle.Fill;
this.containerPanel.Name = "containerPanel";
this.ClientSize = new System.Drawing.Size(450, 210);
this.Controls.Add(this.transparentPanel);
this.Controls.Add(this.propertyGrid);
this.Controls.Add(this.containerPanel);
this.Name = "HostForm";
this.Text = "Host";
this.Load += this.HostForm_Load;
this.transparentPanel.MouseClick += this.transparentPanel_MouseClick;
this.transparentPanel.Paint += this.transparentPanel_Paint;
this.ResumeLayout(false);
}
private void HostForm_Load(object sender, EventArgs e)
{
this.ActiveControl = transparentPanel;
/**************************************/
/*Load the form which you want to edit*/
/**************************************/
var f = new Form();
f.Location = new Point(8, 8);
f.TopLevel = false;
this.containerPanel.Controls.Add(f);
SelectedObject = f;
f.Show();
}
Control selectedObject;
Control SelectedObject
{
get { return selectedObject; }
set
{
selectedObject = value;
propertyGrid.SelectedObject = value;
this.Refresh();
}
}
void transparentPanel_MouseClick(object sender, MouseEventArgs e)
{
if (this.Controls.Count == 0)
return;
SelectedObject = GetAllControls(this.containerPanel)
.Where(x => x.Visible)
.Where(x => x.Parent.RectangleToScreen(x.Bounds)
.Contains(this.transparentPanel.PointToScreen(e.Location)))
.FirstOrDefault();
this.Refresh();
}
void transparentPanel_Paint(object sender, PaintEventArgs e)
{
if (SelectedObject != null)
DrawBorder(e.Graphics, this.transparentPanel.RectangleToClient(
SelectedObject.Parent.RectangleToScreen(SelectedObject.Bounds)));
}
private IEnumerable<Control> GetAllControls(Control control)
{
var controls = control.Controls.Cast<Control>();
return controls.SelectMany(ctrl => GetAllControls(ctrl)).Concat(controls);
}
void DrawBorder(Graphics g, Rectangle r)
{
var d = 4;
r.Inflate(d, d);
ControlPaint.DrawBorder(g, r, Color.Black, ButtonBorderStyle.Dotted);
var rectangles = new List<Rectangle>();
var r1 = new Rectangle(r.Left - d, r.Top - d, 2 * d, 2 * d); rectangles.Add(r1);
r1.Offset(r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(0, r.Height / 2); rectangles.Add(r1);
r1.Offset(0, r.Height / 2); rectangles.Add(r1);
r1.Offset(-r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(-r.Width / 2, 0); rectangles.Add(r1);
r1.Offset(0, -r.Height / 2); rectangles.Add(r1);
g.FillRectangles(Brushes.White, rectangles.ToArray());
g.DrawRectangles(Pens.Black, rectangles.ToArray());
}
protected override bool ProcessTabKey(bool forward)
{
return false;
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
this.Refresh();
}
}
Some caution would be appropriate here, modeling a UI designer after the Winforms designer is an easy decision, actually implementing it is a job that can keep you occupied for many months. Discovering that you cannot paint outside the control bounds is indeed the very first obstacle you'll run into, many more like that.
The first shortcut you might consider is to draw place-holders for the controls so you don't depend on the Control class. Works fine as long as it doesn't have to look too closely like the real control (i.e. give up on WYSIWYG) and you don't have to resize them.
But you'll surely dismiss that. You then have to do the same thing the Winforms designer does, you have to overlay a transparent window on top of the design surface. You can draw anything you want on that overlay and it provides automatic mouse and keyboard isolation so the control itself is completely oblivious of the design-time interaction. Find examples of such an overlay in this post and this post.
Last but not least, it is worth mentioning that you can leverage the existing Winforms designer in your own projects as well. You have to implement IDesignerHost. And a bunch more, unfortunately the abstraction level is fairly high and the MSDN docs rather brief. Best thing to do is to work from a sample that shows a full-featured designer. This KB article has the link. Code is excellent and well documented, you get an almost complete designer with toolbox and Properties window which de/serializes the design from/to XML and can generate C# and VB.NET code. Do look past the garish UI, it doesn't enable Visual Styles and color choices are the kind that I would make :) Making it pretty wasn't the point of the code sample.
I Have Created I windows Form Application Hope this will Help you
BackEnd C# Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Paint += new PaintEventHandler(this_Paint);
}
private void this_Paint(object sender, PaintEventArgs e)
{
Pen pen = new Pen(Color.Green, 2.0F);
pen.DashStyle = DashStyle.Dash;
foreach (Control c in groupBox1.Controls)
{
e.Graphics.DrawRectangle(pen, (groupBox1.Location.X + c.Location.X)-1, (groupBox1.Location.Y + c.Location.Y)-1, c.Width + 2, c.Height + 2);
}
pen.Dispose();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
Designer C# Code
namespace WindowsFormsApplication2
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.comboBox2 = new System.Windows.Forms.ComboBox();
this.comboBox3 = new System.Windows.Forms.ComboBox();
this.comboBox4 = new System.Windows.Forms.ComboBox();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.BackColor = System.Drawing.Color.Transparent;
this.groupBox1.Controls.Add(this.comboBox4);
this.groupBox1.Controls.Add(this.comboBox3);
this.groupBox1.Controls.Add(this.comboBox2);
this.groupBox1.Controls.Add(this.comboBox1);
this.groupBox1.Location = new System.Drawing.Point(33, 36);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(193, 184);
this.groupBox1.TabIndex = 0;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "groupBox1";
//
// comboBox1
//
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point(36, 40);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(121, 21);
this.comboBox1.TabIndex = 0;
//
// comboBox2
//
this.comboBox2.FormattingEnabled = true;
this.comboBox2.Location = new System.Drawing.Point(36, 67);
this.comboBox2.Name = "comboBox2";
this.comboBox2.Size = new System.Drawing.Size(121, 21);
this.comboBox2.TabIndex = 1;
//
// comboBox3
//
this.comboBox3.FormattingEnabled = true;
this.comboBox3.Location = new System.Drawing.Point(36, 94);
this.comboBox3.Name = "comboBox3";
this.comboBox3.Size = new System.Drawing.Size(121, 21);
this.comboBox3.TabIndex = 1;
//
// comboBox4
//
this.comboBox4.FormattingEnabled = true;
this.comboBox4.Location = new System.Drawing.Point(36, 121);
this.comboBox4.Name = "comboBox4";
this.comboBox4.Size = new System.Drawing.Size(121, 21);
this.comboBox4.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 261);
this.Controls.Add(this.groupBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.ComboBox comboBox4;
private System.Windows.Forms.ComboBox comboBox3;
private System.Windows.Forms.ComboBox comboBox2;
}
}
Make GroupBox1 backgroundcolour 'Transparent' because I am drawing on Form not on
GroupBox
You Can also Create Border on Selected Controls by Adding if(c is ComboBox)
or if (c.Name == "comboBox1")
in foreach loop
!! Change the Color According to your Need !!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
hatchedPen = (Pen)SystemPens.ControlDarkDark.Clone();
hatchedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Clear any existing grab handles
using (Graphics g = Graphics.FromHwnd(this.Handle))
{
foreach (Control ctrl in Controls)
{
var rect = GetGrabBounds(ctrl);
g.FillRectangle(SystemBrushes.ButtonFace, rect);
}
}
// Need to draw grab handles?
if (ActiveControl != null && e.ClipRectangle.IntersectsWith(GetGrabBounds(ActiveControl)))
{
DrawGrabHandles(ActiveControl);
}
}
private void DrawGrabHandles(Control ctrl)
{
using (Graphics g = Graphics.FromHwnd(this.Handle))
{
Rectangle bounds = GetGrabRect(ctrl);
g.DrawRectangle(hatchedPen, bounds);
foreach (Point pt in new Point[]
{
new Point(bounds.Left, bounds.Top),
new Point(bounds.Left + bounds.Width / 2, bounds.Top),
new Point(bounds.Right, bounds.Top),
new Point(bounds.Left, bounds.Top + bounds.Height / 2),
new Point(bounds.Right, bounds.Top + bounds.Height / 2),
new Point(bounds.Left, bounds.Bottom),
new Point(bounds.Left + bounds.Width / 2, bounds.Bottom),
new Point(bounds.Right, bounds.Bottom),
})
{
Rectangle r = new Rectangle(pt, new Size(5, 5));
r.X = r.X - 2;
r.Y = r.Y - 2;
g.FillRectangle(SystemBrushes.ButtonFace, r);
g.DrawRectangle(SystemPens.ControlDarkDark, r);
}
}
}
private static Rectangle GetGrabRect(Control ctrl)
{
var result = ctrl.Bounds;
result = Rectangle.Inflate(result, 4, 4);
result.X--;
result.Y--;
return result;
}
private static Rectangle GetGrabBounds(Control ctrl)
{
var result = GetGrabRect(ctrl);
result.Inflate(4, 4);
return result;
}
private Pen hatchedPen;
}

Drawing on a panel c#

I need to graph a polygonal on a panel (size 400, 400)
I try this, but it doesn't work.
PointF[] points = new PointF[totalpaso + 1];
for (int d = 0; d <= totalpaso; d++)
{
s = (float)(hola1[d] + 200);
w = (float)(hola2[d] + 200);
j = new PointF(s, w);
points[d] = j;
}
grafico.DrawPolygon(lapiz, points);
I think you should take a look at this post:
https://msdn.microsoft.com/en-us/library/07e699tw(v=vs.110).aspx
But with only that method you won't get far. It'll be drawn in a OnPaint Method:
C# Forms - Using Paint methods?
You will probably want to make your own control based on Panel.
A really basic example is this:
public sealed class MyPanel: Panel
{
public MyPanel()
{
this.ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var brush = new SolidBrush(this.ForeColor))
{
e.Graphics.FillEllipse(brush, 0, 0, this.Width, this.Height);
}
}
}
To test it, add the class to a Windows Forms project, compile, and then drop it onto a form and set it to "Dock" in the designer.
Then set the BackColor to, say, red and the ForeColor to blue, then run the program.
You can then add your required drawing code to the OnPaint() override.

Vertical tab control with horizontal text at design time

A clear omission seems to be that after applying this approach:
Vertical Tab Control with horizontal text in Winforms
Which is also recommended by Microsoft:
How to: Display Side-Aligned Tabs with TabControl
There is no text on tabs at design time, so further development and support becomes a nightmare.
Is there a way to make tab text also display at design time?
Just create your own control so the custom drawing also works at design time. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form. I tweaked it a bit to make it no so garish.
using System;
using System.Drawing;
using System.Windows.Forms;
class VerticalTabControl : TabControl {
public VerticalTabControl() {
this.Alignment = TabAlignment.Right;
this.DrawMode = TabDrawMode.OwnerDrawFixed;
this.SizeMode = TabSizeMode.Fixed;
this.ItemSize = new Size(this.Font.Height * 3 / 2, 75);
}
public override Font Font {
get { return base.Font; }
set {
base.Font = value;
this.ItemSize = new Size(value.Height * 3 / 2, base.ItemSize.Height);
}
}
protected override void OnDrawItem(DrawItemEventArgs e) {
using (var _textBrush = new SolidBrush(this.ForeColor)) {
TabPage _tabPage = this.TabPages[e.Index];
Rectangle _tabBounds = this.GetTabRect(e.Index);
if (e.State != DrawItemState.Selected) e.DrawBackground();
else {
using (var brush = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, Color.White, Color.LightGray, 90f)) {
e.Graphics.FillRectangle(brush, e.Bounds);
}
}
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
e.Graphics.DrawString(_tabPage.Text, this.Font, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}
}
}
You need to subclass the TabControl and override OnDrawItem. Here's an example:
Public Class UITabControl
Inherits TabControl
Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
Using brush As New SolidBrush(Me.ForeColor)
Using format As New StringFormat() With {.LineAlignment = StringAlignment.Center}
Select Case Me.Alignment
Case TabAlignment.Left
format.Alignment = StringAlignment.Near
Case TabAlignment.Top
format.Alignment = StringAlignment.Far
End Select
format.FormatFlags = (format.FormatFlags Or StringFormatFlags.NoWrap)
Dim rect As Rectangle = e.Bounds
rect.X += 3
rect.Width -= 6
e.Graphics.DrawString(Me.TabPages(e.Index).Text, Me.Font, brush, rect, format)
End Using
End Using
MyBase.OnDrawItem(e)
End Sub
End Class
Since you linked to my question, I thought it expedient to inform you of updates to my question thread.
I have, in an answer to my question, uploaded my code for the control in the interest of the programming community.
This is a screenshot of the control at runtime.
It features full design time support, automatic resizing of tabs (up to 128px wide) and tab icons as well.
The code can be downloaded from here.

Issue with transparent images with a transparent background

I'm having a problem with displaying transparent images with a transparent background. The transparent background takes the color of the underlying control and that is fine ... bu the problem is that some details (lines) on the underlying background are being covered the the images as can be seen in the image below.
Here is the code I am using.... This is the code for the notes....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Media;
using System.Drawing;
namespace Simpe_Piano_new
{
class MusicNote: PictureBox
{
public SoundPlayer sp = new SoundPlayer();
Timer tmr = new Timer();
public int pitch; //The no. of the music key (e.g. the sound freuency).
public int noteDuration; //Shape of note.
public string noteShape;
public MusicNote(int iPitch, int iNoteDuration)
: base()
{
pitch = iPitch;
noteDuration = iNoteDuration;
Size = new Size(40, 40);
}
public void ShowNote()
{ if (this.noteDuration == 1) noteShape = "Quaver.png";
if (this.noteDuration == 4) noteShape = "Crotchet.png";
if (this.noteDuration == 7) noteShape = "minim.png";
if (this.noteDuration == 10) noteShape = "DotMin.png";
if (this.noteDuration == 12) noteShape = "SemiBreve.png";
this.BackgroundImage = Image.FromFile(noteShape);
this.BackColor = Color.Transparent;
Location = new Point((pitch * 40) - 40, 100);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
public void PlaySound()
{
sp.SoundLocation = this.pitch + ".wav";
sp.Play();
}
public void StopSound()
{
sp.SoundLocation = this.pitch + ".wav";
sp.Stop();
}
public void Play()
{
sp.SoundLocation = this.pitch + ".wav";
sp.Play();
//Time to play the duration
tmr.Interval = noteDuration;
tmr.Start();
tmr.Tick += new System.EventHandler(ClockTick);
}
void ClockTick(object sender, EventArgs e)
{
sp.Stop();
tmr.Stop();
}
}
}
This is the code for the underlying control..the music staff
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
namespace Simpe_Piano_new
{
public class MusicStaff: Panel
{
Pen myPen;
Graphics g;
public MusicStaff()
{
this.Size = new Size(1000, 150);
this.Location = new Point(0, 0);
this.BackColor = Color.Transparent;
this.Paint += new PaintEventHandler(DrawLines);
}
private void DrawLines(object sender, PaintEventArgs pea)
{
myPen = new Pen(Color.Black, 1);
g = this.CreateGraphics();
for (int i = 1; i < 6; i++)
{
g.DrawLine(myPen, 0, (this.Height / 6) * i, this.Width, (this.Height / 6) * i);
}
}
}
}
I have found that C# does not handle transparency really well...
Any help would be greatly appreciated..
add the top control "MusicNote" in the children of the underlying control "MusicStaff"
something like that after -Initializing all components-
// mStaff: the MusicStaff object
// mNote: the MusicNote object
mStaff.Children.Add(mNote);
in old scenario, the form is the parent of both of them, so they display the form background in any transparent area
after modifying the parent of the "MusicNote", it displays the "MusicStaff" background in the transparent area
I hope that help!
Two mistakes. PictureBox supports transparent images well, as long as you set its BackColor property to Color.Transparent. Which you did for the MusicStaff but not for the MusicNote. Layered transparency does not work, you don't need MusicStaff to be transparent, just the picture boxes.
This kind of transparency is simulated by asking the Parent to paint itself into the control to provide the background pixels. Which is your second mistake, you use CreateGraphics() in your DrawLines() method. Which draws directly to the screen, not the control surface. You must use pea.Graphics here.
Do note that the value-add you get from using PictureBox is a very low one. Controls are expensive and you'll easily burn up hundreds of them to display a sheet of music. You'll notice, it will become slow to paint itself. You avoid this by having MusicStaff just paint the notes itself, using Graphics.DrawImage() gets the job done. Transparency effects are now much simpler as well, just layers of paint. Which is the way WPF does it. The only inconvenience you'll have to deal with is that mouse hit testing isn't as simple anymore, you need to map the panel's MouseDown event's coordinates to a note. Just keep a List that keeps track where every note is displayed. You'll use that for painting as well as mouse hit testing.

Why when resizing the user control graph it's not really resized?

I have a user control chart in my Form1 designer and this is the code to resize it:
private void graphChart1_MouseEnter(object sender, EventArgs e)
{
graphChart1.Size = new Size(600, 600);
}
When I move the mouse to the control area it's not resizing it make it bigger but deleting some other controls.
This is an image before I move the mouse over the control:
And this is an image when I moved the mouse over the control:
This is the code of the user control where the chart is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Web;
using System.Windows.Forms.DataVisualization.Charting;
namespace GatherLinks
{
public partial class GraphChart : UserControl
{
public GraphChart()
{
InitializeComponent();
}
private double f(int i)
{
var f1 = 59894 - (8128 * i) + (262 * i * i) - (1.6 * i * i * i);
return f1;
}
private void GraphChart_Load(object sender, EventArgs e)
{
chart1.Series.Clear();
var series1 = new System.Windows.Forms.DataVisualization.Charting.Series
{
Name = "Series1",
Color = System.Drawing.Color.Green,
IsVisibleInLegend = false,
IsXValueIndexed = true,
ChartType = SeriesChartType.Line
};
this.chart1.Series.Add(series1);
for (int i = 0; i < 100; i++)
{
series1.Points.AddXY(i, f(i));
}
chart1.Invalidate();
}
}
}
EDIT:
I did this in the user control class code:
public void ChangeChartSize(int width, int height)
{
chart1.Size = new Size(width, height);
chart1.Invalidate();
}
I had to add chart1.Invalidate(); to make it to take effect but then it sized the chart it self inside the user control. The user control was not changed.
So in the Form1 mouse enter I also changing the graphChart1 the control size:
private void graphChart1_MouseEnter(object sender, EventArgs e)
{
graphChart1.ChangeChartSize(600, 600);
graphChart1.Size = new Size(600, 600);
}
The problem is that now it's taking a lot of time almost 20 seconds or so until it take effect when I'm moving the mouse over the control. If I will remove the second line:
graphChart1.Size = new Size(600, 600);
it will work fast but then it will change the chart only inside the control but it won't change the control size.
Tried also with invalidate:
private void graphChart1_MouseEnter(object sender, EventArgs e)
{
graphChart1.ChangeChartSize(600, 600);
graphChart1.Size = new Size(600, 600);
graphChart1.Invalidate();
}
But still very slow. Maybe I need to change the control it self size also in the user control class code and not in Form1 ?
The problem is that you are resizing the GraphicChart (your user control) but not the Chart itself. You could add the method in your GraphChart class in order to do that. This is the method that will change the chart size:
public void ChangeChartSize(int width, int height)
{
chart1.Size = new Size(width, height);
}
And in your mouse enter event handler you could call something like this:
void graphicChart1_MouseEnter(object sender, EventArgs e)
{
graphChart1.ChangeChartSize(600, 600);
}
With graphChart1.Size = you are resizing your container but not the chart within it.
The easiest work-around is probably to make chart1 public in the control and do graphChart1.chart1.Size = instead.
In the user control class code I did:
public void ChangeChartSize(int width, int height)
{
this.Size = new Size(width, height);
chart1.Size = new Size(width, height);
chart1.Invalidate();
}
In Form1 I did:
private void graphChart1_MouseEnter(object sender, EventArgs e)
{
graphChart1.ChangeChartSize(600, 600);
}
Working smooth.

Categories