No announcement yet.

PBDLL: Label Editing in Listview Control

  • Filter
  • Time
  • Show
Clear All
new posts

  • PBDLL: Label Editing in Listview Control


    i'm learning to use listview control from pb/dll. based on examples from these forums - mainly i have used peter redei's posting

    pddll5: generic listview example

    i have come up with following test program

    <font face="courier new, courier" size="3"><pre>

    ' testing listview common control
    ' based on sample by peter redei
    ' include file "listview.bas" can be found in peter's posting
    ' pddll5: generic listview example
    ' ** eliminate unnecessary macros
    %noanimate = 1
    %nodraglist = 1
    %noheader = 1
    %noimagelist = 1
    '%nolistview = 1
    %notabcontrol = 1
    %notrackbar = 1
    %notreeview = 1
    %noupdown = 1

    #compile exe
    #include ""
    #include ""
    #include "listview.bas"

    %idok = 1
    %idlistview = 101

    global hlistview as long
    global lviewsort as integer

    function compare(byval lparam1 as long, byval lparam2 as long, byval lparamsort as long) as integer
    ' written by peter redei

    local value1 as asciiz * 300
    local value2 as asciiz * 300
    local j as integer

    value1 = retrievelvdata(hlistview, lparam1, lparamsort)
    value2 = retrievelvdata(hlistview, lparam2, lparamsort)

    select case lviewsort
    case 0 'ascending
    j = 1
    case else 'descending
    j = -1
    end select

    if value1 < value2 then
    function = -1 * j
    elseif value1 = value2 then
    function = 0
    function = 1 * j
    end if
    end function

    callback function okbutton_proc()
    dialog end cbhndl, 0
    end function

    callback function dialog_proc()
    local hdlg as long
    local my_lplvnm as nm_listview ptr
    local stext as string

    hdlg = cbhndl
    select case cbmsg
    case %wm_notify
    select case lowrd(cbwparam)
    case %idlistview
    my_lplvnm = cblparam
    select case @my_lplvnm.hdr.code
    case %lvn_endlabeledit
    msgbox "done editing!"
    case %lvn_columnclick
    if (@my_lplvnm.isubitem <> -1) then
    'toggle ascending/descending
    lviewsort = not lviewsort
    listview_sortitems hlistview, _
    codeptr(compare), _
    'lparam was set to the original 'recordnumber'
    'now this changed, we need to set it to the new position
    resetlparam hlistview
    end if
    case %nm_dblclk
    stext = retrievelvdata(hlistview, @my_lplvnm.iitem, @my_lplvnm.isubitem)
    msgbox stext,48,"just for test purposes"
    end select
    end select
    end select
    end function

    function pbmain () as long

    $register none

    local hdlg as long
    local icc as init_common_controlsex
    local r as long
    local c as long
    local lstyle as long
    %numcols = 5
    %numrows = 20
    local ldata as listdata
    dim rec(%numcols) as string

    ' init listview control
    icc.dwicc = %icc_listview_classes
    icc.dwsize = sizeof(icc)
    initcommoncontrolsex icc

    ' create a new dialog template
    dialog new 0, "listview test", ,, 315, 182, 0, 0 to hdlg

    ' add controls to it
    control add "syslistview32", _
    hdlg, %idlistview,", _
    0,0,315,161, _
    %ws_border or %ws_child or %ws_visible or %ws_tabstop or _
    %lvs_report or %lvs_showselalways or %lvs_editlabels, _

    control add button, _
    hdlg, %idok, "&ok", _
    137, 164, 40, 14, _
    %ws_tabstop _
    call okbutton_proc

    ' set some extended style flags for listview control
    control handle hdlg,%idlistview to hlistview
    lstyle = sendmessage(hlistview, %lvm_getextendedlistviewstyle, 0, 0)
    lstyle = lstyle or %lvs_ex_fullrowselect or %lvs_ex_gridlines
    call sendmessage(hlistview, %lvm_setextendedlistviewstyle, 0, byval lstyle)

    ' set column headers
    ldata.columns = %numcols
    ldata.fields(0).fname = "item #"
    ldata.fields(0).size = 90
    for c = 1 to %numcols - 1
    ldata.fields(c).fname = "property #" + format$(c)
    ldata.fields(c).size = 90
    ldata.fields(c).alignment = %lvcfmt_left
    setlistview hlistview, ldata

    ' show random data
    for r = 1 to %numrows
    rec(0) = format$(1000+r)
    for c = 1 to %numcols - 1
    rec(c) = chr$(rnd(asc("a"),asc("z"))) + trim$(str$(rnd(1000,2000)))
    next c
    appendlistview hlistview, rec()
    next r

    ' display the dialog
    dialog show modal hdlg call dialog_proc

    end function


    the lvn_endlabeledit part is the first test in this matter - very incomplete, i know. however, i don't understand why program behaves as it does:

    1. first click on a cell selects the row containing the cell - ok.
    2. second click somewhere on the same row opens edit window in the first column (the item of this row), cell text is entered there and all the text is selected - ok.
    3. a click somewhere outside the edit control shows message "done editing!" (notification message lvn_endlabeledit got processed) and the contents of the item cell do no change - ok.
    4. selecting text in the edit box w/mouse works ok.
    5. selecting text w/keys works ok. also ctrl+c copies text to clipboard.
    6. right clicking w/mouse opens context menu - ok.
    7. try to change the text - keyboard entry, del key etc. - and the program crashes - :-(

    can anybody give me any hints why it does it? there i have an edit window w/focus and can do everything else with it except change it- that i don't understand.

    following is quote from ms' docs.
    a list view control that has the lvs_editlabels window style enables a user to edit item labels in place. the user begins editing by clicking the label of an item that has the focus. alternatively, an application can begin editing automatically by using the lvm_editlabel message. the list view control notifies the parent window when editing begins and when it is canceled or completed. when editing is completed, the parent window is responsible for updating the item's label, if appropriate.

    when label editing begins, an edit control is created, positioned, and initialized. before it is displayed, the list view control sends its parent window an lvn_beginlabeledit notification message. if you need to modify the label editing process, you can implement a handler for this notification.
    the way i read this is that there is no need to implement a handler for lvn_beginlabeledit notification message, i.e. you should be able to edit the text in the edit window right away.

    another quote
    when label editing is canceled or completed, a list view control sends its parent window an lvn_endlabeledit notification message. the lparam parameter is the address of an nmlvdispinfo structure. the item member of this structure is an lvitem structure whose iitem member identifies the item. if editing is canceled, the psztext member of the lvitem structure is null; otherwise, psztext is the address of the edited text. the parent window is responsible for updating the item's label if it wishes to keep the new label.
    again i read this so that if i every time (as in the sample program) want to discard the possible edits, i don't have to do anything.

    lasse rantanen
    [email protected]

  • #2

    done some further digging and found the reason - one of the most bizarre features of Windows' controls.

    In "Listview Bugs and Problems" Ron Burke explains:

    Sure enough, the listview control located this flaw in my code for me, due to an "interesting" part of its design. When I started to edit an item in the listview control, as soon as I pressed a key my dialog disappeared! This was indeed mysterious, and I did a lot of head scratching before I finally realized that somebody was generating a notification for either my IDOK button or my IDCANCEL button. Further inspection revealed that the notification code was either 0x0300 or 0x0400. That's when the awful truth hit me.

    When you edit a listview item, the listview control secretly creates its own edit control, positioned above the item being edited. Apparently, the listview control designer decided it would be nice to pass that edit control's notification messages on to the parent dialog. All well and good, but what control ID should be associated with those notifications? In a better world, the designer might have allocated a new reserved control ID (e.g., ID_LISTVIEWEDIT), adding to the existing reserved IDs such as IDOK and IDCANCEL. Instead, the designer decided just to use IDOK for the control ID of the edit control. After all, the edit control notifications, such as EN_CHANGE (0x0300) and EN_UPDATE (0x0400), happen to lie numerically above any possible button notifications.

    Like so many aspects of the Windows API, this feature of the listview control is not documented. That could indicate Microsoft does not want to guarantee support for the feature in future versions, or it could just be a symptom of the generally incomplete documentation. Either way, be aware that notifications from unrelated controls may be stacked upon your IDOK button -- notifications aren't really guaranteed by the documentation to be there in future versions of the listview control.
    OK, that was my problem, too. I had equate %IDOK=1 in my code. Changing it to %ID_OK=100 gotthings working as expected.

    I hope this will help somebody else struggling with in-place editing.

    Lasse Rantanen
    [email protected]