More on column headers - storing the sorted column

Started by mhall, April 04, 2014, 04:12:45 PM

Previous topic - Next topic

mhall

OK,

So I'm still working with the ReportView control and am wondering if there is a way to store which column has been sorted so that this can be reapplied if I update the contents of the control?

When I update the contents of the control, sorting defaults to the first column and the user has to re-click the column header to restore sort.

As I have a number of filtering options for the control contents which update its contents, I was hoping there was a way for me to store which column was sorted and then apply that sort again after updating. Barring that, can I tell in the dialog callback which header was clicked so that I can store that, then pre-sort the array accordingly before updating the control? From what I can see, I cannot tell which header was clicked. I'm using the following TechDB derived code to handle clicks to headers:


         ;Determine Current sorting style: ascending or descending
         style = dialogControlState( requestInfo_Handle,  "ReportView_RequestList", DCSTATE_QUERYSTYLE, "" )
         
         ; If no style is assigned assume ascending
         if style == 0 then style = DCSTYLE_SORTASC
   
         ; Toggle Sort Order
         if style == DCSTYLE_SORTDESC       
             dialogControlState( requestInfo_Handle, "ReportView_RequestList", DCSTATE_REMOVESTYLE, DCSTYLE_SORTDESC )
       dialogControlState( requestInfo_Handle, "ReportView_RequestList", DCSTATE_ADDSTYLE, DCSTYLE_SORTASC )
         elseif style == DCSTYLE_SORTASC
             dialogControlState( requestInfo_Handle, "ReportView_RequestList", DCSTATE_REMOVESTYLE, DCSTYLE_SORTASC )
       dialogControlState( requestInfo_Handle, "ReportView_RequestList", DCSTATE_ADDSTYLE, DCSTYLE_SORTDESC )
         endif


Otherwise, I suppose I could supply a "Sort By ... " right click menu option with sub-menu items for the columns. This would allow me to determine which column to sort by and store it, then read the contents of the control, sort the array by the appropriate column and update the control ...

But is there a better way?

Thanks!
Micheal

Deana

The one based column number of the clicked column is passed to the callback UDF/UDS in the callback's fifth parameter. The event is fired before the indicated column is sorted so the sort direction can be controlled by setting or changing the sort direction style of the control during the callback. Sorting is effectively cancelled by removing both sorting related styles from the control.

Code (winbatch) Select
     
Case MSG_RVHEADER                                 ; ID "ReportView_1"  rvVariable1
       Message('Column Clicked is',MyDialog_ChangeInfo) ; Callback's fifth parameter
       ;Determine Current sorting style: ascending or descending
       style = DialogControlState( MyDialog_Handle,  "ReportView_1", DCSTATE_QUERYSTYLE, "")
       Message('Sort Style',style) ;


The MyDialog_ChangeInfo & Style variables contain the information you are looking for.
Deana F.
Technical Support
Wilson WindowWare Inc.

mhall

Thanks very much for that information Deana - very helpful, as always. I didn't know about that

Is there a way to specify a column to sort a ReportView on programmatically, based on the index of the column? Or is that something I should be prepared to implement via ArraySort()?

Regards,
Micheal

Deana

Quote from: mhall on April 04, 2014, 07:35:11 PM
Thanks very much for that information Deana - very helpful, as always. I didn't know about that

Is there a way to specify a column to sort a ReportView on programmatically, based on the index of the column? Or is that something I should be prepared to implement via ArraySort()?

Regards,
Micheal

Michael,

Yes you got it. the ArraySort function can be used to sort a specific column. Keep in mind that you will need to subtract one from the clicked column, because the clicked column is one based and arrays are zero based.
Deana F.
Technical Support
Wilson WindowWare Inc.

mhall

Thanks Deana,

I did go ahead and implement that according to your suggestions and it's working quite well.

Regards,
Micheal

td

If you simply want to sort your data on a specific column when the column's header is clicked, you don't need to use ArraySort.  You just need to turn on the sorting style when the column header click event for the column is passed to your dialog callback and make sure that it is off for all other column's header click events.

The only time you need to use ArraySort is when you want to load data into the control for the first time and you want it sorted by some column other than the first.  After that it is more efficient to do as described above rather than constantly reloading the control with sorted data.   
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

mhall

Hi Tony,

In the end, I ended up implemented sort using ArraySort() simply because I often update the contents of the control ( filter it, edit a cell value, change column order, etc. ) and need to restore a previously set sort when I update it.

It's my understanding that, under those circumstances, I need to supply a presorted array to the control in order to have my data presented the way I want. Is my understanding of that correct?

Regards,
~Micheal

td

It depends on what you mean by 'edit'. The control will preserve the sort order based on the current sort column when you add rows to or remove them from the control when one of the sorting styles is enabled.   If you mean edit the first column value of a row manually using the edit box provided by the control's edit style and the first column is your sort column then you would need to resort the column by either clicking the header or performing a manual sort using ArraySort.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

mhall

The way I implemented "edit" is with a function that accepts the array contents of the reportview, the value of the first cell in the target row as an id, the column name and a new value. I then iterate through the array until I find the matching row, set the value and update the contents of the reportview. Obviously it's not edit-in-place, but it works for my needs at the moment.

It does mean a somewhat clumsy replacement of the entire contents of the reportView and then scroll the control to get the edited item back into view (it'd nice to be able to reset the scroll position exactly).

Regards,
Micheal

Deana

DialogControlSet Option 10 can be used to scroll a REPORTVIEW control row into view. Use the function's set-info (fourth) parameter to indicate the first column text of the row to scroll into view.
Deana F.
Technical Support
Wilson WindowWare Inc.

mhall

Hi Deana,

I am indeed using that option. However, it's only "scroll into view" ... I haven't seen a DialogControl code such as DC_ITEMSCROLLPOS for saving the current scroll position of the reportView so that it can be restored exactly. This causes the selected item to "jump" (usually down a bit ) in the display after updating the reportView since the item is simply being scrolled into view. It makes for a somewhat choppy user experience.

Not a dealbreaker, just ... abrupt. :)

Regards,
Micheal


Deana

Quote from: mhall on April 08, 2014, 06:30:38 PM
Hi Deana,

I am indeed using that option. However, it's only "scroll into view" ... I haven't seen a DialogControl code such as DC_ITEMSCROLLPOS for saving the current scroll position of the reportView so that it can be restored exactly. This causes the selected item to "jump" (usually down a bit ) in the display after updating the reportView since the item is simply being scrolled into view. It makes for a somewhat choppy user experience.

Not a dealbreaker, just ... abrupt. :)

Regards,
Micheal

Yes the Dialog does not provide a scroll position. How about using the DialogControlGet option 6 to save the selected row(s) of a REPORTVIEW control. Or is that what you are current doing that causes the "jump"?

Deana F.
Technical Support
Wilson WindowWare Inc.

JTaylor

If it is worth the hassle I posted a ComControl extender a while back which allows you to do a bit more with ReportViews.  Might solve your problem and help with some of the other stuff you are doing.

Jim

Deana

Deana F.
Technical Support
Wilson WindowWare Inc.

JTaylor


td

Quote from: mhall on April 08, 2014, 03:32:51 PM
The way I implemented "edit" is with a function that accepts the array contents of the reportview, the value of the first cell in the target row as an id, the column name and a new value. I then iterate through the array until I find the matching row, set the value and update the contents of the reportview. Obviously it's not edit-in-place, but it works for my needs at the moment.

It does mean a somewhat clumsy replacement of the entire contents of the reportView and then scroll the control to get the edited item back into view (it'd nice to be able to reset the scroll position exactly).

If I understand your description correctly that form of editing can be done without reloading the contents of the control.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

mhall

Hi Deana,

Yes, I'm using control code 6 to pull the contents of the reportView into an array, modifying it and then refreshing the contents of the view. That's the only way to change the contents, if I want to change anything other than the first column, correct?

Jim,

Thanks very much for the reminder, I'll be sure to check that out! (And thanks for posting the link Deana!)

Regards,
Micheal

mhall

Tony,

Really? I'm updating the contents of a cell row other than the first column. From the docs, I was under the impression that wasn't possible ... I'll fiddle some more but it'll be a few days. :)

~Micheal

td

It can be done but if you are performing a search on any column other than the first, you would still need to perform the dump so you could use the ArraySearch function to find the row to target.  However, if you are getting the targeted row via user input or a first column search, you don't need to dump the contents to an array.

To modify one or more columns of the targeted row, you can extract the row, replace any column values of your choosing  in the extracted row's array, delete the existing row, and add the modified row back into the control.  Assuming your first column values are unique, this takes three lines in your script plus whatever column modification lines you are already using. If your first row values are not unique, you would need to do a little more work in your script.

To say the least this is approach is not elegant but it can have performance advantages over dumping and reloading the entire contents of the control when the data set is sufficiently large.  However, if your existing approach is working for you, there is no reason to change it.  Just suggesting that there are other ways to perform the task.
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

mhall

Thanks Tony.

I had wondered about that approach - I'll try it out. Is sort updated/maintained in that case - even when not sorting on the first column? So the new row returns to the same location?

I'm out of town for a bit, but will try it out when I return.

Regards,
Micheal

td

Here is a very simple example demonstrating one way to perform in place editing of an off-column's content.  Have no idea how applicable it is to your situation.
Code (winbatch) Select
;;;;;;;;;;;;;;;;;;;;;;;
;; Demonstrates simple RV control sub item editing technique.

InitDialogConstants()  ; Initialize Dialog Constants (need only be done once usually)

aSample = ArrayFromStr("1abcdefghijklmnopqrstuvwxyz")
ArrayRedim(aSample, -1, 2)
aSample[0,0] = "Letter"
aSample[0,1] = "Number"
for i = 1 to ArrInfo(aSample, 1) - 1
   aSample[i, 1] = i
next
#DefineSubroutine EditCallbackProc(Edit_Handle,Edit_Message,Edit_Name,Edit_EventInfo,Edit_ChangeInfo)
switch Edit_Message
case MSG_INIT
   DialogProcOptions(Edit_Handle,MSG_RVITEMSELROW,@TRUE)
   return(RET_DO_DEFAULT)

case MSG_RVITEMSELROW      ; "ReportView_1"
   aTarget = DialogControlGet(Edit_Handle, "ReportView_1", DC_RVMATCHCOL, Edit_ChangeInfo)
   DialogControlSet(Edit_Handle, "ReportView_1", DC_ITEMBOXREMOVE, Edit_ChangeInfo)
   aTarget[0,1] = "Selected"
   DialogControlSet(Edit_Handle, "ReportView_1", DC_ITEMBOXADD, aTarget)

   return(RET_DO_DEFAULT)

endswitch
return(RET_DO_DEFAULT)
#EndSubroutine

ColEditFormat=`WWWDLGED,6.2`

ColEditCaption=`Simple Column Editing`
ColEditX=882
ColEditY=085
ColEditWidth=302
ColEditHeight=206
ColEditNumControls=002
ColEditProcedure=`EditCallbackProc`
ColEditFont=`DEFAULT`
ColEditTextColor=`DEFAULT`
ColEditBackground=`DEFAULT,DEFAULT`
ColEditConfig=0

ColEdit001=`124,186,033,011,PUSHBUTTON,"PushButton_OK",DEFAULT,"OK",1,10,32,DEFAULT,DEFAULT,DEFAULT`
ColEdit002=`006,007,282,171,REPORTVIEW,"ReportView_1",aSample,DEFAULT,DEFAULT,20,32505856,DEFAULT,DEFAULT,DEFAULT`

ButtonPushed=Dialog("ColEdit")
"No one who sees a peregrine falcon fly can ever forget the beauty and thrill of that flight."
  - Dr. Tom Cade

mhall

Hi Tony,

Just wanted to say that method works well, once I update the sort of the reportView and highlight/scroll to the replaced item.

Thanks for the help,
Micheal