I've created a transparent control as suggested here
public partial class TransparentControl : UserControl
{
private readonly Timer refresher;
private Image _image;
public TransparentControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
refresher = new Timer();
refresher.Tick += TimerOnTick;
refresher.Interval = 50;
refresher.Enabled = true;
refresher.Start();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImage(_image, new Rectangle((Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2), _image.Width, _image.Height));
}
protected override void OnPaintBackground(PaintEventArgs e)
{}
public void Redraw()
{
RecreateHandle();
}
private void TimerOnTick(object source, EventArgs e)
{
RecreateHandle();
refresher.Stop();
}
public Image Image
{
get { _image; }
set { _image = value; RecreateHandle(); }
}
}
The problem is that if i overlap two TransparentControl object, the one that stays on top is not being rendered (or maybe it's being rendered but is not visible at all).
Is there something to add to the control to fix this?
Because using PictureBox for the top image works, but on Linux with Mono its not rendering alpha pixels. That's why I need to use this TransparentControl.
Thanks everyone.
Related
Is it possible to have some common event or setting for all forms that create automatically when adding a Form to project?
For example I want to have some override event that is common for all of The Project Forms, so I want to write it once and accept for all forms and speed up developing and decrease mistakes.
Update:
in BaseForm:
public BaseForm()
{
InitializeComponent();
}
int _originalExStyle = -1;
bool _enableFormLevelDoubleBuffering = true;
protected override CreateParams CreateParams
{
get
{
if (_originalExStyle == -1)
_originalExStyle = base.CreateParams.ExStyle;
CreateParams cp = base.CreateParams;
if (_enableFormLevelDoubleBuffering)
cp.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
else
cp.ExStyle = _originalExStyle;
return cp;
}
}
public void TurnOnOffFormLevelDoubleBuffering(bool command)
{
_enableFormLevelDoubleBuffering = command;
}
private void BaseForm_ResizeBegin(object sender, EventArgs e)
{
TurnOnOffFormLevelDoubleBuffering(true);
}
private void BaseForm_ResizeEnd(object sender, EventArgs e)
{
TurnOnOffFormLevelDoubleBuffering(false);
}
in other forms in inherit BaseForm like this:
public partial class Form1 : BaseForm
{
public Form1()
{
InitializeComponent();
}
}
the problem is in form1 the events not fire.
what's wrong or is there any other way?
Thanks in advance.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
Im trying to code a simple slideshow program.
I have a class named SlideShowText.
I want it to be scalable by mouse like scaling the control in Visual Studio.
I want it to have dotted borders.
Any help?
(I didn't try anything since im such a noob)
You can make any control sizeable with the mouse, overriding its CreateParams property.
For example
class SizeableRichTextBox : RichTextBox
{
protected override CreateParams CreateParams
{
get
{
const int WS_SIZEBOX = 0x40000;
var cp = base.CreateParams;
cp.Style |= WS_SIZEBOX;
return cp;
}
}
}
class SizeablePictureBox : PictureBox
{
protected override CreateParams CreateParams
{
get
{
const int WS_SIZEBOX = 0x40000;
var cp = base.CreateParams;
cp.Style |= WS_SIZEBOX;
return cp;
}
}
}
Now they have a thick border and can be resized with the mouse.
The image scale in the SizeablePictureBox will change automatically, if you set the ImageLayout.Zoom parameter.
var pictureBox = new SizeablePictureBox { Parent = this, Width = 500, Height = 500 };
pictureBox.BackgroundImageLayout = ImageLayout.Zoom;
pictureBox.BackgroundImage = Image.FromFile("pic.jpg");
To change the text scale in the TextBox you have to manually calculate the aspect ratio and change the font size. Or you can try to change the value of ZoomFactor property.
Here is a Resizer control:
public partial class Resizer : Control
{
public Resizer()
{
InitializeComponent();
Size = new System.Drawing.Size(12, 12);
}
public Control control { get; set; }
Point mDown = Point.Empty;
public Resizer(Control ctl)
{
InitializeComponent();
control = ctl;
Size = new System.Drawing.Size(12, 12);
}
protected override void OnLayout(LayoutEventArgs levent)
{
base.OnLayout(levent);
if (control != null)
{
BackColor = Color.DarkOrange;
Location = new Point(control.Width - Size.Width,
control.Height - Size.Height);
Parent = control;
BringToFront();
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
mDown = e.Location;
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
Hide();
base.OnMouseUp(e);
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left))
{
Left += -(mDown.X - e.X);
Top += -(mDown.Y - e.Y);
control.Size = new Size(Right, Bottom);
}
base.OnMouseMove(e);
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
}
After adding it to the project you can use it maybe like this:
Resizer rz = null;
private void pictureBox1_DoubleClick(object sender, EventArgs e)
{
if (rz == null) rz = new Resizer(pictureBox1); else rz.Show();
}
Result:
I've created GradientButton which changes angle of gradient when mouse cursor is in its' bounds. Unfortunately the graphics is corrupted as there are random flashes during rendering.
To achieve gradient rotation I start a thread upon MouseEnter and stop it at MouseLeave. Doublebuffered set to true, helped a lot but did not solve this fully.
public partial class GradientButton : UserControl {
public Color Color1 { get; set; }
public Color Color2 { get; set; }
public bool Down { get; set; }
public bool MouseOnButton { get; set; }
[Browsable(true)]
public string TextToDraw { get; set; }
public int Angle { get; set; }
public GradientButton() {
InitializeComponent();
Color1 = Color.YellowGreen;
Color2 = Color.LightGreen;
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
var color1 = Color1;
var color2 = Color2;
if (Down) {
var temp = color1;
color1 = color2;
color2 = temp;
}
if (MouseOnButton) {
color1 = ControlPaint.Dark(Color2);
}
using (LinearGradientBrush brush = new LinearGradientBrush(this.ClientRectangle, color1, color2, Angle)) {
e.Graphics.FillRectangle(brush, this.ClientRectangle);
}
Rectangle rect1 = ClientRectangle;
// Create a StringFormat object with the each line of text, and the block
// of text centered on the page.
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
// Draw the text and the surrounding rectangle.
e.Graphics.DrawString(TextToDraw, Font, new SolidBrush(ForeColor), rect1, stringFormat);
}
protected override void OnClick(EventArgs e) {
base.OnClick(e);
}
protected override void OnResize(EventArgs e) {
base.OnResize(e);
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e) {
base.OnMouseDown(e);
Down = true;
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e) {
base.OnMouseUp(e);
Down = false;
Invalidate();
}
protected override void OnMouseEnter(EventArgs e) {
base.OnMouseEnter(e);
MouseOnButton = true;
Thread t = new Thread(Animate);
t.Start();
}
public void Animate() {
while (MouseOnButton) {
Angle += 5;
Thread.Sleep(25);
Invalidate();
}
}
protected override void OnMouseLeave(EventArgs e) {
base.OnMouseLeave(e);
Angle = 0;
MouseOnButton = false;
Invalidate();
}
}
GradientButton.Designer.cs
partial class GradientButton {
/// <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 Component 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.SuspendLayout();
//
// GradientButton
//
this.Name = "GradientButton";
this.Size = new System.Drawing.Size(78, 28);
this.ResumeLayout(false);
}
#endregion
}
Use
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlsStyles.Opaque, true);
to prevent the background from being painted prior to OnPaint processing. This should prevent the flicker inbetween the background erase and the painting.
I have listview control. I need to add semi-transparent button with image to listview. Something like this:
I found several projects that use semi-transparent buttons on the form. But when I transfer them to the ListView, they do not work.
Necessary to use .net 2.0 framework.
I found some solution.
Making Transparent Controls - No Flickering
I inherit my TransparentToggleButton class from TranspControl class:
public class TransparentToggleButton : TranspControl
{
private Image _normalState;
private Image _mouseUpState;
private Image _activateState;
private bool _state;
private bool _mouseUnder;
public event EventHandler StateChanged;
public bool ToggleState
{
get { return _state; }
set
{
_state = value;
SetImage();
}
}
public void SetImages(Image normalState, Image mouseUpState, Image activateState)
{
BackImage = normalState;
_normalState = normalState;
_mouseUpState = mouseUpState;
_activateState = activateState;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if (e.Button == MouseButtons.Left)
{
_state = !_state;
if (StateChanged != null)
StateChanged(this, e);
SetImage();
}
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
_mouseUnder = true;
SetImage();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
_mouseUnder = false;
SetImage();
}
private void SetImage()
{
try
{
if (_state)
BackImage = _activateState;
else
BackImage = _mouseUnder ? _mouseUpState : _normalState;
}
catch (Exception)
{
}
}
}
Function SetImages loads the 3 images that used for normal state, normal state when cursor over the button, activate state.
Besides need catch listview scroll event and Invalidate() TransparentToggleButton.
So having trying for a while with no luck, i eventually decided to ask about a way to make a transparent controls display each others.
As you see in the picture i have 2 transparent picture boxes, they show the background very well but when it comes to the selected picturebox as you can see in the picture it only renders the background image of the form but not the other picture box below it. I know that there are a common circumstances in winforms due to the lack of proper rendering but the question is :
Is there a way to get around this rendering glitch, is there a way to make the transparent controls render each others ?
Well this is the Answer : Transparent images with C# WinForms
The transparency of a control depends on its parent control .You can however, use a custom container control instead of a picture box for the parent image.and maybe this code is usfull
using System;
using System.Windows.Forms;
using System.Drawing;
public class TransparentControl : Control
{
private readonly Timer refresher;
private Image _image;
public TransparentControl()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
BackColor = Color.Transparent;
refresher = new Timer();
refresher.Tick += TimerOnTick;
refresher.Interval = 50;
refresher.Enabled = true;
refresher.Start();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
protected override void OnPaint(PaintEventArgs e)
{
if (_image != null)
{
e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//Do not paint background
}
//Hack
public void Redraw()
{
RecreateHandle();
}
private void TimerOnTick(object source, EventArgs e)
{
RecreateHandle();
refresher.Stop();
}
public Image Image
{
get
{
return _image;
}
set
{
_image = value;
RecreateHandle();
}
}
}