Can't centre Listview Item when using OwnerDrawn - vb.net

When trying to custom draw my coloumn headers and listview items, I was getting jagged text (not anti-aliased) which looked crappy. I came across the following code snippet to render the text and display much more nicely - which works. However, I can't work out how to centre my text in the column. Currently, setting my flags to HorizontalCentre actually centres the text within the entire listview control.
Private Sub lsvOverdueCalls_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles lsvOverdueCalls.DrawItem
If e.Item.Selected AndAlso e.Item.ListView.Focused Then
e.Item.BackColor = SystemColors.Highlight
e.Item.ForeColor = e.Item.ListView.BackColor
ElseIf e.Item.Selected AndAlso Not e.Item.ListView.Focused Then
e.Item.BackColor = SystemColors.Control
e.Item.ForeColor = e.Item.ListView.ForeColor
Else
e.Item.BackColor = e.Item.ListView.BackColor
e.Item.ForeColor = e.Item.ListView.ForeColor
End If
e.DrawBackground()
' Draw the header text.
Dim rec As New Rectangle(e.Bounds.X + 2, e.Bounds.Y + 2, e.Bounds.Width - 4, e.Bounds.Height - 4)
Dim flags As TextFormatFlags = TextFormatFlags.HorizontalCenter Or TextFormatFlags.EndEllipsis Or TextFormatFlags.ExpandTabs Or TextFormatFlags.SingleLine
TextRenderer.DrawText(e.Graphics, e.Item.Text, e.Item.ListView.Font, rec, e.Item.ForeColor, flags)
End Sub
My result is this:
I need the Call Number (26155) to sit centre of the Call ID Column.

e.Bounds is the entire width. To get the width of your column, try referencing the Width property of the ListView column.
If you gave your columns keys, reference them by key:
listView1.Columns("callID").Width
or index:
listView1.Columns(0).Width
Then your drawing rectangle would look something like this:
Dim colWidth As Integer = listView1.Columns("callID").Width
Dim rec As New Rectangle(e.Bounds.X, e.Bounds.Y, _
colWidth, e.Bounds.Height)

Related

Create a Tiff Bitmap file from a DatagridView

I want to create a Tiff file from a Datagridview. I was able to get the Datagridview to a Tiff file, however I just want the Rows and Columns and nothing else.
Is this possible without using 3rd party Tool?
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
DataGridView1.Rows.Add(New String() {"Value1", "Value2", "Value3"})
Dim height As Integer = DataGridView1.Height
DataGridView1.Height = DataGridView1.RowCount * DataGridView1.RowTemplate.Height
Dim bitmap As Bitmap = New Bitmap(Me.DataGridView1.Width - 1, Me.DataGridView1.Height - 1)
DataGridView1.DrawToBitmap(bitmap, New Rectangle(0, 0, Me.DataGridView1.Width - 1, Me.DataGridView1.Height - 1))
'Save the Bitmap to folder.
bitmap.Save("C:Development\DataGridView.Tiff")
End Sub
I dont want the Highlighted
There are a few things to consider:
The DataGridView Rows and Columns must be visible when the control is drawn to a Bitmap,
ScrollBars may be present,
The height of the Rows may be different, so we have to sum the height of all rows,
The same for the Columns, since each Column has it's own width,
CellFormatting may be in place, so we need to refresh the DataGridView before drawing it: rows that are not visible may not have been formatted yet,
There's a limit (32,767) in the Bitmap dimensions.
Call this method as follows, specifying whether you want to include the Row or Column Headers or exclude both, passing True/False as the ColumnHeaders and RowHeaders arguments.
The dgv argument is of course the DataGridView control instance that will be drawn:
' Prints the DataGridView including the Columns' Headers only
Dim dgvBitmap = DataGridViewToBitmap(DataGridView1, True, False)
Dim imagePath = Path.Combine(AppContext.BaseDirectory, $"{NameOf(DataGridView1)}.tiff")
dgvBitmap.Save(imagePath, ImageFormat.Tiff)
' Dispose of the Bitmap or set it as the PictureBox.Image, dispose of it later.
dgvBitmap.Dispose()
Private Function DataGridViewToBitmap(dgv As DataGridView, ColumnHeaders As Boolean, RowHeaders As Boolean) As Bitmap
dgv.ClearSelection()
Dim originalSize = dgv.Size
dgv.Height = dgv.Rows.OfType(Of DataGridViewRow).Sum(Function(r) r.Height) + dgv.ColumnHeadersHeight
dgv.Width = dgv.Columns.OfType(Of DataGridViewColumn).Sum(Function(c) c.Width) + dgv.RowHeadersWidth
dgv.Refresh()
Dim dgvPosition = New Point(If(RowHeaders, 0, dgv.RowHeadersWidth), If(ColumnHeaders, 0, dgv.ColumnHeadersHeight))
Dim dgvSize = New Size(dgv.Width, dgv.Height)
If dgvSize.Height > 32760 OrElse dgvSize.Width > 32760 Then Return Nothing
Dim rect As Rectangle = New Rectangle(Point.Empty, dgvSize)
Using bmp As Bitmap = New Bitmap(dgvSize.Width, dgvSize.Height)
dgv.DrawToBitmap(bmp, rect)
If (dgv.Width > originalSize.Width) AndAlso dgv.ScrollBars.HasFlag(ScrollBars.Vertical) Then
dgvSize.Width -= SystemInformation.VerticalScrollBarWidth
End If
If (dgv.Height > originalSize.Height) AndAlso dgv.ScrollBars.HasFlag(ScrollBars.Horizontal) Then
dgvSize.Height -= SystemInformation.HorizontalScrollBarHeight
End If
dgvSize = New Size(dgvSize.Width - dgvPosition.X, dgvSize.Height - dgvPosition.Y)
dgv.Size = originalSize
Return bmp.Clone(New Rectangle(dgvPosition, dgvSize), PixelFormat.Format32bppArgb)
End Using
End Function

Multi column combobox change width

I have a vb.net combobox with three columns.
How can I make the e.bounds a wider? I want to set the dropdown of the combobox
wider than the actual combobox.
I used the following code :
Private Sub BlokKiesCMB_DrawItem(ByVal sender As
System.Object, ByVal e As
System.Windows.Forms.DrawItemEventArgs)
Handles BlokKiesCMB.DrawItem
' Draw the default background
e.DrawBackground()
' The ComboBox is bound to a DataTable,
' so the items are DataRowView objects.
Dim drv As DataRowView = CType(BlokKiesCMB.Items(e.Index), DataRowView)
' Retrieve the value of each column.
Dim blokno As String = drv("blokno").ToString()
Dim kultivar As String = drv("kultivar").ToString()
Dim klas As String = drv("klas").ToString()
' Get the bounds for the first column
Dim r1 As Rectangle = e.Bounds
r1.Width = r1.Width / 3
' Draw the text on the first column
Using sb As SolidBrush = New SolidBrush(e.ForeColor)
e.Graphics.DrawString(blokno, e.Font, sb, r1)
End Using
' Draw a line to isolate the columns
Using p As Pen = New Pen(Color.Black)
e.Graphics.DrawLine(p, r1.Right, 0, r1.Right, r1.Bottom)
End Using
' Get the bounds for the second column
Dim r2 As Rectangle = e.Bounds
r2.X = e.Bounds.Width / 3
r2.Width = r2.Width / 3
' Draw the text on the second column
Using sb As SolidBrush = New SolidBrush(e.ForeColor)
e.Graphics.DrawString(kultivar, e.Font, sb, r2)
End Using
' Draw a line to isolate the columns
Using p As Pen = New Pen(Color.Black)
e.Graphics.DrawLine(p, r2.Right, 0, r2.Right, r2.Bottom)
End Using
' Get the bounds for the third column
Dim r3 As Rectangle = e.Bounds
r3.X = r2.Width + r2.X
r3.Width = r3.Width / 3
' Draw the text on the third column
Using sb As SolidBrush = New SolidBrush(e.ForeColor)
e.Graphics.DrawString(klas, e.Font, sb, r3)
End Using
End Sub
e.Bounds does not give you the sides of ComboBox or its DropDown box. Bounds refers to the position of the ComboBox relative to its parent. Read this for further reference.
Now, WinForms ComboBox has a property called DropDownWidth which allows you to control the width of the DropDown wider than the actual ComboBox's width. This property, by default, is set as the same value as the ComboBox's width.
Here is the actual example, the size of the ComboBox is 121, by default the size of its DropDown box will be 121 too.
But if you change the DropDownWidth (says, to 200)
Me.ComboBox1.DropDownWidth = 200 'change this
This is what you are going to get
The ComboBox drop down box got wider.

Dynamically coloring listview but only one column is the text being colored [duplicate]

I would like to change selection color in a ListView, from a default (blue). I can not adapt any code that I found to my needs.
Here is the code that is closest.
If e.Item.Selected = True Then
e.Graphics.FillRectangle(New SolidBrush(Color.Gray), e.Bounds)
TextRenderer.DrawText(e.Graphics, e.Item.Text, New Font(ListView2.Font, Nothing), New Point(e.Bounds.Left + 3, e.Bounds.Top + 2), Color.White)
Else
e.DrawDefault = True
End If
The main problem is e.Item.Text part. It doesn't work for multi column listview. Here is the result.
Before selection :
...and after :
Is it possible to preserve values from other columns and still have full row selection?
Thanks.
The thing to keep in mind with an OwnerDraw Listview is that there are 2 events to respond to (or override if you are subclassing) if the control is Details View: DrawColumnHeader and DrawSubItem.
DrawItem would be used when the control is using a different View and there are no SubItems to draw.
Since SubItems(0) is the same as Item.Text, you can use DrawSubItem to draw the item and subitem text. I cannot tell where that snippet is located, but this will work:
Private Sub lv1_DrawSubItem(sender As Object,
e As DrawListViewSubItemEventArgs) Handles lv1.DrawSubItem
' use sender instead of a hardcodes control ref so
' you can paste this to another LV
Dim myLV As ListView = CType(sender, ListView)
If e.ItemIndex > 0 AndAlso e.Item.Selected Then
Using br As New SolidBrush(Color.Gray)
e.Graphics.FillRectangle(br, e.Bounds)
End Using
Using fnt As New Font(myLV .Font, Nothing)
' use e.SubItem.Text
TextRenderer.DrawText(e.Graphics, e.SubItem.Text,
fnt,
New Point(e.Bounds.Left + 3, e.Bounds.Top + 2),
Color.White)
End Using ' dispose!
Else
e.DrawDefault = True
End If
End Sub
It would appear that you may be using the correct event, but by usingItem.Text rather than e.SubItem.Text the Item text will be also be drawn for all SubItems (DrawSubItem will be called as many times as there are subitems).
Note that I also wrapped the Font in a Using block to dispose of it. Using LimeGreen, the result:

Listview - Multi column - Change selection color for the whole row

I would like to change selection color in a ListView, from a default (blue). I can not adapt any code that I found to my needs.
Here is the code that is closest.
If e.Item.Selected = True Then
e.Graphics.FillRectangle(New SolidBrush(Color.Gray), e.Bounds)
TextRenderer.DrawText(e.Graphics, e.Item.Text, New Font(ListView2.Font, Nothing), New Point(e.Bounds.Left + 3, e.Bounds.Top + 2), Color.White)
Else
e.DrawDefault = True
End If
The main problem is e.Item.Text part. It doesn't work for multi column listview. Here is the result.
Before selection :
...and after :
Is it possible to preserve values from other columns and still have full row selection?
Thanks.
The thing to keep in mind with an OwnerDraw Listview is that there are 2 events to respond to (or override if you are subclassing) if the control is Details View: DrawColumnHeader and DrawSubItem.
DrawItem would be used when the control is using a different View and there are no SubItems to draw.
Since SubItems(0) is the same as Item.Text, you can use DrawSubItem to draw the item and subitem text. I cannot tell where that snippet is located, but this will work:
Private Sub lv1_DrawSubItem(sender As Object,
e As DrawListViewSubItemEventArgs) Handles lv1.DrawSubItem
' use sender instead of a hardcodes control ref so
' you can paste this to another LV
Dim myLV As ListView = CType(sender, ListView)
If e.ItemIndex > 0 AndAlso e.Item.Selected Then
Using br As New SolidBrush(Color.Gray)
e.Graphics.FillRectangle(br, e.Bounds)
End Using
Using fnt As New Font(myLV .Font, Nothing)
' use e.SubItem.Text
TextRenderer.DrawText(e.Graphics, e.SubItem.Text,
fnt,
New Point(e.Bounds.Left + 3, e.Bounds.Top + 2),
Color.White)
End Using ' dispose!
Else
e.DrawDefault = True
End If
End Sub
It would appear that you may be using the correct event, but by usingItem.Text rather than e.SubItem.Text the Item text will be also be drawn for all SubItems (DrawSubItem will be called as many times as there are subitems).
Note that I also wrapped the Font in a Using block to dispose of it. Using LimeGreen, the result:

How to change Tab Control Background Color (VB.NET)

how can I change the grey part into white color?
I want my tabcontrol filled with full white color.
So far what i did is like this:
Private Sub TabControl1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles TabControl1.DrawItem
Dim g As Graphics = e.Graphics
Dim tp As TabPage = TabControl1.TabPages(e.Index)
Dim br As Brush
Dim sf As New StringFormat
Dim r As New RectangleF(e.Bounds.X, e.Bounds.Y + 2, e.Bounds.Width, e.Bounds.Height - 2)
sf.Alignment = StringAlignment.Center
Dim strTitle As String = tp.Text
'If the current index is the Selected Index, change the color
If TabControl1.SelectedIndex = e.Index Then
'this is the background color of the tabpage header
br = New SolidBrush(Color.White) ' chnge to your choice
g.FillRectangle(br, e.Bounds)
'this is the foreground color of the text in the tab header
br = New SolidBrush(Color.Black) ' change to your choice
g.DrawString(strTitle, TabControl1.Font, br, r, sf)
Else
'these are the colors for the unselected tab pages
br = New SolidBrush(Color.White) ' Change this to your preference
g.FillRectangle(br, e.Bounds)
br = New SolidBrush(Color.Black)
g.DrawString(strTitle, TabControl1.Font, br, r, sf)
End If
End Sub
and I also put this at PageLoad function:
TabControl1.DrawMode = TabDrawMode.OwnerDrawFixed
For Each tg As TabPage In TabControl1.TabPages
tg.BackColor = Color.White
Next
There is no property to do this. However it is possible by using something like this
http://dotnetrix.co.uk/tabcontrol.htm
All controls on this site are freely available under MIT license.
Spending fair time to research if someone find a solution; There could be some work around. But according to MSDN Ref.
TabControl.BackColor Property
NET Framework (current version) This API supports the product
infrastructure and is not intended to be used directly from your code.
This member is not meaningful for this control.
Namespace: System.Windows.Forms Assembly: System.Windows.Forms (in
System.Windows.Forms.dll)
As far as I understand, this is adjustable from user's windows setting. (Highlight Color) of TabControl, Forms and other controls; otherwise MS could simply turn this property on.
I make a trick to get around this, I put on the gray part a white label and I have the following result:
Since that color segment of the tabcontrol is unpaintable and cannot be controlled, you have to use a panel or label, etc. to cover up the background color where there is no tabpage header. I use a panel to do this.
This statement working correctly:
Dim PutBackColor As Boolean = False
Private Sub TabControl1_DrawItem(sender As System.Object, e As System.Windows.Forms.DrawItemEventArgs) Handles TabControl1.DrawItem
If Me.PutBackColor = False Then
e.Graphics.FillRectangle(New SolidBrush(<YourColor>), 0 , 0, e.Bounds.Width + 2, e.Bounds.Height + 2)
Me.PutBackColor = True
End If
e.Graphics.FillRectangle(New SolidBrush(<YourColor>), 0 , 0, e.Bounds.Width + 2, e.Bounds.Height + 2)
e.Graphics.DrawString(Me.TabControl1.TabPages(e.In dex).Text, e.Font, Brushes.White, e.Bounds.X + 5, e.Bounds.Y + 5)
If e.State = DrawItemState.Selected Then
Me.PutBackColor = False
End If
End Sub