How in OpenEdge ABL / Progress 4GL do I get the RIGHT-MOUSE-CLICK trigger to perform the default left click to reposition the focus

StackOverflow https://stackoverflow.com/questions/8943855

Question

I'm using OpenEdge ABL / Progress 4GL. I have a browser widget populated with rows. When I left click a row the row is highlighted and that row is now in focus. I want when I right click on a different row for progress to perform a "left click" (to move the focus to the row that was right clicked on) then do the right click.

Was it helpful?

Solution

I already answered this question here : How in OpenEdge ABL / Progress 4GL do I find the row id of a row that is right clicked in a browser.

I'm not sure what the policy is with this duplicate question, but I'm repeating my answer here, I hope it's OK.

I had a similar situation; I wanted to respond to the mouse's Right-click in a browse. Right-clicking does not select the row you're clicking on, so I had to programmatically figure out which row it was. The coding below determines which row you clicked on and selects it. I am afraid it really is this complicated.

This goes in the MOUSE-MENU-DOWN event of the browse:

DEFINE VARIABLE iRowHeight   AS INTEGER     NO-UNDO.
DEFINE VARIABLE iLastY       AS INTEGER     NO-UNDO.
DEFINE VARIABLE iRow         AS INTEGER     NO-UNDO.
DEFINE VARIABLE hCell        AS HANDLE      NO-UNDO.
DEFINE VARIABLE iTopRowY     AS INTEGER     NO-UNDO.

/* See if there are ANY rows in view... */
IF SELF:NUM-ITERATIONS = 0 THEN 
DO:
   /* No rows, the user clicked on an empty browse widget */
   RETURN NO-APPLY. 
END.

/* We don't know which row was clicked on, we have to calculate it from the mouse coordinates and the row heights. No really. */
SELF:SELECT-ROW(1).               /* Select the first row so we can get the first cell. */
hCell      = SELF:FIRST-COLUMN.   /* Get the first cell so we can get the Y coord of the first row, and the height of cells. */
iTopRowY   = hCell:Y - 1.         /* The Y coord of the top of the top row relative to the browse widget. Had to subtract 1 pixel to get it accurate. */
iRowHeight = hCell:HEIGHT-PIXELS. /* SELF:ROW-HEIGHT-PIXELS is not the same as hCell:HEIGHT-PIXELS for some reason */
iLastY     = LAST-EVENT:Y.        /* The Y position of the mouse event (relative to the browse widget) */

/* calculate which row was clicked. Truncate so that it doesn't round clicks past the middle of the row up to the next row. */
iRow       = 1 + TRUNCATE((iLastY - iTopRowY) / iRowHeight, 0). 

IF iRow > 0 AND iRow <= SELF:NUM-ITERATIONS THEN 
DO:
  /* The user clicked on a populated row */
  Your coding here, for example:
  SELF:SELECT-ROW(iRow).
END.
ELSE DO:
  /* The click was on an empty row. */
  SELF:DESELECT-ROWS().
  RETURN NO-APPLY.
END.

I hope this helps.

OTHER TIPS

Check the ABL Reference for mouse events (page 1834 of the 10.2B ABL Reference Guide).

The usual method is to capture the event in question with an "ON event-name OF widget-name" then apply a different event to the widget (APPLY "mouse-select-click" TO b-name) then tell the AVM to ignore the original event with "RETURN NO-APPLY."

It would look something like this:

ON MOUSE-MENU-CLICK   OF b-name
   DO:
   APPLY "mouse-select-click" TO SELF.
   RETURN NO-APPLY.
   END.

Caveat: I'm not sure what event a right-click triggers, so you'll need to adapt this code to suit.

Basically, you would have to define a trigger like this:

ON RIGHT-MOUSE-CLICK OF myBrowseRow DO:  

APPLY "ENTRY" TO myBrowse IN FRAME myFrame.  

/* Code to focus a particular row in the browse. */  
APPLY "ENTRY" TO SELF IN BROWSE myBrowse.
END.

The problem might be that you'll have to add that trigger to every row in the browse, because it's AFAIK impossible to figure out which row has been right-clicked if you set the trigger just for the browse itself...

To expand on the main answer, here are some additional notes and sample code.
1. You need to be aware of the height of the headers and title.
2. You could dynamically attach a menu if you had standard browse functions.
3. Multi-select browsers act slightly differently.

ON 'right-mouse-down':U ANYWHERE DO:
    RUN set_focus (SELF).
    IF SELF:TYPE = 'BROWSE' THEN DO:
        RETURN NO-APPLY.
    END.
    ELSE DO:
        APPLY 'menu-drop' TO SELF.
    END.
END.

PROCEDURE set_focus.
DEF INPUT PARAM i_object            AS HANDLE   NO-UNDO.
DEF VAR l_was_row_one_selected      AS LOG      NO-UNDO.
DEF VAR l_header_y                  AS DEC      NO-UNDO.
DEF VAR w_browse_title_bar_height   AS DEC      NO-UNDO INITIAL 19. /* determine this for your UI */
DEF VAR o_labels                    AS CHAR     NO-UNDO.
DEF VAR o_procedures                AS CHAR     NO-UNDO.
DEF VAR h_menu                      AS HANDLE   NO-UNDO.
DEF VAR h_menu_item                 AS HANDLE   NO-UNDO.
DEF VAR l_count                     AS INT      NO-UNDO.
/* given an object ... */
    IF i_object:TYPE = 'browse' THEN DO:
        IF i_object:NUM-SELECTED-ROWS = 0
            THEN ASSIGN l_was_row_one_selected = FALSE.
            ELSE ASSIGN l_was_row_one_selected = i_object:IS-ROW-SELECTED(1) NO-ERROR.
        i_object:SELECT-ROW(1) NO-ERROR.
        IF ERROR-STATUS:ERROR THEN RETURN.
        l_header_y = MAX(1,i_object:FIRST-COLUMN:Y). /* in case there are no column headers */
        IF i_object:TITLE <> ? THEN l_header_y = l_header_y - w_browse_title_bar_height.
        IF l_was_row_one_selected = FALSE THEN i_object:DESELECT-SELECTED-ROW(1) NO-ERROR.
        /* this section selects the correct row, based on where it was clicked, minus the height of the headers divided by row height */
        i_object:SELECT-ROW(
            INT(
                1 + 
                TRUNC(
                      (LAST-EVENT:Y - l_header_y) / i_object:FIRST-COLUMN:HEIGHT-PIXELS
                     ,0)
                )
            )
            NO-ERROR.
        APPLY 'ENTRY':u TO i_object. /* to get focus properly */
        APPLY 'VALUE-CHANGED':u TO i_object.
        /* use some rule to find associated dynamic menu items, e.g. maintenance options, finding related data*/
        RUN find_menu_stuff (i_object:NAME, OUTPUT o_labels, OUTPUT o_procedures).
        IF o_labels = '' THEN RETURN.

        /* this finds a popup menu, if any */
        h_menu = i_object:POPUP-MENU NO-ERROR.

        IF VALID-HANDLE(h_menu) THEN RETURN. /* already created previously */
        /* create a popup menu */
        CREATE MENU h_menu.
        ASSIGN
            h_menu:POPUP-ONLY   = TRUE
            i_object:POPUP-MENU = h_menu
            .
        /* add the standard maintenance options (they still may not be supported though) */
        DO l_count = 1 TO NUM-ENTRIES (o_labels):
            IF ENTRY(l_count,o_labels) = 'Rule' THEN DO:
                CREATE MENU-ITEM h_menu_item
                    ASSIGN
                        SUBTYPE     = 'RULE'
                        PARENT      = h_menu
                        .

            END.
            ELSE DO:
                CREATE MENU-ITEM h_menu_item
                    ASSIGN
                        PARENT      = h_menu
                        LABEL       = ENTRY(l_count,o_labels)
                        SENSITIVE   = TRUE
                    TRIGGERS:
                        ON CHOOSE PERSISTENT RUN pp_apply_maint_action IN THIS-PROCEDURE (SELF, ENTRY(l_count,o_procedures)).
                    END TRIGGERS.
            END.
        END.
    END.
    IF VALID-HANDLE(h_menu)
        THEN APPLY 'menu-drop' TO h_menu.
    /* MENU-DROP - Supported only when the POPUP-ONLY attribute is set to TRUE and the
                   menu is set as a popup for some other widget */
END PROCEDURE.

PROCEDURE find_menu_stuff.
    /* do lookups or other general or specific things here */
END.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top