I have a control. It's a text box. I want to draw an image at the left of the control. The image should be painted outside the control. I could paint it one but inside.
Here is the code:
private static Image requiredIcon = Resources.Icon_required;
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (base.Enabled && string.IsNullOrEmpty(base.Text))
{
e.Graphics.DrawImage(requiredIcon, 0, 0);
}
}
Instead of drawing the image, you could create an appropriate control, e.g. PictureBox, with it's Image property set to the appropriate image resource.
It may be easier to do this at design time rather than run time. If the image should not be shown intitially, set it's Visible property to false at design time and set it to true at run time when the image should be shown.
Create a user control composed of a TextBox and a PictureBox. Then in the OnPaint event of your user control you will be able to draw outside the textbox (in the PictureBox control).
Here's a picture of what the UserControl could look like. It contains a PictureBox and a TextBox.
If you just want to draw an icon you just have to assigned it to the PictureBox. So the OnPaint may not be necessary in your case.
Instead of overloading the TextBox.OnPaint method, you have to overload the Form's (or whatever is the parent component of the TextBox) OnPaint method, and paint the Image at the left hand side of the TextBox. You can't have the TextBox draw to an area outside its own bounds.
I can get a parent and use it for painting.
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
base.Parent.Paint += new PaintEventHandler(Parent_Paint);
}
private void Parent_Paint(object sender, PaintEventArgs e)
{
if (base.Enabled && string.IsNullOrEmpty(base.Text))
{
e.Graphics.DrawImage(requiredIcon, 0, 0);
}
}
Related
i am creating a drawing programe which Suppose to take the parameters from the user
(Radius,height,width,....etc)
i have created a class with one paramter (radius)
public int faceoutline(int r)
{
Graphic = pictureBox1.CreateGraphics();
Graphic.DrawEllipse(myPen, 0, 0, r, r);
return r;
}
then i call it :
private void button1_Click(object sender, EventArgs e)
{
faceoutline(int.Parse(textBox1.Text));
pictureBox1.Invalidate();
}
....and nothing happens
i copied the button code to a timer but it keep balnking
WHAT I AM DOING WRONG ?!
You should place the drawing code in the Paint event handler of the PictureBox, and use the Graphics provided in the event args. This way, your custom drawing code will be executed every time the control is redrawn.
If you don't do it this way, anything you draw will disappear the next time the control is redrawn. In your code, you call Invalidate right after you draw your ellipse, so the control is redrawn without the ellipse...
Question:
How do you properly draw on a winform from a method other than the OnPaint() method?
Additional Information:
The code I have now draws some background lines for a TicTacToe game in the OnPaint() method. Then I use the Mouse_Click event and am running this code which apparently is not proper:
private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
Graphics g = this.CreateGraphics();
g.DrawEllipse(this.penRed, this.Rectangle);
For reasons I do not understand, it does draw the circle, but when minimizing or moving the form off screen it erases the circles but not the lines from the OnPaint() method.
You are doing a lot of "view" but no "model".
When you want to create a shape, when the mouse button goes down/up, create some DATA representing the shape.
Your data structures represent the persistent information (it is the data that allows you to save and load this information between sessions).
All your paint function needs to do is look at the DATA structures and paint it. This will therefore persist between sizing/hiding/showing.
The problem is that Windows windows (that includes WinForms) have no graphical memory of their own unless their creator provides such memory and it is only a matter of time before that particular window wilk get overwritten or hidden and eventually need to be repainted. You're painting to the screen ( you might say ) and others can do the same. The only convention you can rely on is that the OnPaint will get called when needed. Basically it's alright to use your philosophy and draw whenever you need to (not on some misterious and unpredictable schedule). For that check out my solution.
You should use a "backbuffer bitmap" like:
private Bitmap bb;
protected override void OnResize(EventArgs e) {
this.bb = new Bitmap(this.ClientSize.Width, this.ClientSize.Height);
this.InitBackBuffer();
}
private void InitBackBuffer() {
using (var g = Graphics.FromImage(this.bb)) {
// do any of the "non dissapearing line" drawing here
}
}
private void TicTacToe_MouseClick(object sender, MouseEventArgs e)
using (Graphics g = Graphics.FromImage(this.bb))
g.DrawEllipse(this.penRed, this.Rectangle);
this.Invalidate();
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.DrawImageUnscaled(this.bb);
}
Try that. That should do it :)
What you are doing is drawing on the form "asynchronously" (from the OnPaint method). You see, the OnPaint method is what Windows Forms relies on to draw your entire form. When something happens to your From, it is invalidated and OnPaint is called again. If something isn't drawn in that method, then it will not be there after that happens.
If you want a button to trigger something to appear permanently then what you need to do is Add that object to a collection somewhere, or set a variable related to it. Then call Refresh() which calls Invalidate() and Update() Then, during OnPaint, draw that object (ellipis).
If you want it to still be there after something happens to your form, such as minimize, you have to draw it during OnPaint.
Here's my suggestion:
public partial class Form1 : Form
{
Rectangle r = Rectangle.Empty;
Pen redPen = new Pen(Color.Red);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
r = new Rectangle(50, 50, 100, 100);
Refresh();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (r != Rectangle.Empty)
{
e.Graphics.DrawRectangle(redPen, r);
}
}
}
I have a panel where I dynamically add custom controls to it. If controls go out of the panels bounds, Horizontal/Vertical scrollbars automatically shows (AutoScroll == true) and scrollbars will follow the control via the following code:
if(panelDiagram.VerticalScroll.Visible || panelDiagram.HorizontalScroll.Visible) {
panelDiagram.ScrollControlIntoView(tempNode);
}
This way, while moving the tempNode around, scrollbars will follow it.
Is there any way to preserve the state of the scrollbars when I load everything again from the database? I tried a lot of things like ScrollControlIntoView(lastAddedControl) but nothing is working. Maybe I have to turn off AutoScroll and manage everything by my hand?
Panel is derived from ScrollableControl which exposes a few properties you might find useful:
AutoScrollPosition
VerticalScroll
HorizontalScroll
It looks like autoScrollPosition is what you're after; it's a Point instance that contains the current X and Y scroll coordinates for each scrollbar. X will be zero if you're only doing vertical scrolling.
Save it like so:
public override void OnLoad(Object sender, EventArgs e) {
this.panel1.AutoScrollPosition = GetSavedScrollPoint();
}
public override void OnFormClosing(Object sender, EventArgs e) {
SavePointSomewhere( this.panel1.AutoScrollPosition );
}
I have a method where I disable or enable some custom controls and then use a graphics object to draw lines and rectangles.
The gist of the method:
void MyMethod()
{
//...
mycontrol.enabled = false;
mycontrol.visible = false;
mycontrol.Invalidate();
mycontrol.Update();
GraphicsObject.DrawLines();
//...
}
Right after this method returns, the screen looks great. I have rectangles and lines where controls used to be.
However, after the click event handler returns (which called the above method). The controls which should be invisible draw over the lines and rectangles (leaving those area's blank - the same color as the background form).
Is there any way to fix this?
Thanks
As I mentioned in my comment if you are drawing on an object if you do not use the OnPaint Method or the Paint Event your custom drawing will not be automatically redrawn. Depending on what you are drawing on you can do something like( I am assuming you are drawing on a Form).
void MyMethod()
{
//...
mycontrol.enabled = false;
mycontrol.visible = false;
mycontrol.Invalidate();
mycontrol.Update();
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
//Conditional Logic to determine what you are drawing
// myPoints is a Point array that you fill elsewhere in your program
e.Graphics.DrawLines(new Pen(Brushes.Red), myPoints);
}
I'm trying to create a button in my .NET 4.0 Winforms app in Visual Studio 2010 that is ONLY an image. I have a window that is borderless and has a background image that makes up my custom skin for this application. For the close/minimize buttons in the top right of the window, I wanted to create 2 simple buttons that are images only that look like the typical Windows close/minimize buttons.
I may be going about this design wrong, so if I am please let me know. So far I've determined that I need to create a subclass for Button that only renders the image. The final implementation needs to render different images for each button state (normal, hover, clicked, etc). Here is what I have so far:
public class ImageButton : Button
{
Pen pen = new Pen( Color.Red, 1.0f );
public ImageButton()
{
SetClientSizeCore( BackgroundImage.Width, BackgroundImage.Height );
}
protected override void OnPaint( PaintEventArgs e )
{
e.Graphics.DrawImage( BackgroundImage, 0, 0 );
//e.Graphics.DrawRectangle( pen, ClientRectangle );
//Rectangle bounds = new Rectangle( 0, 0, Width, Height );
//ButtonRenderer.DrawButton( e.Graphics, bounds, PushButtonState.Normal );
//base.OnPaint(pevent);
}
protected override void OnPaintBackground( PaintEventArgs e )
{
// Do nothing
}
}
At this point, assuming this design is appropriate, I need to know how to call SetClientSizeCore() appropriately. Calling it in the constructor raises an exception. I assume this is because the control hasn't had a chance to initialize yet. I'm not sure what function to override that will allow me to change the size of my button to fit the image after it has been initialized by .NET. Any ideas on this?
In the constructor, BackgroundImage is null.
You need to set the size when BackgroundImage is changed by overriding the property.
You should also shadow the Size property and add [DesignerSerializationVisibilty(DesignerSerializationVisibility.Hidden)] to prevent the size from being saved by the designer.
Wait until the BackgroundImage property is assigned so you'll know what size you need. Override the property like this:
public override Image BackgroundImage {
get { return base.BackgroundImage; }
set {
base.BackgroundImage = value;
if (value != null) this.Size = value.Size;
}
}
If you want to use ImageButtons, I'd recommend using BunifuUI as it has ImageButtons.
If you don't want to use BunifuUI, you can use a PictureBox as it also has a click event. Example:
private void pictureBox1_Click(object Sender, EventArgs e) {
webBrowser1.Navigate("https://www.google.com");
}