adam8
asked on
Alternative listview
Hi,
I am using the listview from Windows Common Controls 6.0 (SP4) The problem is that when I use.
ListView1.ListItems(i).Ico n = X
the scroll position of the listview resets to the beginning. I need an update or totally new control (freeware) which is compatible with the ImageList control but wont have the same problem I am currently experiencing.
Thanks
I am using the listview from Windows Common Controls 6.0 (SP4) The problem is that when I use.
ListView1.ListItems(i).Ico
the scroll position of the listview resets to the beginning. I need an update or totally new control (freeware) which is compatible with the ImageList control but wont have the same problem I am currently experiencing.
Thanks
What the listview is doing is scolling to ensure that the currently selected listitem is in view. So, if it's scrolling to the top, it's because no item in the list has been selected. If you can find a way to select one of the currently visible listitems before you issue that code, then the control wont scroll on you.
Which mode are you using, Icon, Small Icon, List, Report?
Which mode are you using, Icon, Small Icon, List, Report?
ASKER
I am using Icon view and I tried that and it works but the prob is what if the user already has a selection out of the visible range. I don't want to interfere with any other selections yet I don't want the position to reset.
As for you PBuck I will download that control to see how it is.
As for you PBuck I will download that control to see how it is.
I tried using LockWindowUpdate and SendMessage to stop window refreshing, but neither of those worked either.
ASKER
well if you come up with something
You may consider a way that's apparently used by (i.e.) the Windows Explorer: update the icons as soon as they become visible, and postpone it as long as they are hidden from view. This requires using either a timer to test for appearing items, or subclassing the scroll-event or the likes of the listview. If you like using an approach like this I may be able to help you further, but it will require quite some extra coding to get it neatly done.
ASKER
okay, maybe I could try something like what you suggested.
ASKER
Hi,
Actually, now that I read your question I realised I have already done that and it is on a timer.
I have no trouble with getting the visible items and loading icons for them but when I set the new icon for a visible item
the scroll bar goes to the start if no selection is made.
If you could give me a way to add an event for the scrolling of a listview that would be great.
So if the user scrolled down or up on the listview I could make it check for visible items
rather than the timer checking at a regular interval.
Actually, now that I read your question I realised I have already done that and it is on a timer.
I have no trouble with getting the visible items and loading icons for them but when I set the new icon for a visible item
the scroll bar goes to the start if no selection is made.
If you could give me a way to add an event for the scrolling of a listview that would be great.
So if the user scrolled down or up on the listview I could make it check for visible items
rather than the timer checking at a regular interval.
> If you could give me a way to add an event for the scrolling of a listview that would be great.
Well, just adding an event... What you can do is subclass the window holding the ListView20WndClass (vb6 listview) for the WM_VSCROLL message (or WM_HSCROLL for that matter) and make sure it isn't processed by CallWindowProc.
If you need an example on how to subclass a window, go here:
http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconpassingfunctionpointerstodllprocedurestypelibraries.asp
Well, just adding an event... What you can do is subclass the window holding the ListView20WndClass (vb6 listview) for the WM_VSCROLL message (or WM_HSCROLL for that matter) and make sure it isn't processed by CallWindowProc.
If you need an example on how to subclass a window, go here:
http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconpassingfunctionpointerstodllprocedurestypelibraries.asp
ASKER
could you please just tell me what I need to do because I can't be bothered reading all the crap on the link.
> because I can't be bothered reading all the crap on the link
It's really very usefull and only a 5 min. read. But I'll do the copy and pasting and adjusting for you, just because it's such a rainy day over here ;)
'Code from http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconpassingfunctionpointerstodllprocedurestypelibraries.asp
'Adjusted for use with ListView from VB6
'Place a checkbox on the form (name: chkSubclass) and add this to the form code:
Private Sub chkSubclass_Click()
If chkSubclass.Value = vbChecked Then
gHW = ListView1.hwnd 'Your listview here
Hook
Else
Unhook
End If
End Sub
'Place the following code in a module
Public Const WM_HSCROLL = &H114
Public Const WM_VSCROLL = &H115
Public Const GWL_WNDPROC = -4
Public Sub Hook()
lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, AddressOf WindowProc)
End Sub
Public Sub Unhook()
SetWindowLong gHW, GWL_WNDPROC, lpPrevWndProc
End Sub
Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'Just add other messages if they bug you
If uMsg = WM_VSCROLL Or uMsg = WM_HSCROLL Then
'Stop processing, no scrolling allowed
WindowProc = DefWindowProc(hw, uMsg, wParam, lParam)
Else
'Call prev. window procedure, the original!
WindowProc = CallWindowProc(lpPrevWndPr oc, hw, uMsg, wParam, lParam)
End If
End Function
Hope this helps,
Cheers
Abel
It's really very usefull and only a 5 min. read. But I'll do the copy and pasting and adjusting for you, just because it's such a rainy day over here ;)
'Code from http://msdn.microsoft.com/library/en-us/vbcon98/html/vbconpassingfunctionpointerstodllprocedurestypelibraries.asp
'Adjusted for use with ListView from VB6
'Place a checkbox on the form (name: chkSubclass) and add this to the form code:
Private Sub chkSubclass_Click()
If chkSubclass.Value = vbChecked Then
gHW = ListView1.hwnd 'Your listview here
Hook
Else
Unhook
End If
End Sub
'Place the following code in a module
Public Const WM_HSCROLL = &H114
Public Const WM_VSCROLL = &H115
Public Const GWL_WNDPROC = -4
Public Sub Hook()
lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, AddressOf WindowProc)
End Sub
Public Sub Unhook()
SetWindowLong gHW, GWL_WNDPROC, lpPrevWndProc
End Sub
Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
'Just add other messages if they bug you
If uMsg = WM_VSCROLL Or uMsg = WM_HSCROLL Then
'Stop processing, no scrolling allowed
WindowProc = DefWindowProc(hw, uMsg, wParam, lParam)
Else
'Call prev. window procedure, the original!
WindowProc = CallWindowProc(lpPrevWndPr
End If
End Function
Hope this helps,
Cheers
Abel
ASKER
So how do I know when the user scrolls?
You don't have to know. Suppose your function to set the icon is called SetIcon(Index As Long), then you simply alter that function as follows:
Sub SetIcon(Index As Long)
gHW = ListView1.hwnd 'Your listview here
Hook
'... your seticon code
UnHook
End Sub
In other words, only when you change the icon you prevent scrolling.
And if you do want to know when the user scrolls, just for the fun of it, see the WindowProc, it happens there. In the if-statement to be more precise.
Cheers,
Abel
Sub SetIcon(Index As Long)
gHW = ListView1.hwnd 'Your listview here
Hook
'... your seticon code
UnHook
End Sub
In other words, only when you change the icon you prevent scrolling.
And if you do want to know when the user scrolls, just for the fun of it, see the WindowProc, it happens there. In the if-statement to be more precise.
Cheers,
Abel
ASKER
but when the images are being processed nothing can be clicked anyway because it is in a loop, so therefore the user wouldn't be scrolling to much anyway :-)
That's good. Does it work? I couldn't test it with your code of course ;-)
ASKER
it is in a loop, everything is freezed until the loop completes so your code wouldn't really do much.
ASKER
wait a minute. WIll your code stop the program from scrolling to the start of the list every time?
ASKER
I tried the hook thing and I put the hook exactly where it changes the icon and put the unhook exactly after that but it freezes the program and i have to end task.
ASKER
any other suggestions
May I have a look at your code? I mean the part of the loop where you change the pictures (you know, the part that makes the listbox scroll unintentionally) plus the way you implemented the hooking code. I'll try to modify it so that it won't scroll the listbox when you change the pictures.
ASKER
hi, here is the whole of the timer code and the problem is occured at
flb.ListItems(i).Icon = Icons(i)
I put the Hook code before that and Unhook after that. I tried putting the hook code in a command button just to check and Visual Basic closed.
On Error Resume Next
Dim i As Long
Dim lstVisCount As Integer
Dim FirstVis As Boolean
Dim SelItem As Long
If tabMain.Tab = 1 Then Exit Sub
If flb.ListItems.Count = 0 Then
tmrLoadThumbnails.Enabled = False
Exit Sub
End If
If FirstVisible = flb.GetFirstVisible.Index Then
Exit Sub
End If
lstVisCount = flb.GetFirstVisible.Index + GetVisibleCount(flb) - 1
SelItem = flb.SelectedItem.Index
FirstVisible = flb.GetFirstVisible.Index
'FirstVis = flb.ListItems(FirstVisible ).Selected
'flb.ListItems(FirstVisibl e).Selecte d = True
If FirstVis = False Then
flb.ListItems(FirstVisible ).Selected = False
End If
gHW = flb.hwnd
'flb.ListItems(SelItem).Se lected = True
StartLoop:
'from first visible item to the next visible items
For i = FirstVisible To lstVisCount
If Icons(i) > 0 Then GoTo LoadNextThumbnail
picSrc.Picture = LoadPicture(flbList(i))
hWidth = picSrc.Width
hHeight = picSrc.Height
If hHeight > 76.8 Then
hWidth = 76.8 * picSrc.Width / picSrc.Height
hHeight = 76.8
End If
If hWidth > 102.4 Then
hHeight = 102.4 * picSrc.Height / picSrc.Width
hWidth = 102.4
End If
picThumb.PaintPicture picSrc, (picThumb.Width - hWidth) / 2, (picThumb.Height - hHeight) / 2, hWidth, hHeight
imgList.ListImages.Add , , picThumb.Image
Icons(i) = imgList.ListImages.Count
flb.ListItems(i).Icon = Icons(i)
picThumb.Cls
flb.Refresh
LoadNextThumbnail:
Next
flb.ListItems(i).Icon = Icons(i)
I put the Hook code before that and Unhook after that. I tried putting the hook code in a command button just to check and Visual Basic closed.
On Error Resume Next
Dim i As Long
Dim lstVisCount As Integer
Dim FirstVis As Boolean
Dim SelItem As Long
If tabMain.Tab = 1 Then Exit Sub
If flb.ListItems.Count = 0 Then
tmrLoadThumbnails.Enabled = False
Exit Sub
End If
If FirstVisible = flb.GetFirstVisible.Index Then
Exit Sub
End If
lstVisCount = flb.GetFirstVisible.Index + GetVisibleCount(flb) - 1
SelItem = flb.SelectedItem.Index
FirstVisible = flb.GetFirstVisible.Index
'FirstVis = flb.ListItems(FirstVisible
'flb.ListItems(FirstVisibl
If FirstVis = False Then
flb.ListItems(FirstVisible
End If
gHW = flb.hwnd
'flb.ListItems(SelItem).Se
StartLoop:
'from first visible item to the next visible items
For i = FirstVisible To lstVisCount
If Icons(i) > 0 Then GoTo LoadNextThumbnail
picSrc.Picture = LoadPicture(flbList(i))
hWidth = picSrc.Width
hHeight = picSrc.Height
If hHeight > 76.8 Then
hWidth = 76.8 * picSrc.Width / picSrc.Height
hHeight = 76.8
End If
If hWidth > 102.4 Then
hHeight = 102.4 * picSrc.Height / picSrc.Width
hWidth = 102.4
End If
picThumb.PaintPicture picSrc, (picThumb.Width - hWidth) / 2, (picThumb.Height - hHeight) / 2, hWidth, hHeight
imgList.ListImages.Add , , picThumb.Image
Icons(i) = imgList.ListImages.Count
flb.ListItems(i).Icon = Icons(i)
picThumb.Cls
flb.Refresh
LoadNextThumbnail:
Next
ASKER
It may seema bit confusing but the code that is making it scroll is this
flb.ListItems(i).Icon = Icons(i)
flb.ListItems(i).Icon = Icons(i)
ASKER
this is not going anywhere
I am terribly sorry, but I did not receive any email notification about your new comments. Just because you still existed on my todo-list made me look back to this q. to see if anything was happening.
I'll copy and paste your code into a testproject and see if I can make it work.
I'll copy and paste your code into a testproject and see if I can make it work.
ASKER
thanks
I have tried the principle goal of your code: updating a listview with new icons when an item is selected. I noticed, that even without hooking, the scroll does not appear! Unless you set Sorted to true and you also change the contents of the listview. This means that what you are experiencing is something either unique to your computer/system or version of Common Controls, or you should set Sorted to False and everything is fine.
If this is indeed a bug then I will re-investigate for you, but now in another direction. I was aiming at "normal", yet undesirable behaviour, but now it appears to be not so normal anymore.
Abel
If this is indeed a bug then I will re-investigate for you, but now in another direction. I was aiming at "normal", yet undesirable behaviour, but now it appears to be not so normal anymore.
Abel
I am sorry, I posted without realising some details about this thread. I reread it and:
you said:
> I am using Icon view
And I was using report view. Forget that last comment, I'll test the full solution and give you a new post when it works without crashing.
Cheers
you said:
> I am using Icon view
And I was using report view. Forget that last comment, I'll test the full solution and give you a new post when it works without crashing.
Cheers
I do have a working version now. Unfortunately I have to hurry to an appointment, but I'll update later today (GMT+1). It currently includes hooking (no crash at all) and setting the Listview to not visible and then visible again. The latter may not be desirable, but it's needed to paint the icons. It doesn't flicker with me, but if it does flicker with you, we'll try something else.
ASKER
I will be happy to give it a try. How did you know that making the listview invisible when hooking would work?
ASKER
I forgot to ask, that won't affect the current code I have will it, I know I will need to add in the extra code but it won't change the way that I load the icons and all that will it?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
> How did you know that making the listview invisible when hooking would work?
Hooking worked already. The reason that it did not work for you is either an error in the WindowProc procedure, which causes VB to crash, or an error in the Hook or Unhook function, which may also lead to unpredictable behaviour. When you subclass, debugging can be very hard because VB can't determine what's happening (and that's precisely what we're after!) and may crash on any error while you hook.
This also means that using "On Error Resume Next" in your code may help VB from crashing, but it may also hide certain errors that disturb other procedures and in turn, they err and crash VB.
If you start using this code and VB crashes again, try to compile your code into an executable. This has two benefits. Firstly, it shows what errors there are from mistyping (I hope you use Option Explicit?!?!). Secondly, when it crashes as an compiled exe you may have the opportunity to see a messagebox hinting you about the error.
Hooking worked already. The reason that it did not work for you is either an error in the WindowProc procedure, which causes VB to crash, or an error in the Hook or Unhook function, which may also lead to unpredictable behaviour. When you subclass, debugging can be very hard because VB can't determine what's happening (and that's precisely what we're after!) and may crash on any error while you hook.
This also means that using "On Error Resume Next" in your code may help VB from crashing, but it may also hide certain errors that disturb other procedures and in turn, they err and crash VB.
If you start using this code and VB crashes again, try to compile your code into an executable. This has two benefits. Firstly, it shows what errors there are from mistyping (I hope you use Option Explicit?!?!). Secondly, when it crashes as an compiled exe you may have the opportunity to see a messagebox hinting you about the error.
Now about the code.
The method showed here is basically similar to the original method, except for a few changes. First of all, I made the functions/subs that enable/disable the subclassing a bit more safe to use, hoping it will avoid misuse.
Then you may notice a different message being blocked: WM_STYLE_CHANGED. As it turned out, not WM_VSCROLL/WM_HSCROLL were causing the trouble, but WM_STYLE_CHANGED. Why it scrolls the listview I don't know, but it appears as if it acts so to force a redraw of the listview.
Now we have to do that manually, hence the third change: visibility to false and to true. You may want to use SendMessage with WM_PAINT and a drawing area instead (hope it works), but this is by far the easiest method to implement and flawless, except for a small flickering (although I didn't see any).
Hopefully it works as well for you as it did for me ;-)
Cheers!
Abel
The method showed here is basically similar to the original method, except for a few changes. First of all, I made the functions/subs that enable/disable the subclassing a bit more safe to use, hoping it will avoid misuse.
Then you may notice a different message being blocked: WM_STYLE_CHANGED. As it turned out, not WM_VSCROLL/WM_HSCROLL were causing the trouble, but WM_STYLE_CHANGED. Why it scrolls the listview I don't know, but it appears as if it acts so to force a redraw of the listview.
Now we have to do that manually, hence the third change: visibility to false and to true. You may want to use SendMessage with WM_PAINT and a drawing area instead (hope it works), but this is by far the easiest method to implement and flawless, except for a small flickering (although I didn't see any).
Hopefully it works as well for you as it did for me ;-)
Cheers!
Abel
ASKER
I am going away for a 2 days but I will give it a go when I get back.
THanks for your hard work.
THanks for your hard work.
ASKER
that is incredible. It works. I have been having this problem for months and no one could help.
Thank you so much. I don't think I can give more than 300 points or else I would give you 500.
It seems good and doesn't flicker. I have it in my code like this
HookListview flb
flb.ListItems(i).Icon = Icons(i)
UnhookListview
flb.Visible = False
flb.Visible = True
I am not sure if that is what you intended but it works fine and the
flb.Visible = False
flb.Visible = True
doesn't seem to do anything so I am not sure if I need it or not.
Thank you so much. I don't think I can give more than 300 points or else I would give you 500.
It seems good and doesn't flicker. I have it in my code like this
HookListview flb
flb.ListItems(i).Icon = Icons(i)
UnhookListview
flb.Visible = False
flb.Visible = True
I am not sure if that is what you intended but it works fine and the
flb.Visible = False
flb.Visible = True
doesn't seem to do anything so I am not sure if I need it or not.
> I am not sure if that is what you intended
Yes it is exactly how I intended it.
> doesn't seem to do anything so I am not sure if I need it or not.
It is too quick for the eye to see, but if you'd use Spy++ to look at the messages sending hence and forth, you'll see that a lot *is* happening. On my system, when I removed the invisible/visible part, the icons disappeared and were not drawn again, at least not before I manually used the scrollbar or did something else (like hovering another window over it) to force the control to redraw itself. But in case you are wondering, remove those two lines and you'll see for yourself. Maybe it was only needed on my system because I happen to have some obscure video card.
> Thank you so much. I don't think I can give more than 300 points or else I would give you 500.
You're welcome, I'm glad it worked ;-)
Don't worry about the points. I'm just trying to help people around here if I get the chance. "Just" a thanks is more appreciated than huge amounts of points. And indeed, 300 pts is the maximum out here, or you have to create another (blank) question.
Cheers!
Abel
Yes it is exactly how I intended it.
> doesn't seem to do anything so I am not sure if I need it or not.
It is too quick for the eye to see, but if you'd use Spy++ to look at the messages sending hence and forth, you'll see that a lot *is* happening. On my system, when I removed the invisible/visible part, the icons disappeared and were not drawn again, at least not before I manually used the scrollbar or did something else (like hovering another window over it) to force the control to redraw itself. But in case you are wondering, remove those two lines and you'll see for yourself. Maybe it was only needed on my system because I happen to have some obscure video card.
> Thank you so much. I don't think I can give more than 300 points or else I would give you 500.
You're welcome, I'm glad it worked ;-)
Don't worry about the points. I'm just trying to help people around here if I get the chance. "Just" a thanks is more appreciated than huge amounts of points. And indeed, 300 pts is the maximum out here, or you have to create another (blank) question.
Cheers!
Abel
http://www.vbaccelerator.com/ and navigate to CONTROLS on the left-hand side and try the SGRID. Looks like the Outlook grid initially, but after you download it and try out the sample - it may be exactly what you need.
Give it a try. Hope this helps!