Saludos a todos los componentes de este foro, lo que quiero consultarles es como puedo cambiar el backcolor y forecolor en el header de un listview en vbnet con las apis de windows, se los agradeceré mucho y espero tener suerte...
hola
No entiendo porqué quieres usar API para cambiar el estilo de las cabeceras de un Listview cuando vb.net ya ofrece medios para ello.
ListView.DrawColumnHeader Event (https://msdn.microsoft.com/en-us/library/system.windows.forms.listview.drawcolumnheader(v=vs.110).aspx)
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ListView1.View = View.Details
ListView1.Columns.Add("Header1", 100)
ListView1.Columns.Add("Header2", 100)
ListView1.Items.Add("Item1")
ListView1.Items(0).SubItems.Add("SubItem1")
ListView1.Items.Add("Item2")
ListView1.Items(1).SubItems.Add("SubItem2")
ListView1.OwnerDraw = True
End Sub
Private Sub ListView1_DrawColumnHeader(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewColumnHeaderEventArgs) Handles ListView1.DrawColumnHeader
'//Rectángulos para el Bacground
Try
'Rectángulo inferior
e.Graphics.FillRectangle(Brushes.Black, e.Bounds)
'Rectángulo superior (Se superpone sobre el rectángulo anterior y es más pequeño)
Dim RectPoint As New Point(e.Bounds.X + 1, e.Bounds.Y + 1)
Dim RectSize As New Size(New Point(e.Bounds.Width - 2, e.Bounds.Height - 2))
Dim Rect As New Rectangle(RectPoint, RectSize)
e.Graphics.FillRectangle(Brushes.White, Rect)
Finally
End Try
'//Dibuja el texto (Se superpone a los rectángulos anteriores o imagen de fondo)
Dim sf As New StringFormat()
Try
Select Case e.Header.TextAlign
Case HorizontalAlignment.Center
sf.Alignment = StringAlignment.Center
Case HorizontalAlignment.Right
sf.Alignment = StringAlignment.Far
End Select
Dim headerFont As New Font("Helvetica", 10, FontStyle.Bold)
Try
e.Graphics.DrawString(e.Header.Text, headerFont, Brushes.Black, _
New Point(e.Bounds.X + 5, e.Bounds.Y + 1), sf)
Finally
headerFont.Dispose()
End Try
Finally
sf.Dispose()
End Try
End Sub
Private Sub ListView1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewItemEventArgs) Handles ListView1.DrawItem
e.DrawDefault = True
End Sub
End Class
Los cambios se asignan por capas primero estableces lo que sería el 'Background' mediante FillRectangle, si creas otro FillRectangle éste se coloca en la parte superior del anterior en el mismo orden en el que se nombra en el código. Y por último la representación del texto. Si escribes la referéncia al texto antes que aplicar el rectángulo entonces no se verá el texto.
También puedes aplicar una imagen en lugar FillRectangle:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
ListView1.View = View.Details
ListView1.Columns.Add("Header1", 100)
ListView1.Columns.Add("Header2", 100)
ListView1.Items.Add("Item1")
ListView1.Items(0).SubItems.Add("SubItem1")
ListView1.Items.Add("Item2")
ListView1.Items(1).SubItems.Add("SubItem2")
ListView1.OwnerDraw = True
End Sub
Private Sub ListView1_DrawColumnHeader(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewColumnHeaderEventArgs) Handles ListView1.DrawColumnHeader
'//Dibuja una imagen
Dim imagen As Image
imagen = Image.FromFile("C:\Documents and Settings\Administrador\Mis documentos\columnHeader.png")
e.Graphics.DrawImage(imagen, e.Bounds)
'//Dibuja el texto (Se superpone a los rectángulos anteriores o imagen de fondo)
Dim sf As New StringFormat()
Try
Select Case e.Header.TextAlign
Case HorizontalAlignment.Center
sf.Alignment = StringAlignment.Center
Case HorizontalAlignment.Right
sf.Alignment = StringAlignment.Far
End Select
Dim headerFont As New Font("Helvetica", 10, FontStyle.Bold)
Try
e.Graphics.DrawString(e.Header.Text, headerFont, Brushes.Black, _
New Point(e.Bounds.X + 5, e.Bounds.Y + 1), sf)
Finally
headerFont.Dispose()
End Try
Finally
sf.Dispose()
End Try
End Sub
Private Sub ListView1_DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawListViewItemEventArgs) Handles ListView1.DrawItem
e.DrawDefault = True 'No quitar esto. A no ser que apliques una personalización para este evento. DrawDefault dibujará los valores por defecto.
End Sub
End Class
Gracias Lekim por responder a la pregunta, lo que quisiera saber como cambiar el backcolor en el header de la parte derecha del sobrante, es decir que toda la barra del header quede de un solo color.
lo que quiero hacer es que se cambie el backcolor de otro color sin utilizar el evento DrawColumnHeader y sin perder los efectos cuando el mouse pasa por encima, por eso decía si se puede modificar solo el backcolor usando alguna api de windows para eso.
tengo mi código que es lo siguiente, lo repinta toda la barra del header pero lo borra las columnas existentes.
Librerias:
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWndParent As IntPtr, ByVal hwndChildAfter As IntPtr, ByVal lpszClass As String, ByVal lpszWindow As String) As IntPtr
Private Declare Function GetClientRect Lib "user32.dll" (ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Integer
Private Declare Function FillRect Lib "USER32.DLL" (ByVal hDC As Integer, ByRef lpRC As RECT, ByVal hBR As Integer) As Integer
Private Declare Function CreateSolidBrush Lib "GDI32.DLL" (ByVal crColor As Integer) As Integer
Private Declare Function DeleteObject Lib "GDI32.DLL" (ByVal hObject As Integer) As Integer
Private Declare Function GetDC Lib "user32" (ByVal hwnd As IntPtr) As Integer
Private Structure RECT
Dim Left As Integer
Dim Top As Integer
Dim Right As Integer
Dim Bottom As Integer
End Structure
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim m_HdrHwnd As IntPtr, x As IntPtr, rt As RECT, hBrush As Integer, dc As Integer
m_HdrHwnd = FindWindowEx(ListView1.Handle, 0, "SysHeader32", vbNullString)
x = GetClientRect(m_HdrHwnd, rt)
dc = GetDC(m_HdrHwnd)
hBrush = CreateSolidBrush(14563858)
FillRect(dc, rt, hBrush)
End Sub
mas o menos quiero algo así como en esta imagen en el siguiente link
(http://www.conaltid.gob.bo/documento/lv.png)
Gracias por responderme.
Es una tarea bastante complicada, incluso recurriendo a P/invokes de la WinAPI.
La zona "sin utilizar" en la derecha de la cabecera de las columnas del Listview forma parte del área NO-cliente de la ventana del control, por ende usando código administrado por ejemplo en el evento DrawColumnHeader solo vas a poder dibujar sobre el área cliente del control, así que tienes que recurrir si o si a las funciones Win32 relacionadas con GDI.
Pero el resultado será sencillamente imperfecto, ya que al tratarse del área no-cliente y como lo estamos tratando de pintar manualmente, Windows no puede determinar cuando se debe redibujar ese área, así que a veces verás como desaparece el color de ese área, ya que con los métodos base de invocadores de eventos del ListView parece no ser suficiente para indicar manualmente cuando se debe redibujar el área no-cliente en los eventos que se suceden en el control (ya que no hay un invocador de evento para controlar cuando se hace click en un separador de columna).
Aquí tienes un ejemplo que escribí, tomatelo como tal...un ejemplo, por que como ya dije esto es imperfecto, notarás como desaparece el color al hacer click sobre un separador de columna, y al redimensionar las columnas;
una solución a lo mencionado sería determinar los handles de ventana (hWnd) de todos los separadores de columnas que existan en el control, y suscribirte a cada una de las ventanas de los separadores, es decir a la función de ventana que procesa sus mensajes (WndProc) para determinar cuando se hace click (mensaje de ventana: WM_LButtonUp y WM_NcLButtonUp ) o cuando se mueve (mensaje de ventana: WM_Move y WM_ExitSizeMove) y en ese momento pintar el area no cliente, pero hacer todo eso es demasiado costoso para satisfacer un simple capricho de pintar esa zona... y aparte, por naturaleza este tipo de hacks en los controles de WinForms tenderán a generar molestos efectos de Flickering.
Imports System
Imports System.ComponentModel
Imports System.Diagnostics
Imports System.Drawing
Imports System.Linq
Imports System.Runtime.InteropServices
Imports System.Security
Imports System.Windows.Forms
Public Class ListViewEx : Inherits ListView
<Category("Appearance")>
<DisplayName("Column-Header BackColor")>
Public Property ColumnHeaderBackColor As Color
<Category("Appearance")>
<DisplayName("Column-Header ForeColor")>
Public Property ColumnHeaderForeColor As Color
<Category("Appearance")>
<DisplayName("Column-Header Separator Color")>
Public Property ColumnHeaderSeparatorColor As Color
<Category("Appearance")>
<DisplayName("Column-Header NonClient-Area Drawing Enabled")>
Public Property ColumnHeaderNonClientAreaDrawingEnabled As Boolean
Private lastColumnHeaderDrawEventArgs As DrawListViewColumnHeaderEventArgs
Private ignoreColumnHeaderNonClientAreaDrawing As Boolean
<DebuggerNonUserCode>
Public Sub New()
Me.ColumnHeaderSeparatorColor = SystemPens.ControlLightLight.Color
Me.ColumnHeaderBackColor = SystemPens.ControlDarkDark.Color
Me.ColumnHeaderForeColor = SystemColors.ControlText
MyBase.OwnerDraw = True
End Sub
Protected Overrides Sub OnEnter(e As EventArgs)
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnEnter(e)
End Sub
Protected Overrides Sub OnLeave(e As EventArgs)
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnLeave(e)
End Sub
Protected Overrides Sub OnGotFocus(e As EventArgs)
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnGotFocus(e)
End Sub
Protected Overrides Sub OnLostFocus(e As EventArgs)
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnLostFocus(e)
End Sub
Protected Overrides Sub OnInvalidated(e As InvalidateEventArgs)
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnInvalidated(e)
End Sub
Protected Overrides Sub OnDrawSubItem(e As DrawListViewSubItemEventArgs)
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnDrawSubItem(e)
End Sub
Protected Overrides Sub OnColumnWidthChanging(e As ColumnWidthChangingEventArgs)
Me.ignoreColumnHeaderNonClientAreaDrawing = True
MyBase.OnColumnWidthChanging(e)
End Sub
Protected Overrides Sub OnColumnWidthChanged(e As ColumnWidthChangedEventArgs)
Me.ignoreColumnHeaderNonClientAreaDrawing = False
Me.DrawNonClientColumnHeader(Me.lastColumnHeaderDrawEventArgs)
MyBase.OnColumnWidthChanged(e)
End Sub
Protected Overrides Sub OnDrawColumnHeader(ByVal e As DrawListViewColumnHeaderEventArgs)
Me.DrawClientColumnHeader(e)
MyBase.OnDrawColumnHeader(e)
End Sub
Protected Overrides Sub OnDrawItem(e As DrawListViewItemEventArgs)
Using g As Graphics = e.Graphics
e.DrawText()
End Using
MyBase.OnDrawItem(e)
End Sub
<DebuggerStepThrough>
Private Sub DrawClientColumnHeader(ByVal e As DrawListViewColumnHeaderEventArgs)
' If it is the last column...
If (e.ColumnIndex = (MyBase.Columns.Count - 1)) Then
Me.lastColumnHeaderDrawEventArgs = e
Me.DrawNonClientColumnHeader(e)
End If
e.DrawDefault = False ' Set Owner drawing.
Using g As Graphics = e.Graphics
' Draw header background.
Dim bgBounds As Rectangle = e.Bounds
Using bgBrush As New SolidBrush(Me.ColumnHeaderBackColor)
g.FillRectangle(bgBrush, bgBounds)
End Using
' Measure column separator bounds.
Dim colBounds As Rectangle = e.Bounds
colBounds.Width -= 1
colBounds.Height -= 1
' Draw column separator.
Using separatorPen As New Pen(Me.ColumnHeaderSeparatorColor)
g.DrawRectangle(separatorPen, colBounds)
End Using
' Set text formatting.
Dim flags As TextFormatFlags = TextFormatFlags.VerticalCenter Or TextFormatFlags.EndEllipsis
Select Case e.Header.TextAlign
Case HorizontalAlignment.Left
flags = (flags Or TextFormatFlags.Left)
Case HorizontalAlignment.Center
flags = (flags Or TextFormatFlags.HorizontalCenter)
Case Else
flags = (flags Or TextFormatFlags.Right)
End Select
' Measure and draw text.
Dim width As Integer = TextRenderer.MeasureText(" ", e.Font).Width
Dim txtBounds As Rectangle = Rectangle.Inflate(e.Bounds, -width, 0)
TextRenderer.DrawText(g, e.Header.Text, e.Font, txtBounds, Me.ColumnHeaderForeColor, flags)
End Using
End Sub
<DebuggerStepThrough>
Private Sub DrawNonClientColumnHeader(ByVal e As DrawListViewColumnHeaderEventArgs)
If (Me.ColumnHeaderNonClientAreaDrawingEnabled) AndAlso Not (Me.ignoreColumnHeaderNonClientAreaDrawing) AndAlso
(e IsNot Nothing) Then
Dim lv As ListView = e.Header.ListView
Dim hwnd As IntPtr = Me.GetColumnHeaderHwnd(lv)
Dim hdc As IntPtr = NativeMethods.GetDC(hwnd)
Dim headersWidth As Integer =
(From col As ColumnHeader In MyBase.Columns.Cast(Of ColumnHeader)()
Select col.Width
).Sum
Using g As Graphics = Graphics.FromHdc(hdc)
Dim rect As New Rectangle(e.Bounds.Right + 1, e.Bounds.Top, (Me.Bounds.Width - headersWidth), e.Bounds.Height)
Using bgBrush As New SolidBrush(Me.ColumnHeaderBackColor)
g.FillRectangle(bgBrush, rect)
End Using
End Using
NativeMethods.ReleaseDC(hwnd, hdc)
End If
End Sub
<DebuggerStepThrough>
Private Function GetColumnHeaderHwnd(ByVal lv As ListView) As IntPtr
Return NativeMethods.SendMessage(lv.Handle, NativeMethods.LvmGetHeader, New IntPtr(0), New IntPtr(0))
End Function
End Class
Friend NotInheritable Class NativeMethods
' https://msdn.microsoft.com/en-us/library/windows/desktop/bb774937%28v=vs.85%29.aspx
Friend Const LvmGetHeader As Integer = &H101F
' https://msdn.microsoft.com/en-us/library/windows/desktop/dd144871(v=vs.85).aspx
<SuppressUnmanagedCodeSecurity>
<DllImport("user32", SetLastError:=True)>
Friend Shared Function GetDC(
ByVal hwnd As IntPtr
) As IntPtr
End Function
' https://msdn.microsoft.com/en-us/library/windows/desktop/dd162920(v=vs.85).aspx
<SuppressUnmanagedCodeSecurity>
<DllImport("user32", SetLastError:=True)>
Friend Shared Function ReleaseDC(
ByVal hwnd As IntPtr,
ByVal hdc As IntPtr
) As IntPtr
End Function
' https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950(v=vs.85).aspx
<SuppressUnmanagedCodeSecurity>
<DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Friend Shared Function SendMessage(
ByVal hwnd As IntPtr,
ByVal msg As UInteger,
ByVal wParam As IntPtr,
ByVal lParam As IntPtr
) As IntPtr
End Function
End Class
PD: Nótese que me faltó añadir un Getter/Setter a las propiedades para llamar a los métodos que pintan sobre la cabecera de las columnas cuando se modifica el valor de dichas propiedades.
Saludos