I am using windows progressbar in winform. It's minimum value is 20 and maximumm value is 120. I have to set threshold in the progressbar for value=60 such that if value remains below 60 then progressbar colour will be red else if value is more than 60 then progress bar colour should be green.
And the most important thing is that I want to show this threshold value as a line in progessbar that should be visible whatever may be the colour of progressbar green or red.
Does anybody have idea?? Your help will be appreciated.
You can try this (However you won't get animation).
It a modified version of this answer with Threshold features added.
public class NewProgressBar : ProgressBar
{
//This property takes the Threshold.
public int Threshold{ get; set; }
public NewProgressBar()
{
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
Rectangle rec = e.ClipRectangle;
rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;
if(ProgressBarRenderer.IsSupported)
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
rec.Height = rec.Height - 4;
//Check value is greater that Threshold
if(this.Value > Threshold)
{
e.Graphics.FillRectangle(Brushes.Green, 2, 2, rec.Width, rec.Height);
}
else
{
e.Graphics.FillRectangle(Brushes.Red, 2, 2, rec.Width, rec.Height);
}
//This line should do that
e.Graphics.DrawLine(Pens.Black,Threshold-1,2,Threshold-1,rec.Height);
}
}
Now you can use it like this:
NewProgressBar p = new NewProgressBar();
//Set properties
//Set threshold
p.Threshold = 60;
With the default ProgressBar implementation, you will not be able to completely achieve what you want.You would need to create a custom control.
If you are interested in changing the color only, you can achieve that by changing the ForeColor property when the percentage value changes.
Related
I have a TextBlock with a fixed size thats wrapping text. sometimes short sometimes long.
If the text is getting to long it isnt displayed entirely like this
How can i make the Fontsize flexible to make the text fit the TextBox with static size?
My solution is the following:
Set the fontsize to a value, than which you don't want any bigger.
The ActualHeight of the TextBlock changes, when you change the font size or when the content is changed. I built the solution based upon this.
You should create an event handler for the SizeChanged event and write the following code to it.
private void MyTextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
double desiredHeight = 80; // Here you'll write the height you want the text to use
if (this.MyTextBlock.ActualHeight > desiredHeight)
{
// You want to know, how many times bigger the actual height is, than what you want to have.
// The reason for Math.Sqrt() is explained below in the text.
double fontsizeMultiplier = Math.Sqrt(desiredHeight / this.MyTextBlock.ActualHeight);
// Math.Floor() can be omitted in the next line if you don't want a very tall and narrow TextBox.
this.MyTextBlock.FontSize = Math.Floor(this.MyTextBlock.FontSize * fontsizeMultiplier);
}
this.MyTextBlock.Height = desiredHeight; // ActualHeight will be changed if the text is too big, after the text was resized, but in the end you want the box to be as big as the desiredHeight.
}
The reason why I used the Math.Sqrt() is that if you set the font size to half as big as before, then the area that the font will use, will be one quarter the size, then before (because it became half as wide and half as tall as before). And you obviously want to keep the width of the TextBox and only change the height of it.
If you were lucky, the font size will be appropriate after this method gets executed once. However, depending on the text that gets re-wrapped after the font size change, you might be so "unlucky", that the text will be one line longer than you would want it to be.
Luckily the event handler will be called again (because you changed the font size) and the resizing will be done again if it is still too big.
I tried it, it was fast and the results looked good.
However, I can imagine, that in a really unlucky choice of text and height, the correct font size would be reached after several iterations. This is why I used Math.Floor(). All in all, it doesn't matter much if the font size is in the end 12.34 or 12 and this way I wouldn't be concerned about an "unlucky" text, which will take too long to render.
But I think Math.Floor() can be omitted if you don't want to have a really tall text box (like 2000 pixels) with a lot of text.
Here's a full solution including an option to set maxheight / maxwidth and and it is calculated straight on render:
public class TextBlockAutoShrink : TextBlock
{
private double _defaultMargin = 6;
private Typeface _typeface;
static TextBlockAutoShrink()
{
TextBlock.TextProperty.OverrideMetadata(typeof(TextBlockAutoShrink), new FrameworkPropertyMetadata(new PropertyChangedCallback(TextPropertyChanged)));
}
public TextBlockAutoShrink() : base()
{
_typeface = new Typeface(this.FontFamily, this.FontStyle, this.FontWeight, this.FontStretch, this.FontFamily);
base.DataContextChanged += new DependencyPropertyChangedEventHandler(TextBlockAutoShrink_DataContextChanged);
}
private static void TextPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
var t = sender as TextBlockAutoShrink;
if (t != null)
{
t.FitSize();
}
}
void TextBlockAutoShrink_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
FitSize();
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
FitSize();
base.OnRenderSizeChanged(sizeInfo);
}
private void FitSize()
{
FrameworkElement parent = this.Parent as FrameworkElement;
if (parent != null)
{
var targetWidthSize = this.FontSize;
var targetHeightSize = this.FontSize;
var maxWidth = double.IsInfinity(this.MaxWidth) ? parent.ActualWidth : this.MaxWidth;
var maxHeight = double.IsInfinity(this.MaxHeight) ? parent.ActualHeight : this.MaxHeight;
if (this.ActualWidth > maxWidth)
{
targetWidthSize = (double)(this.FontSize * (maxWidth / (this.ActualWidth + _defaultMargin)));
}
if (this.ActualHeight > maxHeight)
{
var ratio = maxHeight / (this.ActualHeight);
// Normalize due to Height miscalculation. We do it step by step repeatedly until the requested height is reached. Once the fontsize is changed, this event is re-raised
// And the ActualHeight is lowered a bit more until it doesnt enter the enclosing If block.
ratio = (1 - ratio > 0.04) ? Math.Sqrt(ratio) : ratio;
targetHeightSize = (double)(this.FontSize * ratio);
}
this.FontSize = Math.Min(targetWidthSize, targetHeightSize);
}
}
}
Is there a way I can set Font Height in Steema Teechart Graphics 3D?
The Closest I could find was tchart.graphics3d.fontheight , but it gets the font height , does not set it,
so is there a way I can set the font height?
Thank you so much
You cannot change only the FontHeight, because you are only allowed get the FontHeight or FontWidth to consult their values. Therefore, if you want change the size (height and width) of font you must assign a value to font size as do in next lines of code:
public Form1()
{
InitializeComponent();
InitializeChart();
}
private void InitializeChart()
{
tChart1.AfterDraw += new PaintChartEventHandler(tChart1_AfterDraw);
}
void tChart1_AfterDraw(object sender, Steema.TeeChart.Drawing.Graphics3D g)
{
g.Font.Size = 25;
g.TextOut(100, 150, "TeeChartFor.Net");
}
I hope will helps.
Thanks,
The Chart of TeeChart to default have a gradient in its background. If you want change the color, previously you must disable the gradient of backround. You can do something as next lines of code:
private void InitializeChart()
{
tChart1.Panel.Gradient.Visible = false;
tChart1.Panel.Color = Color.Aqua;
}
I hope will helps.
Thanks,
I am having difficulties to understand why I can change the brush color but can't change the brush radius in a SurfaceInkCanvas.
Here is what I do:
Double newSize = Math.Round(BrushRadiusSlider.Value,0);
drawingAttributes = new System.Windows.Ink.DrawingAttributes();
// Works :
drawingAttributes.Color = Colors.Yellow;
// Does not work :
drawingAttributes.Width = newSize;
drawingAttributes.Height = newSize;
canvas.DefaultDrawingAttributes = drawingAttributes;
For information, BrushRadiusSlider is a slider in the XAML and gives values between 1 and 100.
See here:
SurfaceInkCanvas.DefaultDrawingAttributes Property
You probably forgot to set the UsesTouchShape to false
The issue is I think that the brush is not updating when the slider's value is changed. Your code above takes the value of the slider at one moment in time, and sets the width and height to that, but it is not linked to the slider.
To get it to update when the slider changes you would need to handle the SliderValueChanged event and reset the drawingAttributes then.
XAML:
<Slider x:Name="BrushRadiusSlider" Minimum="1" Maximum="100" Value="1" ValueChanged="SliderValueChanged"/>
Code:
private void SliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (canvas != null)
{
var drawingAttributes = canvas.DefaultDrawingAttributes;
Double newSize = Math.Round(BrushRadiusSlider.Value, 0);
drawingAttributes.Width = newSize;
drawingAttributes.Height = newSize;
}
}
I am trying to evenly space dynamically created controls by giving them a width and height that is a fraction of the width and height of the container control.
However, although my functions calculating the dimensions are correct, for some reason the assignment to the Width property is being stubbornly refused. The WidthToUse() function is returning 19, yet when an attempt is made to assign that vaue to the dynamically created TextBox, it remains at...630! Why 630 to begin with, and why does it refuse to be assigned to?
Even the height, although "working" doesn't work quite right - there are too many controls or not enough space on the panel to accommodate all of the controls using this math.
Here's my code:
int WidthToUse = getTextBoxWidthToUse(tableLayoutPanelGreatGooglyMoogly.Width);
int HeightToUse = getControlHeightToUse(tableLayoutPanelGreatGooglyMoogly.Height);
TextBox txtbx = new TextBox();
txtbx.Parent = tableLayoutPanelGreatGooglyMoogly;
txtbx.Margin = new Padding();
txtbx.Dock = DockStyle.Fill;
txtbx.AutoSize = false;
txtbx.Width = WidthToUse; // WidthToUse is 19, but txtbx.Width is 630 both before AND after this assignment!
txtbx.Height = HeightToUse; // HeightToUse is 27
private static int getControlHeightToUse(int theDynPanelHeight) {
return (theDynPanelHeight / NUMBER_OF_ROWS);
}
private static int getTextBoxWidthToUse(int theDynPanelWidth) {
return (theDynPanelWidth / 32);
}
private static int getLabelWidthToUse(int theDynPanelWidth) {
return ((theDynPanelWidth / 64) * 3);
}
DockStyle.Fill is a property describing the size of a control relative to the size of it's container. A control will resize to fit all of the empty space in it's parent container with this property set.
Because you have the Dock property set to Fill would be my guess.
I need a TextBox or some type of Multi-Line Label control which will automatically adjust the font-size to make it as large as possible and yet have the entire message fit inside the bounds of the text area.
I wanted to see if anyone had implemented a user control like this before developing my own.
Example application: have a TextBox which will be half of the area on a windows form. When a message comes in which is will be approximately 100-500 characters it will put all the text in the control and set the font as large as possible. An implementation which uses Mono Supported .NET libraries would be a plus.
If know one has implemented a control already... If someone knows how to test if a given text completely fits inside the text area that would be useful for if I roll my own control.
Edit: I ended up writing an extension to RichTextBox. I will post my code shortly once i've verified that all the kinks are worked out.
I had to solve the same basic problem. The iterative solutions above were very slow. So, I modified it with the following. Same idea. Just uses calculated ratios instead of iterative. Probably, not quite as precise. But, much faster.
For my one-off need, I just threw an event handler on the label holding my text.
private void PromptLabel_TextChanged(object sender, System.EventArgs e)
{
if (PromptLabel.Text.Length == 0)
{
return;
}
float height = PromptLabel.Height * 0.99f;
float width = PromptLabel.Width * 0.99f;
PromptLabel.SuspendLayout();
Font tryFont = PromptLabel.Font;
Size tempSize = TextRenderer.MeasureText(PromptLabel.Text, tryFont);
float heightRatio = height / tempSize.Height;
float widthRatio = width / tempSize.Width;
tryFont = new Font(tryFont.FontFamily, tryFont.Size * Math.Min(widthRatio, heightRatio), tryFont.Style);
PromptLabel.Font = tryFont;
PromptLabel.ResumeLayout();
}
I haven't seen an existing control to do this, but you can do it the hard way by using a RichTextBox and the TextRenderer's MeasureText method and repeatedly resizing the font. It's inefficient, but it works.
This function is an event handler for the 'TextChanged' event on a RichTextBox.
An issue I've noticed:
When typing, the text box will scroll to the current caret even if scrollbars are disabled. This can result in the top line or left side getting chopped off until you move back up or left with the arrow keys. The size calculation is correct assuming you can get the top line to display at the top of the text box. I included some scrolling code that helps sometimes (but not always).
This code assumes word wrap is disabled. It may need modification if word wrap is enabled.
The code:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, uint wMsg, int wParam, uint lParam);
private static uint EM_LINEINDEX = 0xbb;
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
// If there's no text, return
if (richTextBox1.TextLength == 0) return;
// Get height and width, we'll be using these repeatedly
int height = richTextBox1.Height;
int width = richTextBox1.Width;
// Suspend layout while we mess with stuff
richTextBox1.SuspendLayout();
Font tryFont = richTextBox1.Font;
Size tempSize = TextRenderer.MeasureText( richTextBox1.Text, richTextBox1.Font);
// Make sure it isn't too small first
while (tempSize.Height < height || tempSize.Width < width)
{
tryFont = new Font(tryFont.FontFamily, tryFont.Size + 0.1f, tryFont.Style);
tempSize = TextRenderer.MeasureText(richTextBox1.Text, tryFont);
}
// Now make sure it isn't too big
while (tempSize.Height > height || tempSize.Width > width)
{
tryFont = new Font(tryFont.FontFamily, tryFont.Size - 0.1f, tryFont.Style);
tempSize = TextRenderer.MeasureText(richTextBox1.Text, tryFont);
}
// Swap the font
richTextBox1.Font = tryFont;
// Resume layout
richTextBox1.ResumeLayout();
// Scroll to top (hopefully)
richTextBox1.ScrollToCaret();
SendMessage(richTextBox1.Handle, EM_LINEINDEX, -1, 0);
}
The solution i came up with was to write a control which extends the standard RichTextBox control.
Use the extended control in the same way you would a regular RichTextBox control with the following enhancements:
Call the ScaleFontToFit() method after resizing or text changes.
The Horizontal Alignment field can be used to center align the text.
The Font attributes set in the designer will be used for the entire region. It is not possible to mix fonts as they will changed once the ScaleFontToFit method is called.
This control combines several techniques to determine if the text still fits within it's bounds. If the text area is multiline, it detects if scrollbars are visible. I found a clever way to detect whether or not the scrollbars are visible without requiring any winapi calls using a clever technique I found on one of Patrick Smacchia's posts.. When multiline isn't true, vertical scrollbars never appear so you need to use a different technique which relies on rendering the text using a the Graphics object. The Graphic rendering technique isn't suitable for Multiline boxes because you would have to account for word wrapping.
Here are a few snippets which shows how it works (link to source code is provided below). This code could easily be used to extend other controls.
/// <summary>
/// Sets the font size so the text is as large as possible while still fitting in the text
/// area with out any scrollbars.
/// </summary>
public void ScaleFontToFit()
{
int fontSize = 10;
const int incrementDelta = 5; // amount to increase font by each loop iter.
const int decrementDelta = 1; // amount to decrease to fine tune.
this.SuspendLayout();
// First we set the font size to the minimum. We assume at the minimum size no scrollbars will be visible.
SetFontSize(MinimumFontSize);
// Next, we increment font size until it doesn't fit (or max font size is reached).
for (fontSize = MinFontSize; fontSize < MaxFontSize; fontSize += incrementDelta)
{
SetFontSize(fontSize);
if (!DoesTextFit())
{
//Console.WriteLine("Text Doesn't fit at fontsize = " + fontSize);
break;
}
}
// Finally, we keep decreasing the font size until it fits again.
for (; fontSize > MinFontSize && !DoesTextFit(); fontSize -= decrementDelta)
{
SetFontSize(fontSize);
}
this.ResumeLayout();
}
#region Private Methods
private bool VScrollVisible
{
get
{
Rectangle clientRectangle = this.ClientRectangle;
Size size = this.Size;
return (size.Width - clientRectangle.Width) >= SystemInformation.VerticalScrollBarWidth;
}
}
/**
* returns true when the Text no longer fits in the bounds of this control without scrollbars.
*/
private bool DoesTextFit()
{
if (VScrollVisible)
{
//Console.WriteLine("#1 Vscroll is visible");
return false;
}
// Special logic to handle the single line case... When multiline is false, we cannot rely on scrollbars so alternate methods.
if (this.Multiline == false)
{
Graphics graphics = this.CreateGraphics();
Size stringSize = graphics.MeasureString(this.Text, this.SelectionFont).ToSize();
//Console.WriteLine("String Width/Height: " + stringSize.Width + " " + stringSize.Height + "form... " + this.Width + " " + this.Height);
if (stringSize.Width > this.Width)
{
//Console.WriteLine("#2 Text Width is too big");
return false;
}
if (stringSize.Height > this.Height)
{
//Console.WriteLine("#3 Text Height is too big");
return false;
}
if (this.Lines.Length > 1)
{
//Console.WriteLine("#4 " + this.Lines[0] + " (2): " + this.Lines[1]); // I believe this condition could be removed.
return false;
}
}
return true;
}
private void SetFontSize(int pFontSize)
{
SetFontSize((float)pFontSize);
}
private void SetFontSize(float pFontSize)
{
this.SelectAll();
this.SelectionFont = new Font(this.SelectionFont.FontFamily, pFontSize, this.SelectionFont.Style);
this.SelectionAlignment = HorizontalAlignment;
this.Select(0, 0);
}
#endregion
ScaleFontToFit could be optimized to improve performance but I kept it simple so it'd be easy to understand.
Download the latest source code here. I am still actively working on the project which I developed this control for so it's likely i'll be adding a few other features and enhancements in the near future. So, check the site for the latest code.
My goal is to make this control work on Mac using the Mono framework.
I had a similar requirement for a text box in a panel on a windows form hosted window. (I injected the panel onto the existing form). When the size of the panel changes (in my case) the text would resize to fit the box. Code
parentObject.SizeChanged += (sender, args) =>
{
if (textBox1.Text.Length > 0)
{
int maxSize = 100;
// Make a Graphics object to measure the text.
using (Graphics gr = textBox1.CreateGraphics())
{
for (int i = 1; i <= maxSize; i++)
{
using (var test_font = new Font(textBox1.Font.FontFamily, i))
{
// See how much space the text would
// need, specifying a maximum width.
SizeF text_size =
TextRenderer.MeasureText(
textBox1.Text,
test_font,
new Size(textBox1.Width, int.MaxValue),
TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl);
try
{
if (text_size.Height > textBox1.Height)
{
maxSize = i - 1;
break;
}
}
catch (System.ComponentModel.Win32Exception)
{
// this sometimes throws a "failure to create window handle" error.
// This might happen if the TextBox is invisible and/or
// too small to display a toolbar.
// do whatever here, add/delete, whatever, maybe set to default font size?
maxSize = (int) textBox1.Font.Size;
}
}
}
}
// Use that font size.
textBox1.Font = new Font(textBox1.Font.FontFamily, maxSize);
}
};