Hi there
I have been translating a program I wrote using EZGUI to FireFly. A function I can't seem to translate is EZ_GetLVClickInfo which would give me the position and size of the cell I clicked in. I would then superimpose a properly sized textbox over the cell making it look like a grid.
Does anybody have a method of finding the cell and it's size?
Tried using the API but it's like chinese with English words
thanx
bert
This can be done as I've done it with FireFly using a ListView which from the EZGUI name looks like what he is using. Looks like his function just pulled data from the Notification message of the ListView. I don't have my code in front of me, but I believe I did it that way too, or used a ListView API function to get the bounds of the cell. Usually takes a 1-3 pixel adjustment too since the control placing in the grid has borders and such, but it can look pretty sharp, and FireFly made it really easy. I was able to use Combos and Edit/Text boxes.
Look for LVM_ messages like LVM_GETITEMRECT in google, and it will usually find the MSDN help and you'll then see a whole list of other commands to get column and row sizes, etc in the left sidebar.
Here is a quick example.... based somewhat on the code posted at: http://www.planetsquires.com/forums/viewtopic.php?t=1764
FireFly 3 will have substantially improved ListView and TreeView support.
Notice that I use a PostMessage in the LVM_ITEMCHANGING because we don't want to get into an endless loop by updating text during that message.
%MSG_USER_ENDLISTVIEWEDIT = %WM_USER + 100
Type LISTVIEW_TEXTEDIT
hTextBox As Dword
nRow As Long
nCol As Long
End Type
Global gListviewEdit As LISTVIEW_TEXTEDIT
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_WM_CREATE ( _
hWndForm As Dword, _ ' handle of Form
ByVal UserData As Long _ 'optional user defined Long value
) As Long
FF_ListView_DeleteAllItems HWND_FORM1_LISTVIEW1
FF_ListView_InsertColumn HWND_FORM1_LISTVIEW1, 0, "Column1", 0, 100
FF_ListView_InsertColumn HWND_FORM1_LISTVIEW1, 1, "Column2", 0, 100
FF_ListView_InsertColumn HWND_FORM1_LISTVIEW1, 2, "Column3", %LVCFMT_RIGHT, 100
For row& = 0 To 10
For col& = 0 To 2
FF_ListView_InsertItem HWND_FORM1_LISTVIEW1, row&, col&, Str$(row&) & Str$(col&), 0, 0
Next
Next
End Function
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_CUSTOM (hWndForm As Dword, wMsg As Long, wParam As Dword, lParam As Long) As Long
Local pNmLvw As NM_LISTVIEW Ptr
Local lLvItem As Long
Local lLvSubItem As Long
Local rectSub As Rect
Local lEditRow As Long
Local lEditCol As Long
Local hEdit As Dword
Local strTextCell As String
Select Case wMsg
Case %WM_NOTIFY
Select Case LoWrd(wParam)
Case IDC_FORM1_LISTVIEW1
pNmLvw = lParam
If (@pNmLvw.hdr.code = %NM_DBLCLK) And (@pNmLvw.iItem > -1) Then ' doubleclick in listview
lLvItem = @pNmLvw.iItem
lLvSubItem = @pNmLvw.iSubItem
' Act on the column doubleclicked
Select Case lLvSubItem
Case 0
MsgBox "Column 0 locked"
Case 1
GoSub EditCell
Case 2
MsgBox "Column 2 locked"
End Select
End If
End Select
Case %MSG_USER_ENDLISTVIEWEDIT
CancelListviewEdit
End Select
Exit Function
EditCell:
lEditRow = lLvItem
lEditCol = lLvSubItem
' Is the cell selected
If IsTrue(ListView_GetItemState(HWND_FORM1_LISTVIEW1, lEditRow, %LVIS_SELECTED)) Then
' get the rect of the subitem
ListView_GetSubItemRect HWND_FORM1_LISTVIEW1, lEditRow, lEditCol, %LVIR_LABEL, VarPtr(rectSub)
'prüfen ob bereits ein hEdit besteht
If IsWindow(gListviewEdit.hTextBox) Then DestroyWindow(gListviewEdit.hTextBox)
' Save the cell info
gListviewEdit.nRow = lEditRow
gListviewEdit.nCol = lEditCol
' Create the Edit1 edit control
gListviewEdit.hTextBox = CreateWindowEx( %WS_EX_LEFT, _ ' extended styles
"Edit", _ ' class name
"", _ ' caption
%WS_CHILD Or %WS_VISIBLE Or %ES_LEFT Or %ES_AUTOHSCROLL Or %ES_NOHIDESEL , _ ' class styles
rectSub.nLeft + 6, rectSub.nTop, _ ' left, top
rectSub.nRight - rectSub.nLeft, rectSub.nBottom - rectSub.nTop, _ ' width, height
HWND_FORM1_LISTVIEW1, 9999, _ ' handle of parent, control ID
GetModuleHandle(ByVal %Null), ByVal %Null) ' handle of instance, creation parameters
'setze Font für EditControl
SendMessage gListviewEdit.hTextBox, %WM_SETFONT, GetStockObject(%DEFAULT_GUI_FONT), %TRUE
ShowWindow gListviewEdit.hTextBox, %SW_SHOWNORMAL
SetFocus gListviewEdit.hTextBox
'Text aus Listview Zelle in EditControl
strTextCell = FF_ListView_GetItemText (HWND_FORM1_LISTVIEW1, lEditRow, lEditCol)
FF_TextBox_SetText gListviewEdit.hTextBox, strTextCell
FF_TextBox_SetSel gListviewEdit.hTextBox, 0, -1
End If
Return
End Function
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_LISTVIEW1_LVN_ITEMCHANGING ( _
ControlIndex As Long, _ ' index in Control Array
hWndForm As Dword, _ ' handle of Form
hWndControl As Dword, _ ' handle of Control
ByVal lpNMV As NM_LISTVIEW Ptr _ ' pointer to NM_LISTVIEW
) As Long
' Cancel any edit of a Listview label
PostMessage hWndForm, %MSG_USER_ENDLISTVIEWEDIT, 0, 0
End Function
'------------------------------------------------------------------------------------------------------------------------
Function CancelListviewEdit() As Long
Local sText As String
If gListviewEdit.hTextBox = 0 Then Exit Function
' If the Listview's editing textbox exists then we
' need to get its text and update the Listview and then destroy it.
sText = FF_TextBox_GetText( gListviewEdit.hTextBox )
FF_ListView_SetItemText HWND_FORM1_LISTVIEW1, gListviewEdit.nRow, gListviewEdit.nCol, sText
DestroyWindow gListviewEdit.hTextBox
gListviewEdit.hTextBox = 0
End Function
Same question...almost a year before??? Looks like more work than I did in my code, but it'll work. I'll post mine if I can find it.
It is the same question. Just never could get the code working properly with my program. I seemed to work the first time then go somewhere in deep space. Lack of time and understanding how the code worked, I ended up leaving the project on the shelf. Now back at trying it again.
With the extra code maybe it will work for me. I am just not very good when it comes down to events. Can't get away from linear thinking.
Bert
Quote from: mercierbI am just not very good when it comes down to events. Can't get away from linear thinking.
I hear you loud and clear! I had a hell of time trying to get out of that mode of thinking. Wow! It seemed to take forever and then one day it "just clicked" (get it? "clicked", ha ha ha ha). :) Seriously, it takes a different way of thinking realizing that anything can happen at anytime. Scary really. ;)
Believe me, it hasn't clicked with me.
Now for another stupid question.
How would I access the events like WM_CHAR of that new edit control?
I want to intercept the Enter key to terminate the edit and give the focus to another part of the program.
Bert
I am about ready to go to bed... I'll round up an example in the morning.
The best way to handle this would be to create a TextBox on your Form and set its WS_VISIBLE to False. Move that TextBox into place on your ListView and the show it. When you're finished with the TextBox, HIDE it rather than DESTROY it. Using a Firefly created TextBox allows you to respond to the WM_CHAR messages because FireFly automatically subclasses the TextBox for you. You can subclass the TextBox yourself but it is a little more work.
I'll post an example of what I mean as soon as I can.
Goodnight forgot how late it would be in Newfoundland
thanx
again
Below is the code. It is fairly easy to do with FireFly. The editing is finished when the %VK_RETURN or %VK_ESCAPE keys are triggered in the WM_KEYUP message.
You will need to add a TextBox to your Form (name it "txtListviewEdit") and set the following properties:
WS_VISIBLE unchecked
WS_EX_CLIENTEDGE unchecked
SelText = True
%MSG_USER_ENDLISTVIEWEDIT = %WM_USER + 100
Type LISTVIEW_TEXTEDIT
hTextBox As Dword
nRow As Long
nCol As Long
End Type
Global gListviewEdit As LISTVIEW_TEXTEDIT
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_WM_CREATE ( _
hWndForm As Dword, _ ' handle of Form
ByVal UserData As Long _ 'optional user defined Long value
) As Long
FF_ListView_DeleteAllItems HWND_FORM1_LISTVIEW1
FF_ListView_InsertColumn HWND_FORM1_LISTVIEW1, 0, "Column1", 0, 100
FF_ListView_InsertColumn HWND_FORM1_LISTVIEW1, 1, "Column2", 0, 100
FF_ListView_InsertColumn HWND_FORM1_LISTVIEW1, 2, "Column3", %LVCFMT_RIGHT, 100
For row& = 0 To 10
For col& = 0 To 2
FF_ListView_InsertItem HWND_FORM1_LISTVIEW1, row&, col&, Str$(row&) & Str$(col&), 0, 0
Next
Next
End Function
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_CUSTOM (hWndForm As Dword, wMsg As Long, wParam As Dword, lParam As Long) As Long
Local pNmLvw As NM_LISTVIEW Ptr
Local lLvItem As Long
Local lLvSubItem As Long
Local rectSub As Rect
Local lEditRow As Long
Local lEditCol As Long
Local hEdit As Dword
Local strTextCell As String
Select Case wMsg
Case %WM_NOTIFY
Select Case LoWrd(wParam)
Case IDC_FORM1_LISTVIEW1
pNmLvw = lParam
If (@pNmLvw.hdr.code = %NM_DBLCLK) And (@pNmLvw.iItem > -1) Then ' doubleclick in listview
lLvItem = @pNmLvw.iItem
lLvSubItem = @pNmLvw.iSubItem
' Act on the column doubleclicked
Select Case lLvSubItem
Case 0
MsgBox "Column 0 locked"
Case 1
GoSub EditCell
Case 2
MsgBox "Column 2 locked"
End Select
End If
End Select
Case %MSG_USER_ENDLISTVIEWEDIT
CancelListviewEdit
End Select
Exit Function
EditCell:
lEditRow = lLvItem
lEditCol = lLvSubItem
' Is the cell selected
If IsTrue(ListView_GetItemState(HWND_FORM1_LISTVIEW1, lEditRow, %LVIS_SELECTED)) Then
' get the rect of the subitem
ListView_GetSubItemRect HWND_FORM1_LISTVIEW1, lEditRow, lEditCol, %LVIR_LABEL, VarPtr(rectSub)
' Save the cell info
gListviewEdit.hTextBox = HWND_FORM1_TXTLISTVIEWEDIT
gListviewEdit.nRow = lEditRow
gListviewEdit.nCol = lEditCol
' Get the text from the Listview cell and place it in the textBox
strTextCell = FF_ListView_GetItemText (HWND_FORM1_LISTVIEW1, lEditRow, lEditCol)
FF_TextBox_SetText gListviewEdit.hTextBox, strTextCell
FF_TextBox_SetSel gListviewEdit.hTextBox, 0, -1
' Move the TextBox into position.
' Recalculate the Listview cell position based on coordinates of the Form. This
' saves us from having to make the TextBox the child of the Listview.
MapWindowPoints HWND_FORM1_LISTVIEW1, HWND_FORM1, rectSub, 2
SetWindowPos gListviewEdit.hTextBox, %HWND_TOP, _
rectSub.nLeft + 6, rectSub.nTop, _
rectSub.nRight - rectSub.nLeft, rectSub.nBottom - rectSub.nTop, _
%SWP_SHOWWINDOW
SetFocus gListviewEdit.hTextBox
End If
Return
End Function
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_LISTVIEW1_LVN_ITEMCHANGING ( _
ControlIndex As Long, _ ' index in Control Array
hWndForm As Dword, _ ' handle of Form
hWndControl As Dword, _ ' handle of Control
ByVal lpNMV As NM_LISTVIEW Ptr _ ' pointer to NM_LISTVIEW
) As Long
' Cancel any edit of a Listview label
PostMessage hWndForm, %MSG_USER_ENDLISTVIEWEDIT, 0, 0
End Function
'------------------------------------------------------------------------------------------------------------------------
Function CancelListviewEdit() As Long
Local sText As String
If gListviewEdit.hTextBox = 0 Then Exit Function
' If the Listview's editing textbox exists then we
' need to get its text and update the Listview and then destroy it.
sText = FF_TextBox_GetText( gListviewEdit.hTextBox )
FF_ListView_SetItemText HWND_FORM1_LISTVIEW1, gListviewEdit.nRow, gListviewEdit.nCol, sText
ShowWindow gListviewEdit.hTextBox, %SW_HIDE
End Function
'------------------------------------------------------------------------------------------------------------------------
Function FORM1_TXTLISTVIEWEDIT_WM_KEYUP ( _
ControlIndex As Long, _ ' index in Control Array
hWndForm As Dword, _ ' handle of Form
hWndControl As Dword, _ ' handle in Control
nVirtKey As Long, _ ' virtual key code
lKeyData As Long _ ' key data
) As Long
Select Case nVirtKey
Case %VK_RETURN, %VK_ESCAPE
CancelListviewEdit
End Select
End Function
Thanx the code does work I adjusted the width and height a little bit because it hid the grid line.
The only problem I have is that if I move the mouse pointer some where else on the grid the textbox loses its focus.
example:
I hilite cell row 10 col 2
If I move the mouse pointer toward row 9 to 0 the text box stays in focus
If I move toward row 11 the text box loses focus and the listview background shows.
Any idea
thanx
bert
You must have other code somewhere in there that is responding to a WM_MOUSEMOVE message or similar ???? The example code that I posted does not exhibit the behaviour that you are describing. I can move the mouse anywhere over the Listview and the TextBox always keeps focus. It loses focus if a different cell in the Listview is clicked.
I couldn't find code. But I deleted the lisview and the associated code. Then reinstall and it worked must have been a check ark somewhere. Now everything works. Again thanx for the help.
Bert
One question.
I noticed you put the code in KeyUp
Is there a reason to use it there instead of KeyDown?
Just curious
Bert
Last event fired for the key...less likely to misfire another event when Up event is triggered after it. Also in some cases maybe the user wants to cancel much like a button press- If you go to click a button then at that last split second decide not to you can move off the button and then release...then since no MouseUp on the button it is canceled.