Grid type Control

Started by Petrus Vorster, May 10, 2015, 06:20:21 PM

Previous topic - Next topic

Petrus Vorster

I have never used a grid control in any of my programs.
(A listview for display of info yes, but not for user inputs)
I have taken a look at mylittlegrid, but can seem to find any related help in the documentation.
Is there some free control out there that one can use where i can change the headers and allow controlled user input in columns and rows?
-Regards
Peter

David Kenny

Peter,

This is not a direct answer to your inquiry, but I thought it worth mentioning. You can use the list view as you do now.  When a user performs an action that your program takes as a signal to start edit mode (ie, single click or double-click on an item) you create an edit box over the top of the item and process the input yourself.  Not trivial, but doable.  There are examples on PB's forums.  None use SDK style programming so you would have to convert from DDT. Search for "editable listview".

David

Petrus Vorster

Ok, i can give that a shot, thanks. Sounds workable!
Unless of course i buy the little grid  :)
How does users find the registered version?
-Regards
Peter

Petrus Vorster

Something Gary Beene posted on the Pb forums:
'Compilable Example:
#Compiler PBWin 10
#Compile Exe
#Dim All
%Unicode=1
#Include "win32api.inc"  'Jose Roca includes

Enum Equates Singular
   IDC_ListView     = 500
   IDM_Demo
End Enum

Global hDlg, hListView As Dword, SortDirection As Long
Global MaxRow, MaxCol, CurrentRow, CurrentCol, OrigLVProc As Long

Function PBMain() As Long
   Dialog New Pixels, 0, "ListView Grid Demo",300,300,400,220, %WS_OverlappedWindow To hDlg
   CreateListView
   Dialog Show Modal hDlg Call DlgProc
End Function

CallBack Function DlgProc() As Long
   Local i,j As Long, pLVDI As LV_DISPINFO Ptr, lplvcd As NMLVCUSTOMDRAW Ptr
   Select Case Cb.Msg
      Case %WM_InitDialog
         'initialize data/location
         CreateLVData
         CurrentRow = 1 : CurrentCol = 1
         UpdateStatusBar
         BuildAcceleratorTable
         OrigLVProc = SetWindowLong(hListView, %GWL_WndProc, CodePtr(NewLVProc))  'subclass LV
      Case %WM_Destroy
         SetWindowLong hListView, %GWL_WNDPROC, OrigLVProc
      Case %WM_Command
         Select Case Cb.Ctl
            Case %IDM_Demo    'Ctrl-D to run the Demo
               For i = 1 To 3
                  CurrentCol = i
                  For j = 1 To 10
                     CurrentRow = j  : Sleep 250
                     UpdateStatusBar : Control ReDraw hDlg, %IDC_ListView
                  Next j
               Next i
         End Select
      Case %WM_Notify
         Select Case Cb.NmId
            Case %IDC_ListView
               Select Case Cb.NmCode
                  Case %NM_CustomDraw
                       lpLvCd = CbLParam
                       Select Case @lplvcd.nmcd.dwDrawStage
                          Case %CDDS_PREPAINT, %CDDS_ITEMPREPAINT
                             Function = %CDRF_NOTIFYSUBITEMDRAW
                          Case %CDDS_ITEMPREPAINT Or %CDDS_SUBITEM
                             If  @lplvcd.nmcd.dwItemSpec = CurrentRow-1 Then
                                If @lpLvCd.iSubItem <> CurrentCol-1 Then
                                   @lpLvCd.clrTextBk = %White
                                Else
                                   @lpLvCd.clrTextBk = %Green
                                End If
                             End If
                           Function = %CDRF_NEWFONT
                       End Select
               End Select
         End Select
   End Select
End Function

Sub CreateListView
   Control Add ListView, hDlg, %IDC_ListView,"", 10,10,380,200
   Control Handle hDlg, %IDC_ListView To hListView
   ListView Set StyleXX hDlg, %IDC_ListView, %LVS_Ex_CheckBoxes Or %LVS_Ex_GridLines Or %LVS_Ex_FullRowSelect
End Sub

Sub CreateLVData
   Local i,j As Long
   MaxRow = 50    : MaxCol = 10
   For i = 1 To MaxCol
      ListView Insert Column hDlg, %IDC_ListView, i, "Col" + Trim$(Str$(i)), 100, 0
   Next i
   For i = 1 To MaxRow
      ListView Insert Item hDlg, %IDC_ListView, i,0, "Row " + Trim$(Str$(i))
      For j = 1 To MaxCol
         ListView Set Text hDlg, %IDC_ListView, i, j, "Row" + Trim$(Str$(i)) + " Col" + Trim$(Str$(j))
      Next j
   Next i
End Sub

Sub BuildAcceleratorTable
   Local c As Long, ac() As ACCELAPI, hAccelerator As Dword  ' for keyboard accelator table values
   Dim ac(0)
   ac(c).fvirt = %FVIRTKEY Or %FCONTROL : ac(c).key   = %VK_D : ac(c).cmd   = %IDM_Demo  : Incr c
   Accel Attach hDlg, AC() To hAccelerator
End Sub

Sub UpdateStatusBar
   Dialog Set Text hDlg, "ListView Grid Demo:  " + Str$(CurrentRow) + Str$(CurrentCol)
End Sub

Function NewLVProc(ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
   Local hdnptr As HD_NOTIFY Ptr, hdiptr As HD_ITEM Ptr, w,iResult As Long
   Local LpLvNm As NM_LISTVIEW Ptr, LVHT As LVHitTestInfo
   Select Case Msg
      Case %WM_KeyDown
         Select Case wParam
            Case %VK_Up
               CurrentRow = Max(1,CurrentRow-1)
               UpdateStatusBar
               Control ReDraw hDlg, %IDC_ListView
            Case %VK_Down
               CurrentRow = Min(MaxRow,CurrentRow+1)
               UpdateStatusBar
               Control ReDraw hDlg, %IDC_ListView
            Case %VK_Left
               CurrentCol = Max(1,CurrentCol-1)
               UpdateStatusBar
               Control ReDraw hDlg, %IDC_ListView
            Case %VK_Right
               CurrentCol = Min(MaxCol,CurrentCol+1)
               UpdateStatusBar
               Control ReDraw hDlg, %IDC_ListView
            Case %VK_Pgup
               Dialog Set Text hDlg, "PageUp"   'not sure what row/col this corresponds to
            Case %VK_PgDn
               Dialog Set Text hDlg, "PageDown" 'not sure what row/col this corresponds to
            Case %VK_Home
               CurrentCol = 1
               If GetKeyState(%VK_Control) Then CurrentRow = 1
               Control ReDraw hDlg, %IDC_ListView
               UpdateStatusBar
            Case %VK_End
               CurrentCol = MaxCol
               If GetKeyState(%VK_Control) Then CurrentRow = MaxRow
               Control ReDraw hDlg, %IDC_ListView
               UpdateStatusBar
        End Select
   End Select
   Function = CallWindowProc(OrigLVProc, hWnd, Msg, wParam, lParam)
End Function

Will play around with this, it seems most of the tricks is in here.
-Regards
Peter

Petrus Vorster

Nope, just colored backgrounds. Will dig more....
-Regards
Peter

Petrus Vorster

Found a working example on the PB site. Simple, but effective.
#INCLUDE ONCE "WIN32API.INC"
#INCLUDE ONCE "COMMCTRL.INC"
#INCLUDE ONCE "PBForms.INC"

%IDD_DIALOG1   =  101
%IDC_LISTVIEW1 = 1001
%IDC_TEXTBOX1  = 1002

FUNCTION PBMAIN()
    PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR _
        %ICC_INTERNET_CLASSES)
    ShowDIALOG1 %HWND_DESKTOP
END FUNCTION

CALLBACK FUNCTION ShowDIALOG1Proc()
    LOCAL my_LpLvNm AS NM_LISTVIEW PTR
    STATIC LVRow AS LONG, LVCol AS LONG
    STATIC hListView AS LONG, i AS LONG, x AS LONG, y AS LONG, txtv AS STRING, datav AS LONG
    STATIC SIrect AS RECT

    SELECT CASE AS LONG CB.MSG
        CASE %WM_INITDIALOG
            ' Initialization handler
            CONTROL HANDLE CBHNDL, %IDC_LISTVIEW1 TO hListView

        CASE %WM_NCACTIVATE
            STATIC hWndSaveFocus AS DWORD
            IF ISFALSE CB.WPARAM THEN
                ' Save control focus
                hWndSaveFocus = GetFocus()
            ELSEIF hWndSaveFocus THEN
                ' Restore control focus
                SetFocus(hWndSaveFocus)
                hWndSaveFocus = 0
            END IF

        CASE %WM_NOTIFY
            IF LOWRD(CBWPARAM)= %IDC_LISTVIEW1 THEN
                    my_LpLvNm = CBLPARAM
                    SELECT CASE @my_LpLvNm.hdr.code
                        CASE %NM_CLICK
                            'cursor position
                            LVRow = @my_LpLvNm.iItem
                            LVCol = @my_LpLvNm.iSubItem
                            LISTVIEW UNSELECT CBHNDL, %IDC_LISTVIEW1, LVRow + 1
                            i = ListView_GetSubItemRect(hListView, LVRow, LVCol, %LVIR_BOUNDS, VARPTR(SIrect))
                            CONTROL GET LOC CBHNDL, %IDC_LISTVIEW1 TO x, y
                            IF LVCol = 0 THEN
                                LISTVIEW GET COLUMN CBHNDL, %IDC_LISTVIEW1, 1 TO datav
                                CONTROL SET LOC CBHNDL, %IDC_TEXTBOX1, x + SIrect.nLeft + 6 , y + SIrect.nTop + 1
                                CONTROL SET SIZE CBHNDL, %IDC_TEXTBOX1, datav - 7 , SIrect.nBottom - SIrect.nTop
                            ELSE
                                CONTROL SET LOC CBHNDL, %IDC_TEXTBOX1, x + SIrect.nLeft + 7 , y + SIrect.nTop + 1
                                CONTROL SET SIZE CBHNDL, %IDC_TEXTBOX1, SIrect.nRight - SIrect.nLeft - 8 , SIrect.nBottom - SIrect.nTop
                            END IF
                            CONTROL NORMALIZE CBHNDL, %IDC_TEXTBOX1
                            CONTROL SET FOCUS CBHNDL, %IDC_TEXTBOX1
                            LISTVIEW GET TEXT CBHNDL, %IDC_LISTVIEW1, LVRow + 1,  LVCol + 1 TO txtv
                            CONTROL SET TEXT CBHNDL, %IDC_TEXTBOX1, txtv
                            FUNCTION = 1
                            EXIT FUNCTION
                    END SELECT
            END IF

        CASE %WM_COMMAND
            ' Process control notifications
            SELECT CASE AS LONG CB.CTL
                CASE %IDC_TEXTBOX1
                    IF CB.CTLMSG = %EN_CHANGE THEN
                        CONTROL GET TEXT CBHNDL, %IDC_TEXTBOX1 TO txtv
                        IF ISTRUE INSTR(txtv, $CRLF) THEN
                            CONTROL HIDE CBHNDL, %IDC_TEXTBOX1
                            txtv = REMOVE$(txtv, $CRLF)
                            LISTVIEW SET TEXT CBHNDL, %IDC_LISTVIEW1, LVRow + 1,  LVCol + 1, txtv
                        END IF
                    END IF
            END SELECT
    END SELECT

END FUNCTION

FUNCTION SampleListView(BYVAL hDlg AS DWORD, BYVAL lID AS LONG, BYVAL lColCnt _
    AS LONG, BYVAL lRowCnt AS LONG) AS LONG
    LOCAL lCol   AS LONG
    LOCAL lRow   AS LONG
    LOCAL lStyle AS LONG

    LISTVIEW GET STYLEXX hDlg, lID TO lStyle
    LISTVIEW SET STYLEXX hDlg, lID, lStyle OR %LVS_EX_FULLROWSELECT OR _
        %LVS_EX_GRIDLINES

    ' Load column headers.
    FOR lCol = 1 TO lColCnt
        LISTVIEW INSERT COLUMN hDlg, lID, lCol, USING$("Column #", lCol), 0, 0
    NEXT lCol

    ' Load sample data.
    FOR lRow = 1 TO lRowCnt
        LISTVIEW INSERT ITEM hDlg, lID, lRow, 0, USING$("Column # Row #", _
            lCol, lRow)
        FOR lCol = 1 TO lColCnt
            LISTVIEW SET TEXT hDlg, lID, lRow, lCol, USING$("Column # Row #", _
                lCol, lRow)
        NEXT lCol
    NEXT lRow

    ' Auto size columns.
    FOR lCol = 1 TO lColCnt
        LISTVIEW FIT HEADER hDlg, lID, lCol
    NEXT lCol
END FUNCTION

FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    LOCAL lRslt AS LONG
    LOCAL hDlg  AS DWORD
    DIALOG NEW PIXELS, hParent, "Very Simple Editable Listview", , , _
        768, 372, %WS_POPUP OR %WS_BORDER OR %WS_DLGFRAME OR %WS_SYSMENU OR _
        %WS_MINIMIZEBOX OR %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME _
        OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, _
        %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR %WS_EX_LTRREADING OR _
        %WS_EX_RIGHTSCROLLBAR, TO hDlg
    CONTROL ADD LISTVIEW, hDlg, %IDC_LISTVIEW1, "", 20, 20, 730, _
        330, %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %LVS_REPORT OR _
        %LVS_SHOWSELALWAYS, %WS_EX_LEFT
    CONTROL SET COLOR hDlg, %IDC_LISTVIEW1, %BLACK, RGB(225, 225, 255)
    CONTROL ADD TEXTBOX,  hDlg, %IDC_TEXTBOX1, "", 590, 0, 160, 20, %WS_CHILD _
        OR %WS_VISIBLE OR %WS_TABSTOP OR %ES_LEFT OR %ES_AUTOHSCROLL OR %ES_MULTILINE OR %ES_WANTRETURN OR %ES_AUTOVSCROLL, _
        %WS_EX_LEFT OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR
    CONTROL HIDE hDlg, %IDC_TEXTBOX1

    SampleListView hDlg, %IDC_LISTVIEW1, 7, 30

    DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
    FUNCTION = lRslt
END FUNCTION
                                                                                               
-Regards
Peter

Klaas Holland

#6
This is the SDK version build with FF-PB, but I did not get it converted to FF-FB jet.

David Kenny

Very nice Klaas!

Did you start with a DDT example and convert it to SDK yourself or build from scratch? 


Peter,

Klaas saved you a bunch of work man.  This looks to me like it could easily be adapted to your needs.

James Fuller

The issue I have with most of these ListView/Grid attempts is the lack of multiline headers.
Jose did have an example but I believe it failed with more than one listview in a window.
I hope Paul will have multi-line header text  in the FreeBasic grid he said he is working on.
This is a Report mode based on Patrice's(?) code for manipulating the header font.

James

Petrus Vorster

Klaas, this is a neat piece of work!!!
I am very impressed!!!
Thanks a million.
Now show me another forum on the internet with help and support like this!!!

Problem solved! Will give due credits!!!!!!
-Regards
Peter

Paul Squires

Quote from: Klaas Holland on May 11, 2015, 06:16:28 PM
This is the SDK version build with FF-PB, but I did not get it converted to FF-FB jet.
Hi Klaas,

If you post your FreeBasic version then I will help fix it for you.
Paul Squires
PlanetSquires Software

Petrus Vorster

#11
Man, this tool works like a charm!
So easy!
I am very impressed.
For now PB is fine, haven't really thought about doing a project in FB.

Nice thing about this is the listview headers in the Project is in Dutch which of course is mostly the same as my language.
Kind of making it feel like a very personalized help!

Full marks!
-Regards
Peter

Eddy Van Esch

Klaas,
thanks a lot for your fine example! This is really what I needed. ListViews are new to me and I didn't know where to start!

Something I noticed, when clicking on an item in column 2, a textbox appears on the cell, but I can not type any text in it. When I type a character I hear a 'ping' sound (some kind of windows sound message).
In column 4 I can type text in the ListView textbox and when I hit ENTER key, the text is stored in the LV. So that works as advertised.  :)
Thanks again!

Kind regards
Eddy

Eddy Van Esch

AAARRGGGHHH  ;D  Silly me! I typed text characters in the edit box while only numbers are allowed !!!!!   ::)  :o   ;D

Kind regards
Eddy

David Kenny

Klaas,

I have a bug report for your sample listview.  When running the program, change a column width so that you get a horizontal scrollbar to appear.  If you put either column 2 or 4 into edit mode and then scroll the horizontal scrollbar, you will get drawing artifacts as the edit box is not moving also.  Similar results when using the combobox.  You can quick-fix that by adding %WM_HSCROLL to the case under the FORMT1_LISTVIEW1_CUSTOM function.

Another bug would be that none of the controls are aware that the column they are drawn over might change in size. Or might get "off it's column" when another column is being resized.

Personally, I think I would try updating the controls location and size for all scroll and columnsize events and see if I couldn't keep the edit going instead of just ending it.  Although I do think it should be ended if it is pushed out of view by a scrolling or a columnsize event. But I'll put off working on those features for the next time I need an editable ListView. ;)