Jump to content

Using controls to edit cells in a listview


LarsJ
 Share

Recommended Posts

It's exactly the kind of mistake I'm looking for here in the first version. Thank you. I had forgot all about the $LVS_EX_HEADERDRAGDROP extended style to rearrange columns.

Zip in first post updated. $LVS_EX_HEADERDRAGDROP extended style is added to all listviews and the code is updated so that it actually works. For the examples with the edit box I've retained the old scripts. Then you can compare the code and see how easy it is to add support for the $LVS_EX_HEADERDRAGDROP style.

And it's easy because the code is based on $iSubItem to handle columns. A command like _GUICtrlListView_GetItemText( $hWnd, $iIndex [, $iSubItem = 0] ) with $iSubItem = 0 can be used to get the text of an item in first column. If the first column is dragged to another position you still use $iSubItem = 0 to get the text. This means that you don't have to change anything in the code. Rearranging the columns is handled internally by the code in ComCtl32.dll.

In the examples with keyboard support _GUICtrlListView_GetColumnOrderArray is used to get the left-to-right order of the columns. This is necessary to select the current cell properly in column order with left/right arrow keys (and not in a more or less random $iSubItem order if the columns have been rearranged).

I'll test the code more carefully over the weekend for any unforeseen side effects.

Link to comment
Share on other sites

$LVS_EX_HEADERDRAGDROP: Introduced $aColumnOrderReverse in order to avoid looping through $aColumnOrder too many times.

A few lines of code are added to better support usage of the keyboard. The code provides for horizontal scrolling of the ListView to make sure that a subitem (or column) is fully visible when it's selected with left or right arrow. Among other things, the code takes into account rearranging and resizing of columns as well as resizing of the GUI and ListView. A new example EditControlKeyboardTenCols.au3 demonstrates the features. Zip in first post is updated.

Windows XP problem. If the first column has been moved to another position, there is a white gap in selected rows immediately to the left of the first column. This is a MicroSoft problem. The problem is corrected in all Windows versions after XP. On XP the issue can be resolved with custom draw code. This custom draw code is not implemented in the examples. The problem is seen in the picture.

DtojqGN.png

Edited by LarsJ
New link, old image
Link to comment
Share on other sites

Added an example with checkboxes, icons and subicons. These visual objects affects the position and width of the text label, and thus the position and width of the control. In particular, if the first column is moved to another position, it affects the width again compared to a listview without checkboxes and icons.

Added more code in order to better be able to handle some of the special situations which are seen in the picture:

2mAvmBl.png

How should a double click in an only partly visible cell along left or right edge be handled? How should a double click in a very narrow cell be handled? In a UDF a function parameter can be used to control the actions. And the @error macro can be used to give feedback.

Added more code in order to better be able to handle cell selection with the keyboard. Among other things, hidden columns with zero width are skipped.

In order to avoid updating the same code in all examples Functions.au3 with common functions is introduced.

With the details in this and previous updates (get new zip in bottom of first post) it should be possible to start coding a UDF.

Edited by LarsJ
New link, old image
Link to comment
Share on other sites

LOL I just spent ages incorporating some of your old code. I have made several modifications to it, but development is suffering from time constraints. What I have is way to messy to post, so I'll give you some new suggestions. You can try them because I can't commit to posting examples at the moment.

You have not accounted for right aligned text. I used padding for the highlighted item to keep everything aligned either right or left. You have to get the alignment from the listview column before taking any action and reset it afterwards. I also added margins to the edit control and set alignment for this control too. It's not so difficult to implement, if you wanted to do something like this. Otherwise I will eventually get around to posting an example. Font type and size are also something to consider.

Link to comment
Share on other sites

Also problems occur with the keyboard version when the number of columns has changed.

Edit: I've figured out that I need to update some array variables every time I modify the number of columns. I'm making some progress. I like small snippets like these because it's easier to figure out what's going on.

Edit2: After a change has occurred, calling a function, such as the one below, seems to fix some of the problems. This still needs further investigation. I have been working so much on back end code recently and hardly had time to look at anything else.

; update $aColLeftEdgePosAcc after a change has occured
Func _GetColStartPos()
    Local $aOrder = _GUICtrlListView_GetColumnOrderArray($hListView)
    Dim $aColLeftEdgePosAcc[$aOrder[0]]

    Local $iLeft = 0
    $aColLeftEdgePosAcc[0] = $iLeft
    For $i = 1 To $aOrder[0]
        $aColLeftEdgePosAcc[$aOrder[$i]] = $iLeft + _GUICtrlListView_GetColumnWidth($hListView, $aOrder[$i-1])
        $iLeft = $aColLeftEdgePosAcc[$aOrder[$i]]
    Next
EndFunc

I'm still trying to figure out what every part of your code does. ;)

Edited by czardas
Link to comment
Share on other sites

czardas, I've seen your last update 5 minutes ago, so I have not looked into it yet.

A quick update: Added an example with right aligned text. Added an example where you can delete/insert columns (right click in header). I'll check the code more thoroughly during the week. Font name and size will be handled in the UDF. New zip in first post.

Let me know if there are more of these kinds of problems.

Link to comment
Share on other sites

I'm currently trying to get the basics of a CSV editor working, including some very basic bookkeeping and search features. Then I'm going to use the unfinished program to catch up with some deadlines I have. For this reason I'm using the code I started with earlier, so I can implement the features I need as quickly as possible. I am coming across these kinds of problems, reporting them and patching everything as I go.

The features I will include are as follows: [actions = overwrite|insert|delete|sort|drag]
headers: rename
columns: insert, delete, drag
rows: insert, delete, sort, cut, paste [copy]
cell: edit

Copying selected records will place CSV on the clipboard. I intend to include an undo buffer, sorting (also by date) and search features. There will be some settings so you can tweak it, just a bit. :) For example, forcing two decimal places when appending an accumulative balance column to the right. I like the simplicity of CSV. The idea of a reset function (shown above) needs more work. There must be ways to keep everything on track regardless of what the user does to the listview.

Edited by czardas
Link to comment
Share on other sites

czardas, It seems to be a larger project that you're doing.

Quick updates can be dangerous. Corrected a few errors in EditControlKeyboardColumns.au3 (delete/insert columns, right click in header). New zip in first post.

Link to comment
Share on other sites

13 hours ago, LarsJ said:

Quick updates can be dangerous.

I appreciate this and don't expect you to do anything particularly to suit my needs. I have already added some column header code to my program with several sorting options, as well as the new features you mention above. I am ready to use my program to do my accounts, but it's far from finished: undo features (which can mostly be done manually) need implementing. It's great being able to slice and dice in a ListView, and your examples have given me lots of fresh ideas. ;)

I don't tend to use Excel or Access because these programs are overkill for my needs. I just want to hit a hotkey (or accelerator) and watch the magic happen without having to think of any formulas. Searching within a DB should be as easy as using ebay. Huge learning curves can be a big disincentive for small businessmen and the files created by MS Office applications cannot easily be read on other systems: there are plenty of reasons for me to make my program. Although it's quite limited, it does have the advantage of being portable. :)

I'll post the code when I have finished.

Edited by czardas
Link to comment
Share on other sites

  • 4 months later...

There still appear to be problems associated with scrolling a large number of columns using the keyboard. I didn't get around to looking at this earlier because I've been mainly working on back end stuff. Attempts to integrate your current version were not entirely satisfactory.

You can see the problem if you modify EditControlKeyboardTenCols.au3 and set it to generate 100 columns. It appears that an additional scroll action is taking place when using the arrow keys (I suppose this is standard scrollbar behaviour). I think that may be interfering with reading the precise horizontal scroll position - this is just a theory. Also try scrolling manually off screen with the mouse, then hit the left or right arrow key and see what happens.

I'm currently using this when a column goes off screen:

Func ShowColumn($hListView, $iSubItem)
    ; If $iSubItem = 0 Then Return ; specific to czardas' current project
    Local $iLvWidth = WinGetClientSize( $hListView )[0]
    Local $aRect = _GUICtrlListView_GetSubItemRect( $hListView, $iItem, $iSubItem )

    If $aRect[0] < 0 Then
        _GUICtrlListView_Scroll($hListView, $aRect[0], 0)
    ElseIf $aRect[2] > $iLvWidth Then
        _GUICtrlListView_Scroll($hListView, $aRect[2] - $iLvWidth, 0)
    EndIf
EndFunc ;==> ShowColumn

I commented out the first line of the function because it is only relevant to my project: I am hiding the first column and dealing with it independently. Column 0 could cause problems with the code above (untested with your examples). The logic is not much different to MakeColumnVisible().

 

In case anyone was wondering, $iItem is declared as a global variable in the main code.

Edited by czardas
code simplification
Link to comment
Share on other sites

After holding down the left or right arrow keys for a period, the scroll bar continues to update after the key is released. These scroll actions are queued and are occurring after you set the position. If there was a way to interfere with these messages, it might be possible to set the scrollbar position accurately. Horizontal scrolling should work the same as vertical scrolling: with the scroll bar remaining static until the selection goes off screen.

Edited by czardas
Link to comment
Share on other sites

czardas, I think I've addressed most of the issues in the zip below. The issues are:

  • When the marked cell (cyan) is moved with the left/right arrow keys the standard 5 pixel horizontal scroll is suppressed. Use shift+left/right to perform this 5 pixel scroll.
  • Use ctrl+left/right to move the marked cell horizontally a page at a time. The new marked cell is always aligned to the left edge of the listview.
  • If the marked cell is outside the visible part of the listview (because the listview has been scrolled with the mouse) and Enter, left/right or ctrl+left/right is pressed, the marked cell is scrolled into the visible part of the listview.
  • If the marked cell is not completely visible along left/right edge of the listview when you press Enter to edit the cell, the cell is scrolled into a completely visible position.
  • Calculations are based on listview subitem rectangle instead of scrollbar position as you have proposed.

The zip contains EditControlKeyboardTenCols.au3 (100 columns) and TenColumns.au3 (100 columns) which I've used to verify the behavior of a standard listview.

Zip in first post is not updated. I'll go through the code more carefully and update the zip.

ListViewEditingCells.7z

Edited by LarsJ
Link to comment
Share on other sites

  • 6 months later...

It's been a while since I looked at this. Disclaimer: an older version of your code is now intertwined in my program along with several modifications. Having said that, you might want to check (and consider) what I have discovered after playing around with your code. For a while I was getting problems with arrow key navigation and general functionality. I couldn't trace the problem and continued to work on other aspects of my program in the mean time. It seemed to be a random occurence and I thought it was happening while spamming the keyboard, but this may not be the case because . . .

Yesterday I discovered something new. When a child GUI has focus (and I imagine other controls too), hitting the Enter key was triggering the problem. The old version I am using has three Globals : $bEditOpen, $bEditDoNotOpen and $bEditEscape. If I reset these globals (to the default values = False) immediately after closing the child GUI, it seems to fix the problem. Previously I also found that the problem sometimes remained after closing the program and required a complete reboot to get the thing working again. So you might want to take a look at this.

Reproducer on the way: I need to restart my PC right now.

Func KillIt()
    MsgBox(0, "Kill It", "Press Escape or Enter")
EndFunc

Actually I have just discovered that I can reset initial conditions without a reboot, however it took me a while to figure it out. I don't know if the same problem exists with the current keyboard version. With the ListView running, call the above function using an accelerator key (as I did) or by other means. Follow the instructions and see if you can still navigate the listview using the left and right arrow keys after the message box has disappeared. If not, then you might want to think about checking control focus before making changes (just a suggestion).

Edited by czardas
Link to comment
Share on other sites

There is certainly an issue. I've added an accelerator key (ctrl+b, opens MsgBox) to the code in EditControlKeyboardTenCols.au3 in the zip-file in post 33. The problem is quite clear.

It's correct that the solution is to reset the Edit control variables. In the code in post 33 four variables have to be reset. There is also a $bControl variable. And the variables must be reset in the $NM_KILLFOCUS section when the ListView loses focus.

The zip file contains a new version of EditControlKeyboardTenCols.au3 with the MsgBox and updated code to correct the error. The old version is also added, as well as a file fc.txt that shows the difference between the two versions. Then it should be possible to make the same updates in your own code.

ListViewEditingCells.7z

Edited by LarsJ
Link to comment
Share on other sites

Thanks, I appreciate you making the effort to update a previous version just for my benefit. That wasn't necessary, but it certainly will help me continue with my own project. I would have reported this earlier if I had been able to pin down the issue. Rewriting the ListView editing code was a last priority for me, since it was already working (albeit a little unstable). Now that I know the cause of the problem, it should be a lot easier to resume work on this. :)

Edited by czardas
Link to comment
Share on other sites

  • 1 year later...

Hello,

  I recently started playing around with this code and i'm trying to make a slight modification to it.  I would like to be able to 'click/drag' to 'highlight' item/subitem text within any cell and have it automatically be sent to clipboard ('Ctrl-C' for example).  I believe that I need to modify the "EditCallback" function in order to accomplish that (the send to clipboard 'Ctrl-C' part)...however I get some nasty crashes when attempting it...for example if I try to add a "Case $WM_LBUTTONCLK" or a "Case $WM_LBUTTONUP" before the "Case $WM_LBUTTONDBLCLK" that is already there within that function...is there a way to accomplish this...?   I thank you in advance for any suggestions somebody might have.  Regards. 

Link to comment
Share on other sites

This feature more or less already exists. When you double-click a listview cell in EditControlMouse.au3, a standard edit control opens. This edit control supports copy/paste. But you have to type ctrl+c yourself.

Link to comment
Share on other sites

Hello,

  Thanks for the reply.  I did see that a 'right click' does allow a 'Copy/Cut' operation and then the ComboBox in the cell immediately closes...I was hoping to be able to inject some code to automate that and keep the ComboBox open.  I guess I could also add a button or something like that...but I was hoping for a totally automated way without the user making an extra step to press a button or manually press 'Ctrl-C'.  Thanks again.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...