How to put some color on image - c#

I have here the circle image, what I want to do is to put some color in specific position.. For example, when I click the button1, the left side of the circle will be filled by red, and when I click the button2, the right side will be filled by as well, and when I click the button1 again, the color will be removed, and so on...
I've done some research about it, and found out 2 ways to do it. First is, to layover the circle with another image. Second is to draw, and use the Graphics class in C#..
Now, my question is, is there another possible way to do it? What is the best way?
P.S: The purpose of this is for the tooth chart. :)

Here's a Resizable, Clickable, UserControl based on qing`s post. You can click on the regions directly to toggle them, or change them via code.
public partial class ToothChart : UserControl
{
public ToothChart()
{
InitializeComponent();
this.DoubleBuffered = true;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (this.ParentForm != null)
{
this.ParentForm.FormClosing += (s, evt) => { OnHandleDestroyed(new EventArgs()); };
}
}
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
if (this._pathTop != null)
{
this._pathTop.Dispose();
this._pathTop = null;
}
if (this._pathRight != null)
{
this._pathRight.Dispose();
this._pathRight = null;
}
if (this._pathBottom != null)
{
this._pathBottom.Dispose();
this._pathBottom = null;
}
if (this._pathLeft != null)
{
this._pathLeft.Dispose();
this._pathLeft = null;
}
if (this._pathCenter != null)
{
this._pathCenter.Dispose();
this._pathCenter = null;
}
}
private GraphicsPath _pathTop = null;
private GraphicsPath _pathLeft = null;
private GraphicsPath _pathBottom = null;
private GraphicsPath _pathRight = null;
private GraphicsPath _pathCenter = null;
private bool _TopRegion = false;
public bool TopRegion
{
get
{
return _TopRegion;
}
set
{
if (_TopRegion != value)
{
_TopRegion = value;
this.Invalidate();
}
}
}
private bool _RightRegion = false;
public bool RightRegion
{
get
{
return _RightRegion;
}
set
{
if (_RightRegion != value)
{
_RightRegion = value;
this.Invalidate();
}
}
}
private bool _BottomRegion = false;
public bool BottomRegion
{
get
{
return _BottomRegion;
}
set
{
if (_BottomRegion != value)
{
_BottomRegion = value;
this.Invalidate();
}
}
}
private bool _LeftRegion = false;
public bool LeftRegion
{
get
{
return _LeftRegion;
}
set
{
if (_LeftRegion != value)
{
_LeftRegion = value;
this.Invalidate();
}
}
}
private bool _CenterRegion = false;
public bool CenterRegion
{
get
{
return _CenterRegion;
}
set
{
if (_CenterRegion != value)
{
_CenterRegion = value;
this.Invalidate();
}
}
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
if (this.IsHandleCreated && this._pathTop != null)
{
this.UpdateRegions();
}
}
private void UpdateRegions()
{
int diameterBig = Math.Min(this.Width, this.Height) - 10;
int diameterSmall = Math.Min(this.Width, this.Height) / 3;
if (diameterBig > 0 && diameterSmall > 0)
{
Point _centerPoint = new Point(this.Width / 2, this.Height / 2);
Rectangle rectangle = new Rectangle(_centerPoint.X - diameterBig / 2, _centerPoint.Y - diameterBig / 2, diameterBig, diameterBig);
Rectangle rectangle2 = new Rectangle(_centerPoint.X - diameterSmall / 2, _centerPoint.Y - diameterSmall / 2, diameterSmall, diameterSmall);
_pathTop.Reset();
_pathTop.AddArc(rectangle, 225, 90);
_pathTop.AddArc(rectangle2, -45, -90);
_pathLeft.Reset();
_pathLeft.AddArc(rectangle, 135, 90);
_pathLeft.AddArc(rectangle2, -135, -90);
_pathBottom.Reset();
_pathBottom.AddArc(rectangle, 45, 90);
_pathBottom.AddArc(rectangle2, -225, -90);
_pathRight.Reset();
_pathRight.AddArc(rectangle, -45, 90);
_pathRight.AddArc(rectangle2, -315, -90);
_pathCenter.Reset();
_pathCenter.AddEllipse(rectangle2);
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
if (this.IsHandleCreated)
{
if (this._pathTop == null)
{
this._pathTop = new GraphicsPath();
this._pathRight = new GraphicsPath();
this._pathBottom = new GraphicsPath();
this._pathLeft = new GraphicsPath();
this._pathCenter = new GraphicsPath();
this.UpdateRegions();
}
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
if (this.TopRegion)
{
e.Graphics.FillPath(Brushes.Blue, _pathTop);
}
e.Graphics.DrawPath(Pens.Black, _pathTop);
if (this.RightRegion)
{
e.Graphics.FillPath(Brushes.DarkRed, _pathRight);
}
e.Graphics.DrawPath(Pens.Black, _pathRight);
if (this.BottomRegion)
{
e.Graphics.FillPath(Brushes.Teal, _pathBottom);
}
e.Graphics.DrawPath(Pens.Black, _pathBottom);
if (this.LeftRegion)
{
e.Graphics.FillPath(Brushes.Yellow, _pathLeft);
}
e.Graphics.DrawPath(Pens.Black, _pathLeft);
if (this.CenterRegion)
{
e.Graphics.FillPath(Brushes.LightGreen, _pathCenter);
}
e.Graphics.DrawPath(Pens.Black, _pathCenter);
}
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
Point p = new Point(e.X, e.Y);
if (this._pathTop.IsVisible(p))
{
this.TopRegion = !this.TopRegion;
}
else if (this._pathRight.IsVisible(p))
{
this.RightRegion = !this.RightRegion;
}
else if (this._pathBottom.IsVisible(p))
{
this.BottomRegion = !this.BottomRegion;
}
else if (this._pathLeft.IsVisible(p))
{
this.LeftRegion = !this.LeftRegion;
}
else if (this._pathCenter.IsVisible(p))
{
this.CenterRegion = !this.CenterRegion;
}
}
}

Related

Change transparency for ToolStrip submenu

I am tampering with ToolStrip modifications as of now and is trying to make the submenu also transparent like the MenuStrip. I can't manage to make the submenu's property to be like the menu itself.
How do I do that?
Here's my code for the modifications:
public class ArrowRenderer : ToolStripProfessionalRenderer
{
public ArrowRenderer() : base(new LeftMenuColorTable())
{
}
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
var tsMenuItem = e.Item as ToolStripMenuItem;
if (tsMenuItem != null)
e.TextColor = Color.White;
base.OnRenderItemText(e);
}
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e)
{
var tsMenuItem = e.Item as ToolStripMenuItem;
if (tsMenuItem != null)
e.ArrowColor = Color.White;
base.OnRenderArrow(e);
}
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
{
var tsMenuItem = e.Item as ToolStripMenuItem;
if (tsMenuItem != null)
e.Item.BackColor = Color.Black;
base.OnRenderMenuItemBackground(e);
}
}
public class LeftMenuColorTable : ProfessionalColorTable
{
public override Color MenuItemSelected
{
// when the menu is selected
get { return ColorTranslator.FromHtml("#494f52"); }
}
public override Color ToolStripBorder
{
get { return ColorTranslator.FromHtml("#FFFFFF"); }
}
public override Color ToolStripDropDownBackground
{
get { return Color.White; }
}
}
internal void SetTrayMenu()
{
if (m_menu != null)
if (notifyIcon.ContextMenuStrip != null)
notifyIcon.ContextMenuStrip.Refresh();
m_menu = new ContextMenuStrip();
m_menu.Renderer = new ArrowRenderer();
m_menu.AllowTransparency = true;
m_menu.Opacity = 0.8;
m_menu.BackColor = Color.Black;
}
Because the ToolStripDropDownMenu that hosts/lists the sub items or DropDownItems is not the same object that the ContextMenuStrip inherits. Hence you need to apply the same settings for each sub menu or DropDown.
The SetTrayMenu() should do:
internal void SetTrayMenu()
{
if (m_menu != null && notifyIcon.ContextMenuStrip != null)
//Why?
notifyIcon.ContextMenuStrip.Refresh();
else
{
m_menu = new ContextMenuStrip
{
Renderer = new ArrowRenderer(),
AllowTransparency = true,
Opacity = 0.8,
};
foreach (var dd in m_menu.Items.OfType<ToolStripMenuItem>()
.Where(x => x.HasDropDown))
{
var ddm = dd.DropDown as ToolStripDropDownMenu;
if (ddm != null)
{
ddm.AllowTransparency = true;
ddm.Opacity = 0.8;
}
}
m_menu.BackColor = Color.Black;
}
}
Before
After
Note: Opacity = 0.5 here.

Why does TextBox.GetFirstCharIndexFromLine always return 0?

I made a subclass for TextBox and tested the following method in a separate test project.
internal static int NumberOfPhysicalLinesInTextBox(TextBox tb)
{
int lc = 0;
while (tb.GetFirstCharIndexFromLine(lc) != -1)
{
++lc;
}
return lc;
}
The code Works well, but in my subclass it does not. The above static method is called only from the method UpdateVisibleScrollBars, which is called only in the following places:
from the subclass' c-tor
OnTextChanged
OnFontChanged
OnResize
The only speciality of this subclass is that it has a placeholder when the user did not enter anything in the TextBox, and this UpdateVisibleScrollBars. In this subclass NumberOfPhysicalLinesInTextBox does not return, it loops indefinitely because the GetFirstCharIndexFromLine always returns 0 when the text is the placeholder: "Enter text here...".
Update: I do not use Lines because I need the physical lines (the lines that result after Word-wrapping), so I can know if I need to show or hide the vertical scrollbar. The TextBox is set with WordWrap = true. Here is the GetFirstCharIndexFromLine method's official documentation.
Update 2: All the class' code is below (without non-English comments):
class EnhancedTextBox : TextBox
{
internal string PlaceholderText = "Enter text here...";
internal string ActualText
{
get
{
return PlaceholderShown ? "" : Text;
}
set
{
if (value == "" || value == null)
{
if (Text == PlaceholderText)
{
PlaceholderShown = true;
ActualTextChanged?.Invoke(this, EventArgs.Empty);
}
else
{
if (!Focused)
{
BeforeActualTextChanged?.Invoke(this, EventArgs.Empty);
ProgrammaticTextChange = true;
Text = PlaceholderText;
ProgrammaticTextChange = false;
PlaceholderShown = true;
ActualTextChanged?.Invoke(this, EventArgs.Empty);
}
else
{
PlaceholderShown = false;
ActualTextChanged?.Invoke(this, EventArgs.Empty);
}
}
}
else
{
if (Text != value)
{
BeforeActualTextChanged?.Invoke(this, EventArgs.Empty);
ProgrammaticTextChange = true;
Text = value;
ProgrammaticTextChange = false;
}
PlaceholderShown = false;
ActualTextChanged?.Invoke(this, EventArgs.Empty);
}
}
}
internal Color _PlaceholderForeColor = Utils.GrayByPercent(50);
internal Color PlaceholderForeColor
{
get
{
return _PlaceholderForeColor;
}
set
{
if (_PlaceholderForeColor != value)
{
_PlaceholderForeColor = value;
Invalidate();
}
}
}
internal Color _NormalForeColor = Color.Empty;
internal Color NormalForeColor
{
get
{
return _NormalForeColor;
}
set
{
if (_NormalForeColor != value)
{
_NormalForeColor = value;
Invalidate();
}
}
}
internal bool _PlaceholderShown = true;
internal bool PlaceholderShown
{
get
{
return _PlaceholderShown;
}
set
{
if (_PlaceholderShown != value)
{
_PlaceholderShown = value;
ForceUpdatePlaceholderShown(value);
}
}
}
internal void ForceUpdatePlaceholderShown(bool value)
{
ForeColor = value ? PlaceholderForeColor :
NormalForeColor;
Invalidate();
}
public EnhancedTextBox() : base()
{
NormalForeColor = ForeColor;
ProgrammaticTextChange = true;
Text = PlaceholderText;
ProgrammaticTextChange = false;
PlaceholderShown = true;
ForceUpdatePlaceholderShown(true);
UpdateVisibleScrollBars();
}
protected override void OnEnter(EventArgs e)
{
HidePlaceholder();
base.OnEnter(e);
}
private void HidePlaceholder()
{
if (PlaceholderShown)
{
ProgrammaticTextChange = true;
Text = "";
ProgrammaticTextChange = false;
PlaceholderShown = false;
}
}
protected override void OnLeave(EventArgs e)
{
ShowPlaceholder();
base.OnLeave(e);
}
private void ShowPlaceholder()
{
if (Text == "")
{
ProgrammaticTextChange = true;
Text = PlaceholderText;
ProgrammaticTextChange = false;
PlaceholderShown = true;
}
}
internal static int NumberOfPhysicalLinesInTextBox(TextBox tb)
{
int lc = 0;
while (tb.GetFirstCharIndexFromLine(lc) != -1)
{
++lc;
}
return lc;
}
internal bool ProgrammaticTextChange = false;
/// <summary>
/// Do not use this event using handlers. Use ActualTextChanged instead.
/// </summary>
/// <param name="e"></param>
protected override void OnTextChanged(EventArgs e)
{
if (ProgrammaticTextChange)
{
return;
}
ActualText = Text;
base.OnTextChanged(e);
UpdateVisibleScrollBars();
}
private bool busy = false;
private void UpdateVisibleScrollBars()
{
if (busy) return;
busy = true;
bool c1 = false; // chars == Text.Length; // TODO: this not working for WordWrap = false
bool c2 = NumberOfPhysicalLinesInTextBox(this) > 2;
if (c1 && c2)
{
ScrollBars = ScrollBars.Both;
}
else if (c1)
{
ScrollBars = ScrollBars.Horizontal;
}
else if (c2)
{
ScrollBars = ScrollBars.Vertical;
}
else
{
ScrollBars = ScrollBars.None;
}
ScrollToCaret();
busy = false;
}
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
UpdateVisibleScrollBars();
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
UpdateVisibleScrollBars();
}
public event EventHandler ActualTextChanged, BeforeActualTextChanged;
}
If I replace bool c2 = NumberOfPhysicalLinesInTextBox(this) > 2; with bool c2 = false; there is no non-ending while loop, although I see that the OnResize handler is called often in debugging with a breakpoint put on the c2 line, and repeatedly clicking Continue. Then If I press Continue really fast a few times, the program starts and is usable.
Update 3: Commenting out the UpdateVisibleScrollBars call inside the OnResize handler makes everything work. How can I make the scrollbars' visibility be changed when the TextBox is just resized?
Current code:
class EnhancedTextBox : TextBox
{
internal string _PlaceholderText = "Enter text here...";
internal string PlaceholderText
{
get
{
return _PlaceholderText;
}
set
{
_PlaceholderText = value;
Invalidate();
}
}
internal Color _PlaceholderForeColor = SystemColors.GrayText;
public Color PlaceholderForeColor
{
get
{
return _PlaceholderForeColor;
}
set
{
_PlaceholderForeColor = value;
Invalidate();
}
}
[Obsolete]
internal string ActualText
{
get
{
return Text;
}
set
{
if (Text != value)
{
Text = value;
}
}
}
internal Color _NormalForeColor = Color.Empty;
internal Color NormalForeColor
{
get
{
return _NormalForeColor;
}
set
{
if (_NormalForeColor != value)
{
_NormalForeColor = value;
ForeColor = value;
}
}
}
public EnhancedTextBox() : base()
{
NormalForeColor = ForeColor;
WordWrap = true;
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0xf)
{
if (!this.Focused && string.IsNullOrEmpty(this.Text)
&& !string.IsNullOrEmpty(this.PlaceholderText))
{
using (var g = this.CreateGraphics())
{
TextRenderer.DrawText(g, this.PlaceholderText, this.Font,
this.ClientRectangle, this.PlaceholderForeColor, this.BackColor,
TextFormatFlags.Top | TextFormatFlags.Left);
}
}
}
}
internal static int NumberOfPhysicalLinesInTextBox(TextBox tb)
{
int lc = 0;
while (tb.GetFirstCharIndexFromLine(lc) != -1)
{
++lc;
}
return lc;
}
internal bool ProgrammaticTextChange = false;
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
ActualTextChanged?.Invoke(this, e);
UpdateVisibleScrollBars();
}
private bool busy = false;
private Size textSize = Size.Empty;
private void UpdateVisibleScrollBars()
{
if (busy) return;
busy = true;
bool c1 = false; // chars == Text.Length; // TODO: this not working for WordWrap = false
bool c2 = NumberOfPhysicalLinesInTextBox(this) > 2;
if (c1 && c2)
{
ScrollBars = ScrollBars.Both;
}
else if (c1)
{
ScrollBars = ScrollBars.Horizontal;
}
else if (c2)
{
ScrollBars = ScrollBars.Vertical;
}
else
{
ScrollBars = ScrollBars.None;
}
ScrollToCaret();
busy = false;
}
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
UpdateVisibleScrollBars();
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
//UpdateVisibleScrollBars();
}
[Obsolete]
public event EventHandler ActualTextChanged;
}

Custom combobox control border flickers when mouse hovers in and out

I am developing a custom combobox control dervied from the standard combobox that will look flat and borderless based on the article here:
http://www.codeproject.com/Articles/6971/Making-Standard-ComboBox-appear-flat
According to various sources I will have to override the windows procedure to do that so here is my WndProc override where I have blocked several messages from reaching the control:
protected override void WndProc(ref Message m)
{
IntPtr hDC = IntPtr.Zero;
Graphics gdc = null;
switch (m.Msg)
{
// Block these messages
case WM_CHANGEUISTATE:
case WM_MOUSEACTIVATE:
case WM_MOUSEFIRST:
case WM_MOUSELAST:
case WM_MOUSEHOVER:
case WM_MOUSELEAVE:
m.Result = (IntPtr)1;
break;
// Here we paint the border when non-client paint is received
case WM_NC_PAINT:
hDC = GetWindowDC(this.Handle);
gdc = Graphics.FromHdc(hDC);
SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
SendPrintClientMsg(); // Send to draw client area
PaintFlatControlBorder(this, gdc);
m.Result = (IntPtr) 1; // Indicate message has been processed
ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
break;
case WM_PAINT:
base.WndProc(ref m);
// Flatten the border area again
hDC = GetWindowDC(this.Handle);
gdc = Graphics.FromHdc(hDC);
Pen p = new Pen((this.Enabled? BackColor:SystemColors.Control), 2);
gdc.DrawRectangle(p, new Rectangle(2, 2, this.Width-3, this.Height-3));
PaintFlatDropDown(this, gdc);
PaintFlatControlBorder(this, gdc);
ReleaseDC(m.HWnd, hDC);
gdc.Dispose();
break;
default:
base.WndProc(ref m);
break;
}
}
Here is my constructor:
public FlatComboBox() : base()
{
this.FlatStyle = FlatStyle.Flat;
this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true);
}
What other wndproc messages do I have to block or is there another way around this?
Here is a good reference of all wndproc messages:
https://www.autoitscript.com/autoit3/docs/appendix/WinMsgCodes.htm
I am using .NET v4.5.
Thanks in advance.
I have done this before with a combo box to give it a customisable flat appearance, I am showing the full code so that is easier to get the idea of how it works, however it uses a custom drop down menu and menu items to complete the appearance.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace Custom.Controls
{
public class CustomComboBox : UserControl
{
private const int DEFAULT_WIDTH = 121;
private const int DEFAULT_HEIGHT = 20;
private CustomContextMenuStrip _popupControl;
private CustomToolStripMenuItem _selectedItem;
private bool _bDroppedDown;
private Color _borderColour;
private Color _dropDownButtonColour;
private Color _droppedDownArrowColour;
private Color _closedArrowColour;
private Color _dropDownBackColour;
private Color _dropDownForeColour;
private Color _dropDownBorderColour;
public Color BorderColour
{
get
{
return _borderColour;
}
set
{
_borderColour = value;
this.Invalidate();
}
}
public Color ClosedArrowColour
{
get
{
return _closedArrowColour;
}
set
{
_closedArrowColour = value;
this.Invalidate();
}
}
public Color DroppedDownArrowColour
{
get
{
return _droppedDownArrowColour;
}
set
{
_droppedDownArrowColour = value;
this.Invalidate();
}
}
public Color DropDownButtonColour
{
get
{
return _dropDownButtonColour;
}
set
{
_dropDownButtonColour = value;
this.Invalidate();
}
}
public Color DropDownBorderColour
{
get
{
return _dropDownBorderColour;
}
set
{
_dropDownBorderColour = value;
_popupControl.BorderColour = value;
this.Invalidate();
}
}
public Color DropDownBackColour
{
get
{
return _dropDownBackColour;
}
set
{
_dropDownBackColour = value;
_popupControl.BackColor = value;
this.Invalidate();
}
}
public Color DropDownForeColour
{
get
{
return _dropDownForeColour;
}
set
{
_dropDownForeColour = value;
_popupControl.ForeColor = value;
this.Invalidate();
}
}
public bool DropShadowEnabled
{
get
{
return _popupControl.DropShadowEnabled;
}
set
{
_popupControl.DropShadowEnabled = value;
this.Invalidate();
}
}
public bool DroppedDown
{
get
{
return _bDroppedDown;
}
set
{
_bDroppedDown = value;
if (value)
{
_popupControl.Show(this, new Point(0, this.Height), ToolStripDropDownDirection.BelowRight);
}
else
{
_popupControl.Hide();
}
this.Invalidate();
}
}
public ToolStripItemCollection Items
{
get
{
return _popupControl.Items;
}
}
public CustomToolStripMenuItem SelectedItem
{
get
{
return _selectedItem;
}
}
public CustomComboBox()
{
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.Selectable, true);
this.SetStyle(ControlStyles.UserMouse, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SuspendLayout();
this.ResumeLayout(false);
_popupControl = new CustomContextMenuStrip();
_popupControl.BackColor = this.BackColor;
_popupControl.Closed += new ToolStripDropDownClosedEventHandler(PopupControl_Closed);
_popupControl.ItemClicked += new ToolStripItemClickedEventHandler(PopupControl_ItemClicked);
this.Width = DEFAULT_WIDTH;
this.Height = DEFAULT_HEIGHT;
_selectedItem = null;
_bDroppedDown = false;
this.BackColor = SystemColors.Control;
this.ForeColor = SystemColors.ControlText;
_borderColour = SystemColors.ActiveBorder;
_dropDownButtonColour = SystemColors.ButtonFace;
_droppedDownArrowColour = SystemColors.ControlLight;
_closedArrowColour = SystemColors.ControlDark;
//Set these via the properties so they take effect on _popupControl
this.DropDownBackColour = SystemColors.Control;
this.DropDownForeColour = SystemColors.ControlText;
this.DropDownBorderColour = SystemColors.ActiveBorder;
}
protected override void OnFontChanged(EventArgs e)
{
_popupControl.Font = this.Font;
base.OnFontChanged(e);
}
protected override void OnMouseDown(MouseEventArgs e)
{
this.Invalidate();
this.DroppedDown = !this.DroppedDown;
base.OnMouseDown(e);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
int nIndex = this.Items.IndexOf(_selectedItem);
if (e.Delta < 0)
{
if (nIndex < (this.Items.Count - 1))
{
_selectedItem = (CustomToolStripMenuItem)this.Items[nIndex + 1];
OnSelectedItemChanged(EventArgs.Empty);
this.Invalidate();
}
}
else if (e.Delta > 0)
{
if (nIndex > 0)
{
_selectedItem = (CustomToolStripMenuItem)this.Items[nIndex - 1];
OnSelectedItemChanged(EventArgs.Empty);
this.Invalidate();
}
}
base.OnMouseWheel(e);
}
protected override void OnPaint(PaintEventArgs e)
{
Rectangle boundingRect = new Rectangle(0, 0, this.Width, this.Height);
using (SolidBrush brush = new SolidBrush(this.BackColor))
{
e.Graphics.FillRectangle(brush, boundingRect);
}
ControlPaint.DrawBorder(e.Graphics, boundingRect, _borderColour, ButtonBorderStyle.Solid);
//Draw the dropdown button background
int nButtonWidth = SystemInformation.VerticalScrollBarWidth + SystemInformation.VerticalFocusThickness;
Rectangle dropDownButtonRect = new Rectangle(this.Width - nButtonWidth, 0, nButtonWidth, this.Height);
using (SolidBrush brush = new SolidBrush(_dropDownButtonColour))
{
e.Graphics.FillRectangle(brush, dropDownButtonRect);
}
//Draw the dropdown button arrow
using (GraphicsPath path = new GraphicsPath())
{
Point pTopLeft = new Point()
{
X = (int)Math.Round((float)dropDownButtonRect.X + ((float)dropDownButtonRect.Width * 0.30f)),
Y = (int)Math.Round((float)dropDownButtonRect.Y + ((float)dropDownButtonRect.Height * 0.35f))
};
Point pTopRight = new Point()
{
X = (int)Math.Round((float)dropDownButtonRect.X + ((float)dropDownButtonRect.Width * 0.70f)),
Y = (int)Math.Round((float)dropDownButtonRect.Y + ((float)dropDownButtonRect.Height * 0.35f))
};
Point pBottom = new Point()
{
X = (int)Math.Round((float)dropDownButtonRect.X + ((float)dropDownButtonRect.Width * 0.5f)),
Y = (int)Math.Round((float)dropDownButtonRect.Y + ((float)dropDownButtonRect.Height * 0.65f))
};
path.AddLine(pTopLeft, pTopRight);
path.AddLine(pTopRight, pBottom);
SmoothingMode previousSmoothingMode = e.Graphics.SmoothingMode;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
{
using (SolidBrush brush = new SolidBrush(_bDroppedDown ? _droppedDownArrowColour : _closedArrowColour))
{
e.Graphics.FillPath(brush, path);
}
}
e.Graphics.SmoothingMode = previousSmoothingMode;
}
if (_selectedItem != null)
{
using (SolidBrush brush = new SolidBrush(this.ForeColor))
{
SizeF stringSize = e.Graphics.MeasureString(_selectedItem.Text, this.Font);
e.Graphics.DrawString(_selectedItem.Text, this.Font, brush, new Point(0, (this.Height / 2) - ((int)stringSize.Height / 2)));
}
}
}
protected override void OnSizeChanged(EventArgs e)
{
if (_popupControl != null)
{
_popupControl.MaximumItemSize = new Size(this.Width - 1, _popupControl.MaximumItemSize.Height);
_popupControl.Width = this.Width;
}
base.OnSizeChanged(e);
}
private void OnSelectedItemChanged(EventArgs e)
{
if (SelectedItemChanged != null)
{
SelectedItemChanged(this, e);
}
}
public void SelectFirstItem()
{
if (this.Items != null && this.Items.Count > 0)
{
_selectedItem = (CustomToolStripMenuItem)this.Items[0];
OnSelectedItemChanged(EventArgs.Empty);
}
}
public event EventHandler SelectedItemChanged;
private void PopupControl_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
this.DroppedDown = false;
this.Invalidate(true);
}
private void PopupControl_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
_selectedItem = (CustomToolStripMenuItem)e.ClickedItem;
OnSelectedItemChanged(EventArgs.Empty);
}
}
}

C# progress bar bad render

I created custom progress bar with image but i have problem. From 50% on progress bar are showing spaces.
Progress Bar here: http://i.stack.imgur.com/d686B.png
There is control library code:
public partial class UserControl1: UserControl
{
public UserControl1() : base()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
private void UserControl1_Load(object sender, EventArgs e)
{
}
bool _revealImage = true;
int _maximum = 100;
int _value = 0;
Image _progressbarImage = Properties.Resources.progress;
Color _progressbarColor = Color.Transparent;
protected override void OnResize(EventArgs e)
{
// Invalidate the control to get a repaint.
this.Invalidate();
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
Rectangle r = this.ClientRectangle;
ControlPaint.DrawBorder(g, r, Color.Transparent, ButtonBorderStyle.Solid);
float percent = (float)_value / (float)(_maximum);
//r.Inflate(-1, -1);
r.Width = (int)((float)r.Width * percent);
if ((r.Width < 1))
{
return;
}
if (_progressbarImage == null)
{
using (SolidBrush b = new SolidBrush(_progressbarColor))
{
g.FillRectangle(b, r);
b.Dispose();
}
}
else
{
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
if (_revealImage)
{
g.DrawImage(_progressbarImage, r, r, GraphicsUnit.Pixel);
}
else
{
g.DrawImage(_progressbarImage, r);
}
}
g.Dispose();
}
public int Maximum
{
get
{
return _maximum;
}
set
{
_maximum = value;
this.Invalidate();
}
}
public int Value
{
get
{
return _value;
}
set
{
// _value = value;
int oldValue = _value;
// Make sure that the value does not stray outside the valid range.
if (value < 0)
{
_value = 0;
}
else if (value > Maximum)
{
_value = Maximum;
}
else
{
_value = value;
}
// Invalidate only the changed area.
float percent;
Rectangle newValueRect = this.ClientRectangle;
Rectangle oldValueRect = this.ClientRectangle;
// Use a new value to calculate the rectangle for progress.
percent = (float)(_value - 0) / (float)(Maximum - 0);
newValueRect.Width = (int)((float)newValueRect.Width * percent);
// Use an old value to calculate the rectangle for progress.
percent = (float)(oldValue - 0) / (float)(Maximum - 0);
oldValueRect.Width = (int)((float)oldValueRect.Width * percent);
Rectangle updateRect = new Rectangle();
// Find only the part of the screen that must be updated.
if (newValueRect.Width > oldValueRect.Width)
{
updateRect.X = oldValueRect.Size.Width;
updateRect.Width = newValueRect.Width - oldValueRect.Width;
}
else
{
updateRect.X = newValueRect.Size.Width;
updateRect.Width = oldValueRect.Width - newValueRect.Width;
}
updateRect.Height = this.Height;
// Invalidate the intersection region only.
this.Invalidate(updateRect);
}
}
public Image ProgressbarImage
{
get
{
return _progressbarImage;
}
set
{
_progressbarImage = value;
this.Invalidate();
}
}
public Color ProgressbarColor
{
get
{
return _progressbarColor;
}
set
{
_progressbarColor = value;
this.Invalidate();
}
}
public bool RevealImage
{
get
{
return _revealImage;
}
set
{
_revealImage = value;
this.Invalidate();
}
}
}
Thank you for help.

Mouse down between two pieces of a puzzle

I am building a puzzle game in winforms, and i want to recognize the mousedown over any piece, and move it with the mousemove.
The issue is that when i touch the transparent part of the puzzle piece, i want to verify if there is any piece behind that one, and if so, start the mousemove of that other piece, got it?
I am also able to recognize if the mousedown was over the image, or if it happens in the transparent part of the puzzle piece. My problem is to get the best way to pass the mouse event to the piece behind.
Many Thanks in advance.
UPDATE 1
The following is the class for the puzzle piece:
class Peça : DrawingArea
{
private Point _Offset = Point.Empty;
public Image imagem
{
get;
set;
}
protected override void OnDraw()
{
Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
this.graphics.DrawImage(imagem, location);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (_Offset != Point.Empty)
{
Point newlocation = this.Location;
newlocation.X += e.X - _Offset.X;
newlocation.Y += e.Y - _Offset.Y;
this.Location = newlocation;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
_Offset = Point.Empty;
}
protected override void OnMouseDown(MouseEventArgs e)
{
Down(e);
//Console.WriteLine(color.ToString());
}
public void Down(MouseEventArgs e)
{
Bitmap b = new Bitmap(imagem);
Color? color = null;
try
{
color = b.GetPixel(e.X, e.Y);
if (color.Value.A != 0 && color != null)
{
if (e.Button == MouseButtons.Left)
{
_Offset = new Point(e.X, e.Y);
this.BringToFront();
}
}
}
catch {
}
}
}
The following code, is my DrawingArea (Panel) that i create in order to work with transparency:
abstract public class DrawingArea : Panel
{
protected Graphics graphics;
abstract protected void OnDraw();
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
public DrawingArea()
{
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
}
protected override void OnPaint(PaintEventArgs e)
{
this.graphics = e.Graphics;
this.graphics.TextRenderingHint =
System.Drawing.Text.TextRenderingHint.AntiAlias;
this.graphics.InterpolationMode =
System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
this.graphics.PixelOffsetMode =
System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
this.graphics.SmoothingMode =
System.Drawing.Drawing2D.SmoothingMode.HighQuality;
OnDraw();
}
}
And you can also see my Form code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
}
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000;
return handleParam;
}
}
}
Those are my pieces, and when i touch the transparent space in the first piece, i want to pick up the second one and move it on mouseMouse instead of doing nothing...
It looks like this:
Apologize my bad english.
UPDATE 2
I think i am getting very close to the solution, but something strange happens now, when i touch the piece behind another one, it disappear...
What am i doing wrong?
SOME CODE UPDATES
Piece Class:
class Peça : DrawingArea
{
private Point _Offset = Point.Empty;
public Boolean movable = false;
public Image imagem
{
get;
set;
}
protected override void OnDraw()
{
Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
this.graphics.DrawImage(imagem, location);
}
public void Move(MouseEventArgs e)
{
if (_Offset != Point.Empty)
{
Point newlocation = this.Location;
newlocation.X += e.X - _Offset.X;
newlocation.Y += e.Y - _Offset.Y;
this.Location = newlocation;
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
_Offset = Point.Empty;
movable = false;
}
protected override void OnMouseDown(MouseEventArgs e)
{
Down(e);
//Console.WriteLine(color.ToString());
}
public Boolean Down(MouseEventArgs e, bool propaga=true)
{
Form parentForm = (this.Parent as Form);
Bitmap b = new Bitmap(imagem);
Color? color = null;
Boolean flag = false;
try
{
color = b.GetPixel(e.X, e.Y);
if (color.Value.A != 0 && color != null)
{
if (e.Button == MouseButtons.Left)
{
_Offset = new Point(e.X, e.Y);
this.BringToFront();
flag = true;
movable = true;
}
}
else
{
if(propaga)
(this.Parent as Form1).propagaEvento(this, e);
flag = false;
}
return flag;
}
catch {
return flag; }
}
}
Form1:
public partial class Form1 : Form
{
private List<Peça> peças;
private Point _Offset = Point.Empty;
public Form1()
{
InitializeComponent();
peças = new List<Peça>();
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
criaListaPecas();
associaEventosPecas();
}
private void associaEventosPecas()
{
foreach (Peça p in peças)
{
p.MouseMove += Form1_MouseMove;
}
}
private void criaListaPecas()
{
peças.Clear();
foreach (Control p in this.Controls)
{
if (p.GetType() == typeof(Peça))
peças.Add((Peça)p);
}
Console.WriteLine(peças[0].Name);
Console.WriteLine(peças[1].Name);
Console.WriteLine(peças[2].Name);
}
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000;
return handleParam;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
label1.Text = e.Location.ToString();
gereMovimento(e);
}
private void gereMovimento(MouseEventArgs e)
{
foreach (Peça p in peças)
{
if (p.movable)
{
p.Move(e);
}
}
}
internal void propagaEvento(Peça peça, MouseEventArgs e)
{
foreach (Peça p in peças)
{
if (p != peça)
{
if (p.Down(e, false))
break;
}
}
}
}
Thanks in advance again :)
Pieces can be represent as:
public class Piece
{
public Point Location {get; set;}
public int Z {get; set;}
public int ID {get; set;} // to be bound to control or a control itself?
public Image Image {get; set;} // texture?
public DockStyle PlusArea {get; set;}
public DockStyle MinusArea {get; set;} // can be None
...
public bool HitTest(Point point)
{
// assuming all of same size
if((new Rectangle(Location, new Size(...)).Contains(point))
{
switch(MinusArea)
{
case Top:
if((new Rectangle(...)).Contains(point))
return false;
...
}
}
switch(MinusArea)
{
case Top:
if((new Rectangle(...)).Contains(point))
return true;
...
}
return false;
}
Then puzzle is
public class Puzzle
{
public List<Piece> Pieces {get; set;}
public void Draw(Graphics graphics)
{
// draw all pictures with respect to z order
}
public Piece HitTest(Point point)
{
... // hittest all pieces, return highest z-order or null
}
}
It is not a complete solution, but should give you idea.
Basically:
In mouse event you call Figure.HitTest() to get figure to start moving (that's what you need).
You draw everything into owner drawn control by calling Figure.Draw().
Obviously, drag-n-drop operations are calling Invalidate().
You may have special flag to indicate figure being dragged and draw it differently (with shadows, a bit offsetted to simulate it's pulled over other pieces, etc).
Each figure is represented as rectangle and PlusArea or MinusArea (don't know how to call them better, it's this extra or missing area of piece connectors), this is simplification, you can improve it.
In general, keep a list of all your puzzle piece controls, sorted top down. When you get a mouse down event on one piece, check the transparency at that point, if it it not transparent handle the event on that piece. If it is transparent forward the event to the next piece down in your list (directly calling the event handler is probably the easiest way). Keep doing this until you either find a non transparent point, or run out of pieces.
UPDATE
Here is a link to a project showing an example of how to do this in pure GDI.
https://drive.google.com/file/d/0B42fIyGTLNv3WlJwNGVRN2txTGs/edit?usp=sharing
SOLVED :)
i have figured it out...
Here's the code to anybody how needs
(I have made it right now, so the code is not clean yet):
Piece Class:
class Peça : DrawingArea
{
private Point _Offset = Point.Empty;
public Boolean movable = false;
public Image imagem
{
get;
set;
}
protected override void OnDraw()
{
Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
this.graphics.DrawImage(imagem, location);
}
public Boolean Down(Point e, bool propaga = true)
{
Bitmap b = new Bitmap(imagem);
Color? color = null;
Boolean flag = false;
try
{
color = b.GetPixel(e.X, e.Y);
if (color.Value.A != 0 && color != null)
{
flag = true;
}
else
{
flag = false;
}
return flag;
}
catch
{
return flag;
}
}
}
Form1:
public partial class Form1 : Form
{
private List<Peça> peças;
private Point _Offset = Point.Empty;
private Peça peça1, peça2, peça3, peça4;
private bool canMove;
private Peça atual;
private bool other=false;
public Form1()
{
FormBorderStyle = FormBorderStyle.None;
WindowState = FormWindowState.Maximized;
InitializeComponent();
atual = new Peça();
peça1 = new Peça();
peça2 = new Peça();
peça3 = new Peça();
peça4 = new Peça();
peça1.imagem = Properties.Resources._4p1_1;
peça2.imagem = Properties.Resources._4p1_2;
peça3.imagem = Properties.Resources._4p1_3;
peça4.imagem = Properties.Resources._4p1_4;
peças = new List<Peça>();
peça1.Name = "peça1";
peça2.Name = "peça2";
peça3.Name = "peça3";
peça4.Name = "peça4";
this.Controls.Add(peça1);
this.Controls.Add(peça2);
this.Controls.Add(peça3);
this.Controls.Add(peça4);
criaListaPecas();
foreach (Peça p in peças)
{
p.Size = new Size(p.imagem.Width, p.imagem.Height);
}
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
associaEventosPecas();
canMove = false;
}
private void associaEventosPecas()
{
foreach (Peça p in peças)
{
p.MouseMove += Form1_MouseMove;
p.MouseDown += Form1_MouseDown;
p.MouseUp += Form1_MouseUp;
}
}
private void criaListaPecas()
{
peças.Clear();
foreach (Control p in this.Controls)
{
if (p.GetType() == typeof(Peça))
peças.Add((Peça)p);
}
Console.WriteLine(peças[0].Name);
Console.WriteLine(peças[1].Name);
Console.WriteLine(peças[2].Name);
Console.WriteLine(peças[3].Name);
}
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000;
return handleParam;
}
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (sender.GetType().Equals(typeof(Peça)))
{
label1.Text = new Point(e.Location.X + (sender as Peça).Location.X, e.Location.Y + (sender as Peça).Location.Y).ToString();
}
else
label1.Text = e.Location.ToString();
gereMovimento(sender, e);
}
private void gereMovimento(object sender, MouseEventArgs e)
{
if (canMove)
{
if (other)
{
Point p = atual.PointToClient(new Point(e.X + (sender as Peça).Location.X, e.Y + (sender as Peça).Location.Y));
Point newlocation = atual.Location;
newlocation.X += p.X - _Offset.X;
newlocation.Y += p.Y - _Offset.Y;
atual.Location = newlocation;
}
else
{
Point newlocation = atual.Location;
newlocation.X += e.X - _Offset.X;
newlocation.Y += e.Y - _Offset.Y;
atual.Location = newlocation;
}
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (sender.GetType().Equals(typeof(Peça)) && e.Button == MouseButtons.Left)
{
atual = sender as Peça;
atual.BringToFront();
criaListaPecas();
if (atual.Down(e.Location))
{
_Offset = new Point(e.X, e.Y);
canMove = true;
other = false;
}
else
{
Console.WriteLine(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)));
Console.WriteLine(atual.Location);
Point p = new Point();
if (peças[1].ClientRectangle.Contains(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
&& peças[1].Down(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
{
p = peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
atual = peças[1];
atual.BringToFront();
criaListaPecas();
_Offset = p;
canMove = true;
other = true;
}
else if (peças[2].ClientRectangle.Contains(peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
&& peças[2].Down(peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
{
p = peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
atual = peças[2];
atual.BringToFront();
criaListaPecas();
_Offset = p;
canMove = true;
other = true;
}
else if (peças[3].ClientRectangle.Contains(peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
&& peças[3].Down(peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
{
p = peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
atual = peças[3];
atual.BringToFront();
criaListaPecas();
_Offset = p;
canMove = true;
other = true;
}
}
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
canMove = false;
}
}
Apologize the repeated and confused code, but as i said, i have made it seconds ago, and did not clean the code yet ;)

Categories