How can I make default fontstyle be one that the font likes? - c#

I have a small app that get a list of all the windows fonts. I can then choose one and display all its characters. All worked till I then found I had a problem, not all fonts have FontStyle:Regular. No problem I could do a check but this is where I run into a problem, when I start the system seems to have FontStyle:Regular as its default and I cannot change it so if I run the code below with text "Aharoni" selected in my combobox it falls over telling me that regular is not supported. How can I make it ignore the style or force the style to be one it uses like bold?
var cvt = new FontConverter();
Font fname = cvt.ConvertFromString(cmbobx_fontname.Text) as Font;
If I cannot do this then is it possible to get the styles that the choosen font will support?

The FontFamily class has a method to check if a style is available for the font - so rather than try to create a Font directly, first create a FontFamily instance & interate through the styles till you find one that is supported e.g.
FontFamily fontf = new FontFamily("Aharoni");
System.Drawing.FontStyle fs = System.Drawing.FontStyle.Regular;
System.Drawing.Font font;
if (fontf.IsStyleAvailable(System.Drawing.FontStyle.Regular))
fs = System.Drawing.FontStyle.Regular;
else if (fontf.IsStyleAvailable(System.Drawing.FontStyle.Bold))
fs = System.Drawing.FontStyle.Bold;
else if (fontf.IsStyleAvailable(System.Drawing.FontStyle.Italic))
fs = System.Drawing.FontStyle.Italic;
else if (fontf.IsStyleAvailable(System.Drawing.FontStyle.Strikeout))
fs = System.Drawing.FontStyle.Strikeout;
else if (fontf.IsStyleAvailable(System.Drawing.FontStyle.Underline))
fs = System.Drawing.FontStyle.Underline;
else
throw new Exception("No Font Styles Available");
font = new System.Drawing.Font(fontf, 10, fs);
You could iterate through the FontStyle enum - rather than use if/else as I have done.

Related

Embedded resource font in C# does not work correctly

I embedded a .ttf font file ("Amatic Bold", specifically) in my resources and I'm using this code below to get the Font.
I tried the code fom this post: How do I Embed a font with my C# application? (using Visual Studio 2005)
This is my implementation:
static public Font GetCustomFont (byte[] fontData, float size, FontStyle style)
{
if (_fontCollection == null) _fontCollection = new PrivateFontCollection();
IntPtr fontPtr = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(fontData.Length);
System.Runtime.InteropServices.Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
_fontCollection.AddMemoryFont(fontPtr, fontData.Length);
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(fontPtr);
return new Font(_fontCollection.Families[0], size, style);
}
Im using it like that:
Font font = GetCustomFont(Properties.MainResources.Amatic_Bold, 25, System.Drawing.FontStyle.Bold);
The font should look like:
The problem is the font is loading but not correctly showing when used; it looks like an "Arial" or other standard font instead of what it should be.
If I install the font in Windows, it works (I suppose is obvious...)
I searched for an existing answer but could'nt find my exact problem...
Any help will be appreciated.
Thanks in advance.
Well, then... I think I got it!
I'll explain what I've "discovered" (whether it can be obvious or not):
First: Application.SetCompatibleTextRenderingDefault must be set to true for Memory fonts to be rendered in the controls.
(Also Control.UseCompatibleTextRendering can be used)
It's perfectly specified in Microsoft documentation but I've missed that :-(
Second: PrivateFontCollection.Families return an array of added fonts, but.. Surprise! It's alphabetically ordered!
No matter what's the order you add the fonts or the method you use (AddMemoryFont/AddFontFile), you'll get it alphabetically ordered!
So if you're adding more than one font and then trying to get the last font you've added, you'll probably getting the wrong one.
Third: I've also tried doing FreeCoTaskMem() after adding the font in the collection or doing it on form closing. Both were working for me!
I don't know the exact implications of this...
This is my final code:
//This list is used to properly dispose PrivateFontCollection after usage
static private List<PrivateFontCollection> _fontCollections;
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(true); //Mandatory in order to have Memory fonts rendered in the controls.
//Dispose all used PrivateFontCollections when exiting
Application.ApplicationExit += delegate {
if (_fontCollections != null) {
foreach (var fc in _fontCollections) if (fc != null) fc.Dispose();
_fontCollections = null;
}
};
Application.Run(new frmMain());
}
void frmMain_Load(object sender, EventArgs e)
{
Font font1 = GetCustomFont(Properties.Resources.Amatic_Bold, 25, FontStyle.Bold);
//or...
Font font1 = GetCustomFont("Amatic-Bold.ttf", 25, FontStyle.Bold);
labelTestFont1.Font = font1;
Font font2 = GetCustomFont(Properties.Resources.<font_resource>, 25, FontStyle.Bold);
//or...
Font font2 = GetCustomFont("<font_filename>", 25, FontStyle.Bold);
labelTestFont2.Font = font2;
//...
}
static public Font GetCustomFont (byte[] fontData, float size, FontStyle style)
{
if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>();
PrivateFontCollection fontCol = new PrivateFontCollection();
IntPtr fontPtr = Marshal.AllocCoTaskMem(fontData.Length);
Marshal.Copy(fontData, 0, fontPtr, fontData.Length);
fontCol.AddMemoryFont(fontPtr, fontData.Length);
Marshal.FreeCoTaskMem(fontPtr); //<-- It works!
_fontCollections.Add (fontCol);
return new Font(fontCol.Families[0], size, style);
}
static public Font GetCustomFont (string fontFile, float size, FontStyle style)
{
if (_fontCollections == null) _fontCollections = new List<PrivateFontCollection>();
PrivateFontCollection fontCol = new PrivateFontCollection();
fontCol.AddFontFile (fontFile);
_fontCollections.Add (fontCol);
return new Font(fontCol.Families[0], size, style);
}
As you can see, I've decided to create an exclusive PrivateFontCollection for each font, then store it to a List for a final disposal on application end.
This was tested in 3 different PC's (both with Windows 7, 32 and 64 bits) and 3 different .ttf fonts.
An example of the result:
I don't know if my approach is good enough, but I expect it could be useful for others!
One more detail:
Unlike what I expected, AddMemoryFont is slower then AddFontFile (21ms vs. 15 ms)
Again, thanks to all comments!
The problem might be since fontfamily exact font needs to be specified while using a fontfile, compiler switches to default font.
You can get the basic idea from the following two methods on what you are missing.
var fontFile = new FontFamily("pack://application:,,,/Resources/#YourFont");
var typeface = new Typeface(new FontFamily(new Uri("pack://application:,,,/"), "/Resources/#YourFont"), FontStyles.Normal, FontWeights.Regular, FontStretches.Normal);
var cultureinfo = new CultureInfo("en-us");
var ft = new FormattedText("YourText", cultureinfo, FlowDirection.LeftToRight,
typeface, 28, Brushes.White)
dc.DrawText(ft, new Point(0,0));
Install font on client system by using resource path.
PrivateFontCollection yourfont = new PrivateFontCollection();
yourfont.AddFontFile("Your font Path");
label1.Font = new Font(yourfont.Families[0], 16, FontStyle.Regular);

Assigning the same font to multiple controls C#

What is the best practice for disposing of Font objects in C# used in several different controls?
As an example, I have several text boxes, labels, and buttons to which I want to assign the same font.
I thought of using the following code:
using (Font f = new Font("Calibri", 10.0f))
{
textbox1.Font = f;
textbox2.Font = f;
label1.Font = f;
button1.Font = f;
}
The problem is that after using f once I can't use it again and I have to declare a new Font object.
What is the best practice for these situations? Should I use the following code?
Font f;
f = new Font(...);
textbox1.Font = f;
f.Dispose();
f = new Font(...);
textbox1.Font = f;
...
Thanks for the help.
Why you're disposing your font just after its creation? You still need it (Dispose() should be called when you won't use it any more). You can use code from both examples, they're OK when removing Dispose() and using:
Font f = new Font("Calibri", 10.0f);
textbox1.Font = f;
textbox2.Font = f;
label1.Font = f;
button1.Font = f;
Or (it's slightly less efficient because you allocate more unneeded resources unless Font constructor manages a kind of cache, I'm not sure about it):
textbox1.Font = new Font("Calibri", 10.0f);
textbox2.Font = new Font("Calibri", 10.0f);
label1.Font = new Font("Calibri", 10.0f);
button1.Font = new Font("Calibri", 10.0f);
EDIT
Little note about resource disposing: of course you should always dispose a resource each time it's possible (simple rule is to always call Dispose() for classes that implements IDisposable). That said you have to do it after you used it, not before. Let's see this code:
var font = font;
textbox1.Font = font;
font.Dispose();
Of course it won't work because textbox1 has a reference to a disposed object (I don't know what will happen, an ObjectDisposedException? Just ignored?). Dispose() should be called only when you won't use that resource again in future and it's not the case because it'll be used by textbox1 to draw its text. A proper use, for example is:
using (var font = new Font("Calibri", 10.0f))
{
e.Graphics.DrawText(Text, font, Brushes.Black, ClientRectangle);
}
In this case font is used only by code inside using statement and it can be properly and safely disposed (even if in this case you'd better to avoid to create it each time and you should reuse it).
When the Font property of a control is set, the control will make note of the characteristics of the assigned font, and then generate a new Font object for its own use based upon that. Reading the Font property will return a reference to the object that was used to set it, but that is the only use to which the passed-in object will be put once the control observes its characteristics. Calling Dispose on a Font will prevent it from being used for drawing, but will not prevent controls from observing its characteristics and making their own (usable) Font object based upon them. Indeed, one may assign a font to a control even after calling Dispose on it.
Arguably, what this indicates is that the Font property of a control should have been a different type from the IDisposable font which can be used directly for drawing, but since the Framework is what it is, it's best to simply recognize that the Font property of a control really works with "font characteristics" rather than with a Font object.

Font does not support style 'Regular' - using Semibold fonts in C#

I have a TrueType font, which is "Semibold". I try to use that in the following method:
private FontFamily GetFontFamily(string name)
{
PrivateFontCollection pfc = new PrivateFontCollection();
var path = Server.MapPath("~/Static/webfont/" + name + ".ttf");
pfc.AddFontFile(path);
return pfc.Families[0];
}
private Font GetFont(string name, int size,FontStyle style)
{
return new Font(GetFontFamily(name), size, style);
}
Where I provide a name of my font, and it finds the Sentinel-SemiboldItalic.ttf font. As a FontStyle, I have tried to provide any of the options in the .NET framework (regulary, bold, italic, underline and strikeout).
No matter what, I get the following error:
Font 'Sentinel Semibold' does not support style 'Regular'.
What should I do? How to use a semibold font as a font in C#? Also, can I somehow convert my TrueType font to a regular one (if that would fix the issue) ?
As you can read in the answer to this question, each font has its own properties (for example: enabling a Regular Style or not), as provided by the font creator.
By looking at your font (even just by looking at its name), it seems clear that it is a sub-type whose defining characteristics are precisely being (semi-)bold and italic; consequently, it does sound logical to not have the option to remove these features. If you want a non-bold, non-italic version, you should rely on the parent family (Sentinel).
I too faced the same issue like you. And found that even though we are adding the font[.ttf] file, the incorrect font is getting added in privatefontcollection. Hence i found the workaround for this case. This issue will be thrown randomly. So add the font till correct font is added in private font collection.
private FontFamily GetFontFamily(string name)
{
PrivateFontCollection pfc = new PrivateFontCollection();
var path = Server.MapPath("~/Static/webfont/" + name + ".ttf");
pfc.AddFontFile(path);
**while (pfc.FontFamilies != null && pfc.Families.Length > 0 && (pfc.FontFamilies[0] as FontFamily).Name != "YourFontName")
{
pfc.Dispose();
pfc = new PrivateFontCollection();
GetFontFamily();
}
return pfc.Families[0];
}

Change default font dialog in c#

Can anyone tell me how can set default Font Name , Font Size , Font Color.. of FontDialog;
FontDialog dlg = new FontDialog();
dlg.ShowColor = true;
if (dlg.ShowDialog() != DialogResult.OK) return;
The dlg.ShowDialog() ; method should show Font name that I choose insted of "microsoft san serif"
You just need to set the Font property before calling ShowDialog.
For example:
dlg.Font = new Font("Consolas", 10);
//or
dlg.Font = myCurrentlySelectedFont;
It's also worth pointing out that when getting the font name from the font dialog, you want the value: fontDlg.Font.Name, or fontDlg.Font.FontFamily.Name.
This value will correctly allow you to set the font name as above before showing the dialogue.

C# Winforms bold treeview node doesn't show whole text

I'm using the following code to make my treenodes bold:
Font font = new Font(tvQuestionSequence.Font, FontStyle.Bold);
foreach (QuestionnaireBuilder_Category cat in categories)
{
TreeNode node = new TreeNode();
node.Text = cat.Description;
node.Name = cat.Id.ToString();
node.NodeFont = font;
tvQuestionSequence.Nodes.Add(node);
}
But the text of the bold nodes is not displayed correctly. The last letter(s) are not shown. How come? And how to solve this problem?
I found this Post when searching through the web because I am facing the exact same problem.
However, appending a white space to the end of the node was not an option, and I found an alternative way that seems to fix the issue.
After setting my node font Bold, all I need to do is reset the node text with the same value.
Here is the Code Sample:
Font boldFont = new Font(treeview.Font, FontStyle.Bold);
node.NodeFont = boldFont;
node.Text = node.Text;
It seems that the node is redrawn after changing the text, which is exactly what I wanted in the first place.
I've found that this is a Windows issue. A workaround for this problem is this:
In the form constructor set the font of the treeview to bold. When adding nodes which must not be bold, change the font to regular:
// Constructor of your form
public Form()
{
InitializeComponent();
Font font = new Font(tvQuestionSequence.Font, FontStyle.Bold);
tvQuestionSequence.Font = font;
}
// Add regular nodes (not bold)
Font font = new Font(tvQuestionSequence.Font, FontStyle.Regular);
TreeNode treeNode = new TreeNode();
treeNode.Text = "Foo";
treeNode.NodeFont = font;
TreeNode parent = tvQuestionSequence.Nodes.Find("parent", true);
parent.Nodes.Add(treeNode);
Simply use treeView.BeginUpdate() before you bold the node then treeView.EndUpdate() after you've bolded the node.
This is a known Windows bug.
The simple solution is just to append an extra space character at the end of your strings. The space character will not be visible, but it will increase the number of pixels needed to draw the string, so the entire string will be visible.
This is all not helping for me.
What DID the trick is making the font a little bigger and bold at DESIGN time.
(In the Properties window)
So make sure you define the treeview with big enough font, then later you can add nodes with smaller font. They will fit.
I do agree with the solution provided. I just want to add to it to shed a little more light on what the problem is.
The treeview has its own font which determines the width of items at the root level. That compensates for the fact that there is only an item height property available and no item width property.
The solution to your problem is to determine what the font of your root node should be, then set the tree to that same font. You can do that at design time also.
Hope that helps someone.
A workaround for this problem is this:
Set the defaul font of treeview to bold in the properties.
And chnage to not bold when you need.
I do the following, I set the DrawNode Event to call, it sets the node to bold and removes the highlighted colour.
You can set any colour you like using the first parameter of the e.Graphics.FillRectangle function.
private void SetNodeBoldWhenSelected(object sender, DrawTreeNodeEventArgs e)
{
if (e.Node == null) return;
var font = e.Node.NodeFont ?? e.Node.TreeView.Font;
if (e.Node.IsSelected)
{
font = new Font(font, FontStyle.Bold);
}
var bounds = new Rectangle( e.Bounds.X,e.Bounds.Y,e.Bounds.Width+20,e.Bounds.Height);
e.Graphics.FillRectangle(SystemBrushes.ControlDarkDark, bounds);
TextRenderer.DrawText(e.Graphics, e.Node.Text, font, bounds, SystemColors.HighlightText, TextFormatFlags.GlyphOverhangPadding);
}
Now when I select a node I get 20 pixels more space, for my font, this works well, one can calculate the "real" size needed but there is no specification stating it needs to do this but you can use Graphics.MeasureString if you feel you need to do that.
Very easy and works fine
treeView1.SelectedNode.NodeFont = new System.Drawing.Font(treeView1.SelectedNode.TreeView.Font, treeView1.SelectedNode.TreeView.Font.Style | FontStyle.Bold);
this.treeView1.SelectedNode.Text += string.Empty;
I realize this is an old thread and it may have been answered. I just ran across this problem as I'm learning to use TreeViews. What worked for me was changing the font size for the entire TreeView to the same size, or bigger than the font of the level you want to bold. The default font size is 8.something. I changed mine to 10, which was the size I wanted my nodes, and the truncating was gone.
What worked for me: Hooking into the load event in the Control's constructor and tweaking the node as explained in BlunT's answer.
public MyControl()
{
InitializeComponent();
_head = new TreeNode();
this.Load += (s, e) =>
{
trvParts.Nodes.Clear();
_head.NodeFont = new Font(trvParts.Font, FontStyle.Bold);
trvParts.Nodes.Add(_head);
_head.Text = "Node Name";
};
}
It's in vb.Net however the solution to re-enter the value of the TEXT field gets around this nicely. As in:
With myNode
Dim myText As String = .Text 'capture the text
.NodeFont = New Font(<name of your treeview>.Font, FontStyle.Bold)
.Text = myText 'reset the text to the original value
End With
Based on MSDN Library, try change your code to:
Font font = new Font(tvQuestionSequence.Font, FontStyle.Bold);
foreach (QuestionnaireBuilder_Category cat in categories)
{
TreeNode node = new TreeNode();
node.Text = cat.Description;
node.Name = cat.Id.ToString();
node.NodeFont = font;
tvQuestionSequence.BeginUpdate(); //added newline here <--
tvQuestionSequence.Nodes.Add(node);
tvQuestionSequence.EndUpdate(); //added newline here <--
}
It work for me

Categories

Resources