ListView column header text on column resizing?

W

Walter Sobchak

I have a listview control with a couple of columns. Sort order is
indicated with a litle triangle.
The problem is when the sorted column is resized to a smaller width the
text is shortened and there are 3 dots displayed at the end.
The dots are bellow the triangle so I'd like to delete the dots or make
the shortening of text happen earlier.

Thanks for any help.

p.s.
I tried cutting the text on columnwidthchanging event but it doesn't
alwasy work ok (sometimes when one char is left displayed the column
text variable is containing zero chars).
 
C

Claes Bergefall

How are you putting the image in the column?

I tried my own control I've written and it doesn't experience the problem
you're describing. It uses an image list and with the standard properties on
the ColumnHeader class (i.e ImageIndex) the image ends up on the left side
of the text. In this case there obviously aren't any dots under the image.
Some tweaking with P/Invoke puts the image to the right of the text, but the
dots are still drawn to the left of the text. Not sure why you get the dots
drawn underneath the image.

Can you show a short sample to reproduce what you're seeing?

/claes
 
W

Walter Sobchak

This happens because I am using Graphics to draw the triangle after I
compute where to put it.
I'll try to do it that way.
I guess you are using your own and not system images?
 
C

Claes Bergefall

Yes, I draw my own images and put them in an imagelist. Then assign the
imagelist to the ListView.SmallImageList

There doesn't seem to be a .NET way to right align the image though, so
you'll have to use some P/Invoke
1. Use LVM_GETHEADER to get a handle to the column header control
2. Use HDM_SETITEM to set a new format flag (the fmt member in the HDITEM
structure)) that includes HDF_BITMAP_ON_RIGHT
You should only need to do this once upon startup

Here's the code I use to create the image list with the arrows in it. It's
in VB.NET though, but should be easy to understand:

Private Function CreateSortingImages() As ImageList
Dim imgList As New ImageList
Dim imgUpArrow As New Bitmap(16, 16,
Drawing.Imaging.PixelFormat.Format32bppArgb)
Dim imgDownArrow As New Bitmap(16, 16,
Drawing.Imaging.PixelFormat.Format32bppArgb)
imgList.ImageSize = New Size(16, 16)
imgList.ColorDepth = ColorDepth.Depth8Bit
imgList.TransparentColor = SystemColors.Desktop

Dim penLeft As New Pen(SystemColors.ControlDark, 1)
Dim penRight As New Pen(SystemColors.ControlLightLight, 1)
Dim brushBackground As New SolidBrush(SystemColors.Control)
Dim brushTransparent As New SolidBrush(SystemColors.Desktop)
Dim dc As Graphics
Dim point1 As Point
Dim point2 As Point
Dim point3 As Point
Dim point4 As Point
Dim point5 As Point
Dim point6 As Point

' Up arrow image - Index 0
dc = Graphics.FromImage(imgUpArrow)
dc.FillRectangle(brushTransparent, 0, 0, 16, 16)
point1 = New Point(7, 5)
point2 = New Point(8, 5)
point3 = New Point(11, 10)
point4 = New Point(11, 11)
point5 = New Point(4, 11)
point6 = New Point(4, 10)
dc.FillPolygon(brushBackground, New Point() {point1, point2, point3,
point4, point5, point6})
dc.DrawLine(penLeft, point6, point1)
dc.DrawLine(penRight, point2, point3)
dc.DrawLine(penRight, point4, point5)
imgList.Images.Add(imgUpArrow, SystemColors.Desktop)

' Down arrow image - Index 1
dc = Graphics.FromImage(imgDownArrow)
dc.FillRectangle(brushTransparent, 0, 0, 16, 16)
point1 = New Point(4, 4)
point2 = New Point(11, 4)
point3 = New Point(11, 5)
point4 = New Point(8, 10)
point5 = New Point(7, 10)
point6 = New Point(4, 5)
dc.FillPolygon(brushBackground, New Point() {point1, point2, point3,
point4, point5, point6})
dc.DrawLine(penLeft, point1, point2)
dc.DrawLine(penRight, point2, point4)
dc.DrawLine(penLeft, point5, point6)
imgList.Images.Add(imgDownArrow, SystemColors.Desktop)

Return imgList
End Function


/claes
 
W

Walter Sobchak

Thanks for your help.
So far I used this code to initialize the image list:

IntPtr hc;

// Get a handle to the header control.
hc = Win32.SendMessage(aControl.Handle, Win32.LVM_GETHEADER, (UInt32)0,
(UInt32)0);

// Add the image list to the header control.
Win32.SendMessage(hc, Win32.HDM_SETIMAGELIST, (UInt32)0,
(UInt32)CreateSortingImages().Handle);

Now when I want to display an arrow I tried to use something like
lv.Columns[0].ImageIndex = 1;

But it doesn't work.
Can you show me your code for changing imageindex?
I don't know what I am doing wrong.
 
W

Walter Sobchak

Now I tried to set the imagelist to the listview instead of the column
header and it works. The problem is that I already have one imagelist
associated with the listview.
So I should be able to associate 2 image lists to listview or associate
one to the column header..
 
W

Walter Sobchak

Walter said:
Thanks for your help.
So far I used this code to initialize the image list:

IntPtr hc;

// Get a handle to the header control.
hc = Win32.SendMessage(aControl.Handle, Win32.LVM_GETHEADER, (UInt32)0,
(UInt32)0);

// Add the image list to the header control.
Win32.SendMessage(hc, Win32.HDM_SETIMAGELIST, (UInt32)0,
(UInt32)CreateSortingImages().Handle);

Setting the imagelist to column header is the right thing to do.
The problem was that I didn't set the imageindex correctly.
This works:

for (int i = 0; i < lv.Columns.Count; i++)
{
// Use the LVM_SETCOLUMN message to set the
column's image index.
Win32.LVCOLUMN col;
// col.mask: include LVCF_FMT | LVCF_IMAGE
col.mask = Win32.LVCF_FMT | Win32.LVCF_IMAGE;

// LVCFMT_IMAGE
//col.fmt = Win32.LVCFMT_IMAGE;
col.fmt = Win32.LVCFMT_IMAGE |
Win32.HDF_BITMAP_ON_RIGHT;

// The image to use from the image list.

if (ColumnToSort == i)
{
if (OrderOfSort == SortOrder.Ascending)
{
col.iImage = 0;
}
else
{
col.iImage = 1;
}
}
else
col.iImage = -1;


// Initialize the rest to zero.
col.pszText = (IntPtr)0;
col.cchTextMax = 0;
col.cx = 0;
col.iSubItem = 0;
col.iOrder = 0;

// Send the LVM_SETCOLUMN message.
// The column that we are assigning the image to is
defined in the third parameter.
Win32.SendMessage(lv.Handle, Win32.LVM_SETCOLUMN,
(UInt32)i, ref col);
}

Claes, thank you very much for your help.
 
C

Claes Bergefall

Using the ColumnHeader.ImageIndex property apparently doesn't work as you
found out. The code I have was written for 1.1 where that property doesn't
exist, so it uses the exact same technique as you've shown below. Since that
still works I haven't bothered investigating why the .NET property doesn't
behave as expected (maybe someday I'll be bored enough to find out why :)).

Anyway, glad to see you have a working solution.

/claes
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top