Announcement

Collapse

Forum Guidelines

This forum is for finished source code that is working properly. If you have questions about this or any other source code, please post it in one of the Discussion Forums, not here.
See more
See less

Very Simple Editable Listview

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • PBWin Very Simple Editable Listview

    ' I would like to compliment PowerBasic for making windows programming
    ' so much simpler thanks to DDT, which has been expanded considerably
    ' in recent versions. This code is made with PBwin10.02.
    '
    ' Editing cells in a listview was previously quite complicated, but using
    ' DDT it can be quite simple as shown in this example. However, if you
    ' want a lot of features, some of the old windows code may still be
    ' necessary.
    '
    ' In this code you click to edit a cell. You end editing by pressing ENTER.
    ' No subclassing is needed for this simple method, which uses some
    ' other tricks like capturing the $CRLF character in the textbox.
    ' To do this, you need these styles to be included for the textbox:
    ' %ES_MULTILINE OR %ES_WANTRETURN OR %ES_AUTOVSCROLL.
    ' Yes, somewhat odd, but it does work! Good Luck.
    '
    ' Best regards,
    '
    ' Erik Christensen ------------- July 30, 2011
    Code:
    ' Very Simple Editable Listview
    '
    ' I would like to compliment PowerBasic for making windows programming
    ' so much simpler thanks to DDT, which has been expanded considerably
    ' in recent versions. This code is made with PBwin10.02.
    '
    ' Editing cells in a listview was previously quite complicated, but using
    ' DDT it can be quite simple as shown in this example. However, if you
    ' want a lot of features, some of the old windows code may still be
    ' necessary.
    '
    ' In this code you click to edit a cell. You end editing by pressing ENTER.
    ' No subclassing is needed for this simple method, which uses some
    ' other tricks like capturing the $CRLF character in the textbox.
    ' To do this, you need these styles to be included for the textbox:
    ' %ES_MULTILINE OR %ES_WANTRETURN OR %ES_AUTOVSCROLL.
    ' Yes, somewhat odd, but it does work! Good Luck.
    '
    ' Best regards,
    '
    ' Erik Christensen  -------------  July 30, 2011
    
    #COMPILE EXE
    #DIM ALL
    
    #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
    Last edited by Erik Christensen; 10 Aug 2011, 06:42 AM.

  • #2
    ' Very Simple Editable Listview
    '
    ' Version 2.

    ' This version uses a rather special method involving a timer to hide the
    ' textbox and abolish editing if for some reason scrolling should occur
    ' during editing. You may have a more elegant method using the listview
    ' notification %LVN_BEGINSCROLL, which I could not get working.
    '
    ' Best regards,
    '
    ' Erik Christensen ------------- July 30, 2011
    Code:
    ' Very Simple Editable Listview
    '
    ' Version 2.
    
    ' This version uses a rather special method involving a timer to hide the
    ' textbox and abolish editing if for some reason scrolling should occur
    ' during editing. You may have a more elegant method using the listview
    ' notification %LVN_BEGINSCROLL, which I could not get working.
    '
    ' Best regards,
    '
    ' Erik Christensen  -------------  July 30, 2011
    
    #COMPILE EXE
    #DIM ALL
    
    #INCLUDE ONCE "WIN32API.INC"
    #INCLUDE ONCE "COMMCTRL.INC"
    #INCLUDE ONCE "PBForms.INC"
    
    %IDD_DIALOG1   =  101
    %IDC_LISTVIEW1 = 1001
    %IDC_TEXTBOX1  = 1002
    %IDC_TIMER1    = 1090
    
    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, SIrectPr AS RECT
        STATIC timerdelay AS DWORD, hTimerdel AS LONG
    
        SELECT CASE AS LONG CB.MSG
            CASE %WM_INITDIALOG
                ' Initialization handler
                CONTROL HANDLE CBHNDL, %IDC_LISTVIEW1 TO hListView
                timerdelay = 200 ' 0.2 sec.
    
            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
                                SetTimer(CBHNDL, BYVAL %IDC_TIMER1, BYVAL timerdelay, BYVAL %NULL)
                                '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))
                                SIrectPr.nLeft = SIrect.nLeft : SIrectPr.nRight = SIrect.nRight
                                SIrectPr.nTop = SIrect.nTop   : SIrectPr.nBottom = SIrect.nBottom
                                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_TIMER
                SELECT CASE AS LONG CBWPARAM
                    CASE %IDC_TIMER1
                        KillTimer CBHNDL, %IDC_TIMER1
                        i = ListView_GetSubItemRect(hListView, LVRow, LVCol, %LVIR_BOUNDS, VARPTR(SIrect))
                        IF SIrectPr.nLeft <> SIrect.nLeft OR SIrectPr.nRight <> SIrect.nRight OR _
                          SIrectPr.nTop <> SIrect.nTop OR SIrectPr.nBottom <> SIrect.nBottom THEN
                            CONTROL HIDE CBHNDL, %IDC_TEXTBOX1
                        ELSE
                            hTimerdel = SetTimer(CBHNDL, BYVAL %IDC_TIMER1, BYVAL timerdelay, BYVAL %NULL)
                        END IF
                END SELECT
    
            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
                                KillTimer CBHNDL, %IDC_TIMER1
                            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 'or %LVS_EX_ONECLICKACTIVATE
    
        ' 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
    Last edited by Erik Christensen; 3 Aug 2011, 04:27 PM.

    Comment


    • #3
      Very nice. One change I made in both examples was
      txtv = Remove$(txtv, $CrLf)
      vice
      txtv = Remove$(txtv, $Cr)

      The latter leaves, I guess, the $Lf, linefeed char in the LV

      Comment


      • #4
        Norm, you are perfectly right. I have changed the code accordingly. Thanks, Erik

        Comment


        • #5
          For code 2 to work optimally in any situation, the line marked below should be inserted.
          Code:
                  CASE %WM_TIMER
                      SELECT CASE AS LONG CBWPARAM
                          CASE %IDC_TIMER1
                              KillTimer CBHNDL, %IDC_TIMER1
                              i = ListView_GetSubItemRect(hListView, LVRow, LVCol, %LVIR_BOUNDS, VARPTR(SIrect))
                              IF SIrectPr.nLeft <> SIrect.nLeft OR SIrectPr.nRight <> SIrect.nRight OR _
                                SIrectPr.nTop <> SIrect.nTop OR SIrectPr.nBottom <> SIrect.nBottom THEN
                                  CONTROL HIDE CBHNDL, %IDC_TEXTBOX1
          ' line to be inserted: ********************************************
                                  InvalidateRect CBHNDL, BYVAL %NULL, %FALSE
          ' *****************************************************************
                              ELSE
                                  hTimerdel = SetTimer(CBHNDL, BYVAL %IDC_TIMER1, BYVAL timerdelay, BYVAL %NULL)
                              END IF
                      END SELECT

          Comment


          • #6
            Code:
            i = ListView_GetSubItemRect(hListView, LVRow, LVCol, %LVIR_BOUNDS,  VarPtr(SIrect))         
            
            To
            
             i = ListView_GetSubItemRect(hListView, LVRow, LVCol, %LVIR_BOUNDS, ByVal VarPtr(SIrect))

            Comment

            Working...
            X