SELECT-NEXT-ROW returns true when on last row of browse

ThecTutor

New Member
OpenEdge 11.7.2

I've encountered a strange error when programatically traversing a browse.

The code uses the SELECT-NEXT-ROW() method on the browse and expects the method to return false when on the last row.

DO WHILE v-ok: /* do stuff */ v-ok = hbrowse:SELECT-NEXT-ROW(). END.

Normally, this works fine, but if one of the cells on that last line is currently open for editing, SELECT-NEXT-ROW() returns true even if it's on the last row. This causes my code to go into an infinite loop.

Note that this is in a generic context, so I cannot make any assumptions about the browse or its contents.

So my options are to iterate through the browse in a different way or find a way to force the cell to close so SELECT-NEXT-ROW() can work properly.

The user wants to see the browse scroll down while this is happening, so pulling out the QUERY object and iterating it there is not an option.

I've actually tried to ask ChatGPT about this and it keeps offering methods that don't seem to exist (at least on my version of Progress) like EDI-EDIT, GET-CELL-STATE, or END-EDIT-CELL. yikes.

Any hep would be appreciated.

-Ken
 
You might want to post just a tiny little bit more code as an actual working example. Maybe use the "customer" table in the sports database?
 
yeah, I actually have a small example program that demonstrates the issue.

When you click the SELECT-NEXT-ROW button and the cell is open, it returns "yes", even on the last row of the browse.

This uses a temp-table, so there's no DB to connect to.

Oddly enough, if you clear the "Flat" and "no-focus" flags of the button, it will work properly, but note that in the real example, the procedure just has a handle to a BROWSE and I don't know how to force that BROWSE handle lose focus.
 

Attachments

  • BrowseTest.w
    14.4 KB · Views: 5
I know that it is ungrateful of me but... 469 lines of app builder cruft really wasn't what I had in mind :oops:
 
Sorry about that. I just figured that something that was runnable out of the box would be preferable

The key parts are here:
DEFINE BROWSE bwsItem QUERY bwsItem DISPLAY /* */ ttitem.rownum COLUMN-LABEL "Row#" WIDTH 4 ttItem.ITEM COLUMN-LABEL "Item" WIDTH 20 ttItem.descr[1] COLUMN-LABEL "descr1" WIDTH 40 ttItem.descr[2] COLUMN-LABEL "descr2" WIDTH 40 ttItem.product_line COLUMN-LABEL "Product Line" WIDTH 20 "" ENABLE descr[1] descr[2] ON CHOOSE OF cmdSelectNextRow IN FRAME fMain /* SELECT-NEXT-ROW */ DO: DEF VAR rv AS LOGICAL NO-UNDO. /* This seems to be ignored */ APPLY "leave" TO BROWSE bwsItem. rv = BROWSE bwsItem:SELECT-NEXT-ROW(). txtSNRresult = string(rv, "yes/no"). DISPLAY txtSNRresult WITH FRAME fmain. END.
 
Never used SELECT-NEXT-ROW so not sure the best solution. One idea is to check what has focus and if a cell then remove focus. A really rough example only but hopefully it gives some ideas:

Code:
ON CHOOSE OF cmdSelectNextRow IN FRAME fMain /* SELECT-NEXT-ROW */
DO:
  DEF VAR rv AS LOGICAL NO-UNDO.
  DEF VAR hCell AS HANDLE NO-UNDO.

  hCell = FOCUS.
  IF VALID-HANDLE(hCell) AND hCell:NAME = "descr" THEN
     APPLY "CTRL-TAB".

  /* This seems to be ignored */
  APPLY "leave" TO BROWSE bwsItem.
  
  rv = BROWSE bwsItem:SELECT-NEXT-ROW().
  
  txtSNRresult = string(rv, "yes/no").
    
  DISPLAY txtSNRresult WITH FRAME fmain.
  
END.
 
I see where you're going with that, but I have two issues.

This is in a completely generic context, so something like hCell:NAME = "descr" would not be possible. Now hCell:ENABLED or something like that may be useful, but I've been having trouble finding a good list of attributes and methods for the cell.

Also, I'm not sure exactly what applying "CTRL-TAB" (as opposed to "TAB") will do, but there may be multiple enabled cells on the browse and leaving one may just open the next one.

I wonder if it's possible to disable the whole browse and re-enable it....
or would I have to iterate through the columns and disable them if I can detect that they are enabled, then re-enable them afterwards....
 
For a generic context you could iterate through the browse columns and check that way:

Code:
DEFINE VARIABLE brws-col-hdl AS HANDLE NO-UNDO.
DEFINE VARIABLE browse-hdl AS HANDLE NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.

browse-hdl = BROWSE bwsItem:HANDLE.
DO i = 1 TO browse-hdl:NUM-COLUMNS:
   brws-col-hdl = browse-hdl:GET-BROWSE-COLUMN(i).
   IF /* brws-col-hdl:MODIFIED */ FOCUS = brws-col-hdl THEN DO:
      MESSAGE "A cell is open so leave the cell." VIEW-AS ALERT-BOX INFORMATION.
      APPLY "CTRL-TAB".
      LEAVE.
   END.
END.

The reason for applying "CTRL-TAB" is it will leave any open cell and select the whole row. See the following:


However, if you do not want to leave the current open cell then the only other thing I can think of is check for the OFF-END event. That way you can put in processing to stop/exit cleanly and avoid the infinite loop:

Code:
ON OFF-END OF bwsItem IN FRAME fMain
DO:
  /* Note: will only fire if user presses the cursor down key or the cmdSelectNextRow button is selected and in an open cell. */
  MESSAGE "Browse has reached the last row." VIEW-AS ALERT-BOX INFORMATION.
END.
 
Thank you for the clarification on the CTRL-TAB event though I've never applied an event without a widget reference. It's always been
APPLY "<event>" TO <widget>.

We are actually iterating though the columns already, so this should be easy to check.

I'll let you know...
 
This was working so well until I ran into this defined in the master window.

Code:
ON 'ctrl-tab' ANYWHERE
DO:
    RUN nextwindow.
    RETURN NO-APPLY.
END.

So it was all working properly until I tried running it from within our application and it didn't work.
 
These things are never easy! So I am guessing the problem is that the CTRL-TAB is only applying to the master window and not others?

Is it possible in the master window you can get a handle to either the procedures, window or browse and if so set a CTRL-TAB specific trigger to the handle? Something similar to:

Code:
ON CTRL-TAB OF browse-hdl PERSISTENT
   RUN nextwindow IN THIS-PROCEDURE.

/* or - not sure if this is actually valid */

RUN prog1 PERSISTENT SET hProg.
ON CTRL-TAB OF hProg PERSISTENT
   RUN nextwindow IN hProg.
 
Back
Top