I try to list all available fonts in ComboBox, but with font names printed in a given font family. It works, but it also crashes from time to time, with message "Out of memory", when I move mouse over opened ComboBox. Without changing fonts, it doesn't crash. Why the message occurs? And what to do to make it works?
Code:
private void tbrFontNameComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
if (e.Index >= 0)
{
Graphics g = e.Graphics;
Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) ?
new SolidBrush(Color.Blue) : new SolidBrush(e.BackColor);
Brush tBrush = new SolidBrush(e.ForeColor);
g.FillRectangle(brush, e.Bounds);
Font font = new Font(tbrFontName.Items[e.Index].ToString(), 10);
e.Graphics.DrawString(tbrFontName.Items[e.Index].ToString(), font,
tBrush, e.Bounds, StringFormat.GenericDefault);
brush.Dispose();
tBrush.Dispose();
font.Dispose();
}
e.DrawFocusRectangle();
}
Related
I have a problem with the font of the TabControl.
I set the Alignment to Left, and use following code to set the font:
private void tabControl1_DrawItem(Object sender, System.Windows.Forms.DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _textBrush;
// Get the item from the collection.
TabPage _tabPage = tabControl1.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _tabBounds = tabControl1.GetTabRect(e.Index);
if (e.State == DrawItemState.Selected) {
// Draw a different background color, and don't paint a focus rectangle.
_textBrush = new SolidBrush(Color.Black);
g.FillRectangle(Brushes.LightSkyBlue, e.Bounds);
}
else {
_textBrush = new System.Drawing.SolidBrush(e.ForeColor);
e.DrawBackground();
}
// Use our own font.
Font _tabFont = new Font("Calibri", (float)11.0, FontStyle.Regular, GraphicsUnit.Pixel);
// Draw string. Left the text.
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Near;
_stringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}
I set the font to "Calibri", (float)11.0, but the text in the tabcontrol are smaller. Please refer to the following:
Font Error
What should I do to set the correct font?
Really appreciate your help!
Eric
I am using a ComboBox in Text and DropDown mode (the default) and I want to have an ItemHeight of X (e.g. 40) but have the ComboBox's Height set to Y (e.g. 20).
The reason for this is that I am intending to use the ComboBox for a Quick Search feature in which the user keys in text and detailed results are rendered in the list items. Only one line of input is required.
Unfortunately, Winforms automatically locks the ComboBox's Height to the ItemHeight and I can see no way to change this.
How can I make the ComboBox's Height differ to the ItemHeight?
What you have to do is, first of all, change DrawMode from Normal to OwnerDrawVariable. Then you've got to handle 2 events: DrawItem and MeasureItem . They would be something like:
private void comboBox1_MeasureItem(object sender, MeasureItemEventArgs e)
{
e.ItemHeight = 40; //Change this to your desired item height
}
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
ComboBox box = sender as ComboBox;
if (Object.ReferenceEquals(null, box))
return;
e.DrawBackground();
if (e.Index >= 0)
{
Graphics g = e.Graphics;
using (Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
? new SolidBrush(SystemColors.Highlight)
: new SolidBrush(e.BackColor))
{
using (Brush textBrush = new SolidBrush(e.ForeColor))
{
g.FillRectangle(brush, e.Bounds);
g.DrawString(box.Items[e.Index].ToString(),
e.Font,
textBrush,
e.Bounds,
StringFormat.GenericDefault);
}
}
}
e.DrawFocusRectangle();
}
I'm receiving an unhandled exception when executing a .net application:
InvalidArgument=Value of '-1' is not valid for 'index'.
Parameter name: index
The code itself is used to change a selected item's background color in a listbox (winforms):
private void listbox_DrawItem(object sender, DrawItemEventArgs e)
{
Brush bg = new SolidBrush(Color.FromArgb(100, 100, 100));
e.DrawBackground();
Graphics g = e.Graphics;
Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) ? bg : new SolidBrush(e.BackColor);
g.FillRectangle(brush, e.Bounds);
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds, StringFormat.GenericDefault);
e.DrawFocusRectangle();
}
The exception indicates that it is the Brush brush = ... line, but I don't understand why it's throwing this exception.
Before using e.Index check it's value
if(e.Index >= 0)
{
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds, StringFormat.GenericDefault);
}
If you have received this exception, then you might want to consider being defensive before the block of code by adding a check to see that the index is greater than 0.
if (!e.Index < 0)
{
e.DrawBackground();
Graphics g = e.Graphics;
Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) ? bg : new SolidBrush(e.BackColor);
g.FillRectangle(brush, e.Bounds);
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(), e.Font, new SolidBrush(e.ForeColor), e.Bounds, StringFormat.GenericDefault);
e.DrawFocusRectangle();
}
By doing this you will only execute the code when the event is raised from the source with valid arguments.
Actually, I think it's indicating this line:
... (ListBox)sender).Items[e.Index] ...
It seems to be trying to get the -1 element in the ListBox.
To confirm it, place a breakpoint on that line and see if e.Index == -1.
I have a TreeView and each of it's Node.Text has two words.
The first and second words should have different colors. I'm already changing the color of the text with the DrawMode properties and the DrawNode event but I can't figure out how to split the Node.Text in two different colors. Someone pointed out I could use TextRenderer.MeasureText but I have no idead how/where to use it.
Someone has an idea ?
Code :
formload()
{
treeView1.DrawMode = TreeViewDrawMode.OwnerDrawText;
}
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
Color nodeColor = Color.Red;
if ((e.State & TreeNodeStates.Selected) != 0)
nodeColor = SystemColors.HighlightText;
TextRenderer.DrawText(e.Graphics,
e.Node.Text,
e.Node.NodeFont,
e.Bounds,
nodeColor,
Color.Empty,
TextFormatFlags.VerticalCenter);
}
Try this:
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
string[] texts = e.Node.Text.Split();
using (Font font = new Font(this.Font, FontStyle.Regular))
{
using (Brush brush = new SolidBrush(Color.Red))
{
e.Graphics.DrawString(texts[0], font, brush, e.Bounds.Left, e.Bounds.Top);
}
using (Brush brush = new SolidBrush(Color.Blue))
{
SizeF s = e.Graphics.MeasureString(texts[0], font);
e.Graphics.DrawString(texts[1], font, brush, e.Bounds.Left + (int)s.Width, e.Bounds.Top);
}
}
}
You must manage State of node to do appropriated actions.
UPDATE
Sorry, my mistake see updated version. There is no necessary to measure space size because it already contains in texts[0].
How can I set the background color of a specific item in a System.Windows.Forms.ListBox?
I would like to be able to set multiple ones if possible.
Thanks for the answer by Grad van Horck. It guided me in the correct direction.
To support text (not just background color), here is my fully working code:
//global brushes with ordinary/selected colors
private SolidBrush reportsForegroundBrushSelected = new SolidBrush(Color.White);
private SolidBrush reportsForegroundBrush = new SolidBrush(Color.Black);
private SolidBrush reportsBackgroundBrushSelected = new SolidBrush(Color.FromKnownColor(KnownColor.Highlight));
private SolidBrush reportsBackgroundBrush1 = new SolidBrush(Color.White);
private SolidBrush reportsBackgroundBrush2 = new SolidBrush(Color.Gray);
//custom method to draw the items, don't forget to set DrawMode of the ListBox to OwnerDrawFixed
private void lbReports_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
bool selected = ((e.State & DrawItemState.Selected) == DrawItemState.Selected);
int index = e.Index;
if (index >= 0 && index < lbReports.Items.Count)
{
string text = lbReports.Items[index].ToString();
Graphics g = e.Graphics;
//background:
SolidBrush backgroundBrush;
if (selected)
backgroundBrush = reportsBackgroundBrushSelected;
else if ((index % 2) == 0)
backgroundBrush = reportsBackgroundBrush1;
else
backgroundBrush = reportsBackgroundBrush2;
g.FillRectangle(backgroundBrush, e.Bounds);
//text:
SolidBrush foregroundBrush = (selected) ? reportsForegroundBrushSelected : reportsForegroundBrush;
g.DrawString(text, e.Font, foregroundBrush, lbReports.GetItemRectangle(index).Location);
}
e.DrawFocusRectangle();
}
The above adds to the given code and will show the proper text plus highlight the selected item.
Probably the only way to accomplish that is to draw the items yourself.
Set the DrawMode to OwnerDrawFixed and code something like this on the DrawItem event:
private void listBox_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
Graphics g = e.Graphics;
g.FillRectangle(new SolidBrush(Color.Silver), e.Bounds);
// Print text
e.DrawFocusRectangle();
}
The second option would be using a ListView, although they have an other way of implementations (not really data bound, but more flexible in way of columns).
// Set the background to a predefined colour
MyListBox.BackColor = Color.Red;
// OR: Set parts of a color.
MyListBox.BackColor.R = 255;
MyListBox.BackColor.G = 0;
MyListBox.BackColor.B = 0;
If what you mean by setting multiple background colors is setting a different background color for each item, this isn't possible with a ListBox, but it is with a ListView, with something like:
// Set the background of the first item in the list
MyListView.Items[0].BackColor = Color.Red;
public MainForm()
{
InitializeComponent();
this.listbox1.DrawItem += new DrawItemEventHandler(this.listbox1_DrawItem);
}
private void listbox1_DrawItem(object sender, System.Windows.Forms.DrawItemEventArgs e)
{
e.DrawBackground();
Brush myBrush = Brushes.Black;
var item = listbox1.Items[e.Index];
if(e.Index % 2 == 0)
{
e.Graphics.FillRectangle(new SolidBrush(Color.Gold), e.Bounds);
}
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
e.Font, myBrush,e.Bounds, StringFormat.GenericDefault);
e.DrawFocusRectangle();
}
}