Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/17/2016 in all areas

  1. From time to time questions arise about listviews with multi-line headers or headers with increased height. Eg. these two questions: Multi-line listview column headings and Listview header height. To use a multi-line header in a listview the height of the header must be increased to make room for multiple lines, and it must be possible to display multiple text lines in the header items. Increase height of header control Because the header control is contained in a listview, the height of the header must be increased in such a way that the listview will be aware of the increased height. An easy and common method of increasing the height is to define a text font for the header with a suitable height. Increasing the height in this way requires that the header is not provided with any themes. However, it is possible to restore themes after the height is increased. A better but slightly more cumbersome method is based on HDM_LAYOUT messages. A HDM_LAYOUT message (implemented in _GUICtrlHeader_Layout) is used to retrieve information about the size of a header control. To use this message to define the height, the header control must be subclassed. The HDM_LAYOUT method is preferred in the examples. Two examples with the font height method are added in "Using font height" folder. Whichever method is chosen, the header height must be increased before rows are added to the listview. Subclassing controls After Windows XP the recommended way to subclass controls is to use the four functions SetWindowSubclass, GetWindowSubclass, RemoveWindowSubclass and DefSubclassProc (all implemented in WinAPIShellEx.au3). These functions are used in the examples. And they are much easier to use than the old SetWindowLong (_WinAPI_SetWindowLong) function. Since we are subclassing a header control contained in a listview this issue must be taking into account. I have verified that this is also an issue for _WinAPI_DefSubclassProc. The solution is the same as the solution in the link: ;Return _WinAPI_DefSubclassProc( ... ) ; Not so good Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", ... )[0] ; Much better Responding to HDM_LAYOUT messages HDM_LAYOUT messages are generated when columns are added to the listview with _GUICtrlListView_AddColumn. To respond to these messages the header control must be subclassed before columns are added: Local $pHeaderProc = DllCallbackGetPtr( DllCallbackRegister( "HeaderProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) _WinAPI_SetWindowSubclass( $hHeader, $pHeaderProc, 9999, $iHeaderHeight ) ; SubclassId = 9999, $pData = $iHeaderHeight If columns are added directly in GUICtrlCreateListView command, this code snippet (copied from _GUICtrlHeader_Create) can be used to generate a HDM_LAYOUT message: Local $tRect = _WinAPI_GetClientRect( $hListView ) Local $tWindowPos = _GUICtrlHeader_Layout( $hHeader, $tRect ) _WinAPI_SetWindowPos( $hHeader, DllStructGetData( $tWindowPos , "InsertAfter" ), _ DllStructGetData( $tWindowPos , "X" ), DllStructGetData( $tWindowPos , "Y" ), _ DllStructGetData( $tWindowPos , "CX" ), DllStructGetData( $tWindowPos , "CY" ), _ DllStructGetData( $tWindowPos , "Flags" ) ) This is the subclass callback function: Func HeaderProc( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $iHeaderHeight ) #forceref $iSubclassId Switch $iMsg Case $HDM_LAYOUT Local $tHdLayout = DllStructCreate( $tagHDLAYOUT, $lParam ) Local $tRect = DllStructCreate( $tagRECT, DllStructGetData( $tHdLayout, "Rect" ) ) Local $tWindowPos = DllStructCreate( $tagWINDOWPOS, DllStructGetData( $tHdLayout, "WindowPos" ) ) ; Modify $tRect and $tWindowPos in $tHdLayout to increase Header height DllStructSetData( $tRect, "Top", $iHeaderHeight ) DllStructSetData( $tWindowPos, "X", DllStructGetData( $tRect, "Left" ) ) DllStructSetData( $tWindowPos, "Y", 0 ) DllStructSetData( $tWindowPos, "CX", DllStructGetData( $tRect, "Right" ) - DllStructGetData( $tRect, "Left" ) ) DllStructSetData( $tWindowPos, "CY", $iHeaderHeight ) DllStructSetData( $tWindowPos, "Flags", 0x0020 ) ; 0x0020 = $SWP_FRAMECHANGED Return True EndSwitch ; Call next function in subclass chain Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] EndFunc Multiple text lines in header items The items in a standard header control can display a single line of text. There seems not to be any options to change this. There is no word wrap option. Fortunately the header control supports both custom and owner drawn items. Custom drawn items are implemented through NM_CUSTOMDRAW notifications included in WM_NOTIFY messages. NM_CUSTOMDRAW notifications are generated automatically by the code in ComCtl32.dll when the header control is updated. Implementing custom drawn items is a matter of responding to these messages or not. Owner drawn items are implemented through WM_DRAWITEM messages. The HDF_OWNERDRAW flag must be set for the header items to generate WM_DRAWITEM messages. Custom drawn items are preferred in the examples. An example with owner drawn items is added in "Owner drawn" folder. Custom drawn items WM_NOTIFY (and WM_DRAWITEM) messages are send to the parent of the header control. The parent is usually an AutoIt GUI, and messages can be handled by a function registered with GUIRegisterMsg. In this case the listview is the parent of the header control. To catch header messages from the listview, the listview must be subclassed. Implement subclassing for the listview: Local $pListViewProc = DllCallbackGetPtr( DllCallbackRegister( "ListViewProc", "lresult", "hwnd;uint;wparam;lparam;uint_ptr;dword_ptr" ) ) _WinAPI_SetWindowSubclass( $hListView, $pListViewProc, 9999, 0 ) The subclass callback function looks like this: Func ListViewProc( $hWnd, $iMsg, $wParam, $lParam, $iSubclassId, $pData ) #forceref $iSubclassId, $pData Switch $iMsg Case $WM_NOTIFY Local $tNMHDR = DllStructCreate( $tagNMHDR, $lParam ) Local $hWndFrom = HWnd( DllStructGetData( $tNMHDR, "hWndFrom" ) ) Local $iCode = DllStructGetData( $tNMHDR, "Code" ) Switch $hWndFrom Case $hHeader Switch $iCode Case $NM_CUSTOMDRAW Local $tNMCustomDraw = DllStructCreate( $tagNMCUSTOMDRAW, $lParam ) Local $dwDrawStage = DllStructGetData( $tNMCustomDraw, "dwDrawStage" ) Switch $dwDrawStage ; Holds a value that specifies the drawing stage Case $CDDS_PREPAINT ; Before the paint cycle begins Return $CDRF_NOTIFYITEMDRAW ; Notify parent window of any item related drawing operations Case $CDDS_ITEMPREPAINT ; Before an item is drawn: Default painting (frames and background) Return $CDRF_NOTIFYPOSTPAINT ; Notify parent window of any post item related drawing operations Case $CDDS_ITEMPOSTPAINT ; After an item is drawn: Custom painting (item texts) Local $iIndex = DllStructGetData( $tNMCustomDraw, "dwItemSpec" ) ; Item index Local $hDC = DllStructGetData( $tNMCustomDraw, "hdc" ) ; Device context _WinAPI_SetBkMode( $hDC, $TRANSPARENT ) ; Transparent background DllStructSetData( $tNMCustomDraw, "Left", DllStructGetData( $tNMCustomDraw, "Left" ) + $aHdrInfo[$iIndex][1] ) ; Left margin DllStructSetData( $tNMCustomDraw, "Right", DllStructGetData( $tNMCustomDraw, "Right" ) - $aHdrInfo[$iIndex][1] ) ; Right margin DllStructSetData( $tNMCustomDraw, "Top", DllStructGetData( $tNMCustomDraw, "Top" ) + 2 ) ; 2 pixel top margin DllStructSetData( $tNMCustomDraw, "Bottom", DllStructGetData( $tNMCustomDraw, "Bottom" ) - 4 ) ; 4 pixel bottom margin DllCall( "user32.dll", "int", "DrawTextW", "handle", $hDC, "wstr", $aHdrInfo[$iIndex][0], "int", StringLen( $aHdrInfo[$iIndex][0] ), "struct*", DllStructGetPtr( $tNMCustomDraw, "Left" ), "uint", $aHdrInfo[$iIndex][2] ) ; _WinAPI_DrawText Return $CDRF_NEWFONT ; $CDRF_NEWFONT must be returned after changing font or colors EndSwitch EndSwitch EndSwitch EndSwitch ; Call next function in subclass chain Return DllCall( "comctl32.dll", "lresult", "DefSubclassProc", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam )[0] EndFunc Default code in the $CDDS_ITEMPREPAINT stage draws the item frames and background. Code is added to the $CDDS_ITEMPOSTPAINT stage to draw the multi-line item texts. Since we are forced to use custom drawn (or owner drawn) items in any case, we might as well take the opportunity to use some of the options which custom drawn (or owner drawn) items offers. This includes various text styles and fonts, colored text and background, item icons or bitmaps and item frames. The picture shows some of the possibilities: Examples The examples are divided into four folders: Custom drawn contains the examples based on custom drawing. In these examples there is only added code to the $CDDS_ITEMPOSTPAINT stage to fill the inside of the item frames. Owner drawn folder contains an example that shows how to use an owner drawn header control. Two examples in Using font height shows how to use a font to increase the height of the header. Themes are disabled for the header control while the height is increased. Items are custom drawn. The first example restores the theme and draws multi-line texts in the $CDDS_ITEMPOSTPAINT stage. The second example draws entire header items including frames in the $CDDS_ITEMPREPAINT stage. Frames are drawn with _WinAPI_DrawFrameControl. Two examples in Using HDM_LAYOUT shows how to use HDM_LAYOUT messages to increase the height of the header when columns are added with _GUICtrlListView_AddColumn and directly with GUICtrlCreateListView. In all examples LVS_EX_HEADERDRAGDROP extended style is defined for the listview to be able to rearrange columns by drag-and-drop of header items. ListviewHeader.7z Custom drawn\ 1) Simple multi-line header.au3 2) Simple formatted text.au3 3) Styles, fonts, colors.au3 4) Icons and bitmaps.au3 Pattern.bmp Owner drawn\ 1) Simple multi-line header.au3 DrawItem.au3 Using font height\ 1) Restore header theme.au3 2) Drawing everything.au3 Using HDM_LAYOUT\ 1) Columns added with _GUICtrlListView_AddColumn.au3 2) Columns added with GUICtrlCreateListView.au3 ListviewHeader.7z Update 2015-11-24 I have made some tests with real listviews with more than 10 rows. It turns out that the method for increasing the height of the header has a significant impact on performance when rows are inserted in the listview. Increasing the height by responding to HDM_LAYOUT messages is a slow method. Each row inserted generates a HDM_LAYOUT message. This makes insertion slow if there are many rows. (HDM_LAYOUT method can still be used. But it should not be used when the header is contained in a listview.) Using a font to increase the height of the header does not have this negative effect on performance. The purpose of the examples is to be able to use multi-line headers in real listviews. I have updated the examples to use the faster font method to increase the height. A small UDF (GuiHeaderEx.au3) with one function is added to the zip: #include-once #include <WinAPITheme.au3> Func _GUICtrlHeader_SetItemHeightByFont( $hHeader, $iHeight, $bRestoreTheme = True ) ; Remove Header theme _WinAPI_SetWindowTheme( $hHeader, "", "" ) ; Get font of Header control ; Copied from _GUICtrlGetFont example by KaFu ; See https://www.autoitscript.com/forum/index.php?showtopic=124526 Local $hDC = _WinAPI_GetDC( $hHeader ), $hFont = _SendMessage( $hHeader, $WM_GETFONT ) Local $hObject = _WinAPI_SelectObject( $hDC, $hFont ), $lvLogFont = DllStructCreate( $tagLOGFONT ) _WinAPI_GetObject( $hFont, DllStructGetSize( $lvLogFont ), DllStructGetPtr( $lvLogFont ) ) Local $hHdrfont = _WinAPI_CreateFontIndirect( $lvLogFont ) ; Original Header font _WinAPI_SelectObject( $hDC, $hObject ) _WinAPI_ReleaseDC( $hHeader, $hDC ) ; Set height of Header items by applying text font with suitable height $hFont = _WinAPI_CreateFont( $iHeight, 0 ) _WinAPI_SetFont( $hHeader, $hFont ) _WinAPI_DeleteObject( $hFont ) ; Restore Header theme If $bRestoreTheme Then _ _WinAPI_SetWindowTheme( $hHeader ) ; Return original Header font Return $hHdrfont EndFunc ListviewHeader 2015-11-24.7z Custom drawn\ 1) Simple multi-line header.au3 2) Simple formatted text.au3 3) Styles, fonts, colors.au3 4) Icons and bitmaps.au3 5) Drawing everything.au3 GuiHeaderEx.au3 Pattern.bmp Owner drawn\ 1) Simple multi-line header.au3 GuiHeaderEx.au3 DrawItem.au3 You need AutoIt 3.3.10 or later. Tested on Windows 7 32/64 bit and Windows XP 32 bit. Comments are welcome. Let me know if there are any issues. (Set tab width = 2 in SciTE to line up comments by column) ListviewHeader 2015-11-24.7z
    1 point
  2. Yeah something may actually be acting up here after my re-installation, my au3 paths are on the fritz apparently... So disregard that last test please The only thing I can think of if I look at the script and the library, is that you are directly writing a 32 bit DLL to that temp directory and then using the 64 bits executor to work with it but whether that could or could not be a problem is slightly over my head for now...
    1 point
  3. Also, may or may not help at this point, but as I was able to find a portable application that USED to be available on AutoHotKey's website, and is very useful for those who want to create IE automation scripts. This is why I locally store any application I find interesting, in the event that it falls off the face of the earth and is no longer available online, I still got it. First, it only works with IE, but it is a tool which is very similar to the AutoIT Window Info Tool in terms of operation, but instead of providing information about Windows forms, it provides you information about the elements within a loaded webpage. Very useful to who ever wants it. iWB2 Learner - 32bit.zip iWB2 Learner - 64bit.zip
    1 point
  4. water

    Help _Excel_RangeRead

    As this has been asked a few times I will add the function to the wiki
    1 point
  5. this should do the job: #include <Date.au3> $nExelres=42567.25 ConsoleWrite(_convertSerialDate($nExelres)&@CRLF) Func _convertSerialDate($nDT) Local Const $dtEXcel='1899/12/31 00:00:00' Local $iDate=Int($nDT)-1 ;adjusted after reading wiki and why result is 1 day to much: http://www.cpearson.com/excel/datetime.htm Local $iTime=Mod($nDT,1) $iTime=int(24*3600*$iTime) $dtRes=_DateAdd('D',$iDate,$dtEXcel) $dtRes=_DateAdd('s',$iTime,$dtRes) Return $dtRes EndFunc As i added 0.25 the time is 06:00 AM.
    1 point
  6. Mbee, I have already explained the problem in detail via PM, but for others reading the problem with the code you sent me was the _CustomInputBox UDF which was also registering the WM_GETMINMAXINFO message to limit the size of the UDF dialog. Very poor coding practice on the part of the UDF author resulted in the message subsequently being applied to ALL GUIs within the script - hence the resizing of the main GUI as soon as Windows received any form of RESIZEMOVE message from it. A salutary lesson to all UDF writers - you MUST make sure that your code does not adversely affect the script which calls the UDF. M23
    1 point
×
×
  • Create New...