Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Listview tooltip on mouse hover?


  • Please log in to reply
8 replies to this topic
adamrgolf
  • Members
  • 442 posts
  • Last active: May 22 2017 09:16 PM
  • Joined: 28 Dec 2006
is showing of row data in a listview possible by just hovering?

I'm trying to get something to do the following, accept without clicking:

#SingleInstance,Force
OnExit,GuiClose

Gui,Add,Listview,vLV gLV AltSubmit,Name|Size

Gui,Show

Loop, %A_WinDir%\*.*
	LV_Add("",A_LoopFileName,A_LoopFileSizeKB)

Return

LV:
	If A_GuiEvent in Normal
		{
			LV_GetText(name,A_EventInfo,1)
			LV_GetText(size,A_EventInfo,2)
			tooltip, Name: %name%%A_Tab%Size: %size%
		}
Return

GuiClose:
	ExitApp

Thanks!

Adam

adamrgolf
  • Members
  • 442 posts
  • Last active: May 22 2017 09:16 PM
  • Joined: 28 Dec 2006
Anyone have any ideas? :O

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

accept without clicking:


It not possible, ( I guess ) to get a row text without selecting it first... but a row under mouse can be selected ( without clicking ) if you enable hot-track selection ( LVS_EX_TRACKSELECT LV0x8 ) style for the ListView Control.

This is what I mean:

#SingleInstance,Force
OnExit,GuiClose

Gui,Add,Listview,vLV r10 gLV [color=red]LV0x8[/color] AltSubmit,Name|Size
LV_ModifyCol(1,150 )
Gui,Show

Loop, %A_WinDir%\*.*
   LV_Add("",A_LoopFileName,A_LoopFileSizeKB)

Return

LV:
   If ( A_GuiEvent="I" )
      {
         LV_GetText(name,A_EventInfo,1)
         LV_GetText(size,A_EventInfo,2)
         tooltip, Name: %name%%A_Tab%Size: %size%
         SetTimer, ToolTipOff, -2000
      }
Return

GuiClose:
   ExitApp
   
ToolTipOff:
 Tooltip
Return

:)
kWo4Lk1.png

Micahs
  • Members
  • 463 posts
  • Last active: Mar 01 2013 06:01 AM
  • Joined: 01 Dec 2006
Try this. It calcs the row from the mouse pos and displays the text from the first two columns. No Hot-Tracking!
I tweaked parts of my "Listview In-Cell Editing" script.
#SingleInstance,Force
OnExit,GuiClose

Gui,Add,Listview, gLV vLV hwndLV_LView AltSubmit,Name|Size

Gui,Show

Loop, %A_WinDir%\*.*
   LV_Add("",A_LoopFileName,A_LoopFileSizeKB)

tipDuration = 4000

ControlGetPos, LV_lx, LV_ly, LV_lw, LV_lh, , ahk_id %LV_LView%	;get info on listview
SysGet, SM_CXVSCROLL, 2			;get width of vertical scrollbar
LVIR_LABEL = 0x0002					;LVM_GETSUBITEMRECT constant - get label info
LVM_GETITEMCOUNT = 4100			;gets total number of rows
LVM_SCROLL = 4116						;scrolls the listview
LVM_GETTOPINDEX = 4135			;gets the first displayed row
LVM_GETCOUNTPERPAGE = 4136	;gets number of displayed rows
LVM_GETSUBITEMRECT = 4152		;gets cell width,height,x,y
OnMessage(0x200, "WM_MOUSEMOVE")   
Return

WM_MOUSEMOVE(wParam, lParam, msg, hwnd)
{
	global
	If(hwnd = LV_LView)	;only if the mouse moved over the listview
	{	SendMessage, LVM_GETITEMCOUNT, 0, 0, , ahk_id %LV_LView%
		LV_TotalNumOfRows := ErrorLevel	;get total number of rows
		SendMessage, LVM_GETCOUNTPERPAGE, 0, 0, , ahk_id %LV_LView%
		LV_NumOfRows := ErrorLevel	;get number of displayed rows
		SendMessage, LVM_GETTOPINDEX, 0, 0, , ahk_id %LV_LView%
		LV_topIndex := ErrorLevel	;get first displayed row
		
		LV_mx := lParam & 0xFFFF	;get mouse x,y
		LV_my := lParam >> 16
		
		VarSetCapacity(LV_XYstruct, 16, 0)	;create struct
		Loop,% LV_NumOfRows + 1	;gets the current row and cell Y,H
		{	LV_which := LV_topIndex + A_Index - 1	;loop through each displayed row
			NumPut(LVIR_LABEL, LV_XYstruct, 0)	;get label info constant
			NumPut(A_Index - 1, LV_XYstruct, 4)	;subitem index
			SendMessage, LVM_GETSUBITEMRECT, %LV_which%, &LV_XYstruct, , ahk_id %LV_LView%	;get cell coords
			LV_RowY := NumGet(LV_XYstruct,4)	;row upperleft y
			LV_RowY2 := NumGet(LV_XYstruct,12)	;row bottomright y2
			LV_currColHeight := LV_RowY2 - LV_RowY ;get cell height
			If(LV_my <= LV_RowY + LV_currColHeight)	;if mouse Y pos less than row pos + height
			{	If(oldLV_which != LV_which)
				{	LV_currRow  := LV_which + 1	;1-based current row
					LV_currRow0 := LV_which		;0-based current row, if needed
					LV_GetText(txt1, LV_currRow, 1)
					LV_GetText(txt2, LV_currRow, 2)
					ToolTip,Name: %txt1%%A_Tab%Size: %txt2%,,,19
					SetTimer, killTip, %tipDuration%
				}
				oldLV_which := LV_which
				Break
				killTip:
					tooltip,,,, 19
					SetTimer, killTip, Off
				Return
			}
		}
	}
	Else
	{	oldLV_which=
		tooltip,,,, 19
	}
}

LV:
;~    If A_GuiEvent in Normal
;~       {
;~          LV_GetText(name,A_EventInfo,1)
;~          LV_GetText(size,A_EventInfo,2)
;~          tooltip, Name: %name%%A_Tab%Size: %size%
;~       }
Return

GuiClose:
   ExitApp

Posted Image

adamrgolf
  • Members
  • 442 posts
  • Last active: May 22 2017 09:16 PM
  • Joined: 28 Dec 2006
Holy crap Micahs, that is great!

Edit: This is perfect, exactly what I needed. Great work!

Micahs
  • Members
  • 463 posts
  • Last active: Mar 01 2013 06:01 AM
  • Joined: 01 Dec 2006
Glad you like it! Hope it helps.
Posted Image

ribbs2521
  • Members
  • 279 posts
  • Last active: Feb 23 2012 05:58 PM
  • Joined: 28 Sep 2007
I have been using Micahs' code for quite some time now and it is a great tool. The only thing I would like to change is the ability to have a delay.

I'm not sure how to implement this but an example would be like in a lot of forums, the tooltip is not immediate, there is a three or four second delay.

What I did was I just added a mouse coordinate check after two seconds and if the mouse hadn't moved, it would display the tip but it doesn't always work. I still get some tips that come up from rows I didn't hover over for a full two seconds. I believe it's because, by sleeping for two seconds and then checking again I'm causing a large queue of WM_MOUSEMOVE calls if it moves during those two seconds. If that made any sense.

So, I guess it may be as simple as telling it to kill the other WM_MOUSEMOVE threads each time a new one is started if that's possible.

Well, let me know what you think.

Micahs
  • Members
  • 463 posts
  • Last active: Mar 01 2013 06:01 AM
  • Joined: 01 Dec 2006
Here is an updated version and example:
#SingleInstance,Force
OnExit,GuiClose

Gui,Add,Listview, vLV hwndLV_LView AltSubmit,Name|Size
Gui,Show

Loop, %A_WinDir%\*.*	;just fill listview
   LV_Add("",A_LoopFileName,A_LoopFileSizeKB)

OnMessage(0x200, "WM_MOUSEMOVE")   
Return

WM_MOUSEMOVE(wParam, lParam, msg, hwnd)
{
	global
	If(hwnd = LV_LView)	;only if the mouse moved over the listview
	{	LV_MouseGetCellPos(LV_CurrRow, LV_CurrCol, LV_LView)
		If(oldLV_CurrRow != LV_CurrRow)	;if it has changed
		{	oldLV_CurrRow := LV_CurrRow
			ToolTip,,,, 20
			counter := A_TickCount + 500
			Loop	;loop for 500 ms and cancel tip if row changed
			{	LV_MouseGetCellPos(LV_CurrRow, LV_CurrCol, LV_LView)
				IfNotEqual, oldLV_CurrRow, %LV_CurrRow%
				{	SetTimer, KillNow, -1
					Return
				}
				looper := A_TickCount
				IfGreater, looper, %counter%, Break
				sleep, 150
			}
			LV_GetText(txt1, LV_currRow, 1)
			LV_GetText(txt2, LV_currRow, 2)
			SetTimer, killTip, 500
			ToolTip,Name: %txt1%%A_Tab%Size: %txt2%,,,20
		}
		Return
		killTip:
			killTipCounter++
			MouseGetPos, , , outWm, outK, 2
			If(outK != LV_LView) or (killTipCounter >= 8)	;500ms*8 = ~4 secs
			{	;this lets us kill the tooltip immediately
				KillNow:
					SetTimer, killTip, Off
					ToolTip,,,, 20
					killTipCounter=0
				Return
			}
		Return
	}
	Else	;if not over lv, destroy tip
	{	SetTimer, killTip, -1	;go now once
	}
}

GuiClose:
   ExitApp
Return


LV_MouseGetCellPos(ByRef LV_CurrRow, ByRef LV_CurrCol, LV_LView)
{	
	LVIR_LABEL = 0x0002					;LVM_GETSUBITEMRECT constant - get label info
	LVM_GETITEMCOUNT = 4100			;gets total number of rows
	LVM_SCROLL = 4116						;scrolls the listview
	LVM_GETTOPINDEX = 4135			;gets the first displayed row
	LVM_GETCOUNTPERPAGE = 4136	;gets number of displayed rows
	LVM_GETSUBITEMRECT = 4152		;gets cell width,height,x,y
	ControlGetPos, LV_lx, LV_ly, LV_lw, LV_lh, , ahk_id %LV_LView%	;get info on listview

	SendMessage, LVM_GETITEMCOUNT, 0, 0, , ahk_id %LV_LView%
	LV_TotalNumOfRows := ErrorLevel	;get total number of rows
	SendMessage, LVM_GETCOUNTPERPAGE, 0, 0, , ahk_id %LV_LView%
	LV_NumOfRows := ErrorLevel	;get number of displayed rows
	SendMessage, LVM_GETTOPINDEX, 0, 0, , ahk_id %LV_LView%
	LV_topIndex := ErrorLevel	;get first displayed row
	
	CoordMode, MOUSE, RELATIVE
	MouseGetPos, LV_mx, LV_my
	LV_mx -= LV_lx, LV_my -= LV_ly
	
	VarSetCapacity(LV_XYstruct, 16, 0)	;create struct
	Loop,% LV_NumOfRows + 1	;gets the current row and cell Y,H
	{	LV_which := LV_topIndex + A_Index - 1	;loop through each displayed row
		NumPut(LVIR_LABEL, LV_XYstruct, 0)	;get label info constant
		NumPut(A_Index - 1, LV_XYstruct, 4)	;subitem index
		SendMessage, LVM_GETSUBITEMRECT, %LV_which%, &LV_XYstruct, , ahk_id %LV_LView%	;get cell coords
		LV_RowY := NumGet(LV_XYstruct,4)	;row upperleft y
		LV_RowY2 := NumGet(LV_XYstruct,12)	;row bottomright y2
		LV_currColHeight := LV_RowY2 - LV_RowY ;get cell height
		If(LV_my <= LV_RowY + LV_currColHeight)	;if mouse Y pos less than row pos + height
		{	LV_currRow  := LV_which + 1	;1-based current row
			LV_currRow0 := LV_which		;0-based current row, if needed
			;LV_currCol is not needed here, so I didn't do it! It will always be 0. See my ListviewInCellEditing function for details on finding LV_currCol if needed.
			LV_currCol=0
			Break
		}
	}
}

It now uses parts of my tooltipV2 function. This one originally used version one of the tooltip stuff. I had improved it but hadn't updated this accordingly. This more closely mimics normal tooltip behavior. There is a 500ms lag before the tip appears. It will stay for about 4 seconds. I also broke the LV row detection out into a function called "LV_MouseGetCellPos". Hope this helps.

Micahs
Posted Image

KCzx3
  • Members
  • 22 posts
  • Last active: Oct 07 2015 02:31 AM
  • Joined: 09 Jun 2015

In case anyone has searched like I have for many hours to find this and then adjust it...  Here is the code to get the current column.

VarSetCapacity(LV_XYstruct, 16, 0)	;create struct
	Loop % LV_GetCount("Col")	;%;gets the current column, and cell X,W
	{
		NumPut(LVIR_LABEL, LV_XYstruct,0)	;get label info constant
		NumPut(A_Index-1, LV_XYstruct,4)	;subitem index
		SendMessage,LVM_GETSUBITEMRECT, %LV_CurrRow%, &LV_XYstruct, %LV%, ahk_id %LV_LView%	;get cell coords
		LV_RowX 	:= NumGet(LV_XYstruct,0,4) + LV_lx	;row upperleft x = itempos x + listview x
		LV_RowX2 	:= NumGet(LV_XYstruct,8,4) + LV_lx	;row bottomright x2 = itempos x2 + listview x
		LV_currColWidth := LV_RowX2 - LV_RowX	;get cell width
		If(LV_mx <= LV_RowX + LV_currColWidth)	;if mouse X pos less than column pos+width
		{	
			LV_currCol := A_Index	;get current column number
			Break
		}
	}

Some of my fields are a bit different though.

 

One unique field is:

LV = SysListView321