LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

table right click

Solved!
Go to solution

Hello,

I am trying to setup a "right click menu" on a table with menu items related to the cell (or at least to the row) where the right click was hit.

For example two such menu items will be "Add new row after" and "Add new row before".

For this reason, I need to get the cell (or at least the row) x and y position numbers where the click was asserted. I have tried to modify the example which can be found here: http://sine.ni.com/apps/we/niepd_web_display.display_epd4?p_guid=B45EACE3E8FF56A4E034080020E74861&p_...

with no success. It works fine with the left click, but not with the right.

Please notice also that I have managed how to hide the built in right menu items associated with a table control and how to insert mine with the respective functions. What I am missing is just how to retrieve the cell coordinates in the table after a right click on it.

Many thanks for your suggestions,

Marco

 

 

 

0 Kudos
Message 1 of 8
(5,814 Views)

First of all, the deferred call method is no more needed to handle events on the table controls on more recent versions of CVI (the document you linked refers to version 5.5 which is quite old. I'm not sure about release 7, but at least starting from rel. 8 this is no more necessary).

Second item: wouldn'i it be simpler to hande only one click event and generate a two-items menu: add row after and add row before? You can detect which menu item was clicked so you can operate in the proper way.

Additionally, I don't understand why you want to specifically handle a right click event on the table: if you have already customized thetable menu with HideBuiltInCtrlMenuItem and NewCtrlMenuItem you don't need anything to display the context menu: the control will automatically handle menu display.

 

Different is the case if you have completely removed native table menu with SetCtrlAttribute (panelHandle, controlID, ATTR_ENABLE_POPUP_MENU, 0); In this case, this is a snippet of code that handles the right click on a table and displays a context menu (you will need to create your menu inside the UIR editor):

 

    Point   cell;

 

    if (event != EVENT_RIGHT_CLICK) return 0;

    // Right click: pop-up menu modifica
    GetTableCellFromPoint (panel, control, MakePoint (eventData2, eventData1), &cell);
    if (cell.y > 0) {   // Discriminate whether an actual cell was clicked instead of row/column header or so

        SetActiveTableCell (panel, control, cell);
        idx = RunPopupMenu (GetPanelMenuBar (panel), menuId, panel, eventData1, eventData2, 0, 0, 0, 0);
    }
 

After menu is clicked, 'idx' holds the menuID of the item clicked (0 if menu is cancelled).



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 2 of 8
(5,812 Views)

Hi Roberto,

many thanks for your comments. I am using the latest CVI version (CVI 2009) so I will no longer use the "old" code as you suggest.

I have hidden the default context menu items and added mine. And I just want one single right click, not double right click.

So my problem can be confined to this question: when I right-click the table and my custom context menu is displayed, how can I programmatically retrieve the cell coordinates where the right click was issued ?

Many thanks for your patience.

Marco

0 Kudos
Message 3 of 8
(5,809 Views)

If you install your own menu callback(s), you can detect the active cell by using GetActiveTableCell inside the callback, this way:

 

void CVICALLBACK MenuCallback (int panelHandle, int controlID, int MenuItemID, void *callbackData)
{
    char    msg[512];
    Point    cell;

    GetActiveTableCell (panelHandle, controlID, &cell);
    if (!cell.y || !cell.x)
        MessagePopup ("Context menu", "No actual cell selected");
    else {
        sprintf (msg, "Active cell is:\nrow %d\ncolumn %d", cell.y, cell.x);
        MessagePopup ("Context menu", msg);
    }
}
 

A table always has an active cell, which is independent from where the user clicks on the control, so in this case the "no cell selected" is not likely to happen. If you want to activate an actual cell depending on the mouse position you must hide the control menu and use the following lines in the table callback (not in the menu callback):

 

    switch (event) {
        case EVENT_LEFT_CLICK:
        case EVENT_RIGHT_CLICK:
            GetTableCellFromPoint (panel, control, MakePoint (eventData2, eventData1), &cell);
            if (cell.x == 0 && cell.y == 0) return 1;    // Mouse not on the cells area

 

            GetNumTableRows (panel, control, &r);
            SetTableCellRangeAttribute (panel, control, VAL_TABLE_ENTIRE_RANGE,
                ATTR_TEXT_BOLD, 0);     // Disable highlighting on the whole table

           SetTableCellRangeAttribute (panel, control, VAL_TABLE_ROW_RANGE (cell.y),
                ATTR_TEXT_BOLD, 1);     // Highlight entire row
            if (event == EVENT_LEFT_CLICK) break;
            // Context menu

           choice = RunPopupMenu (panel, control, panel, eventData1, eventData2, 0, 0, 0, 0);
            switch (choice) {

                case 0:                // No choice

                   break;
                // Here menu items must be added to handle operator selection

            }

            break;

        // Other event cases here if needed
    }

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 4 of 8
(5,805 Views)

Hello and thanks again Roberto,

the code you suggested solved the issue Smiley Happy.

For the benefit of other users who may have my same need, I resume here what I did finally.

 

1) programmatically create a menu bar, a menu and its menu items. When doing this, as the menu is intended as a custom context-like menu, I pass 0 to the NewMenuBar function in order not to see the menu on top of the uir window. I pass 0 also to the callback function parameter because I want to process the user's choice in the table callback:

 

 

MenuBar = NewMenuBar(0);
MenuId = NewMenu(MenuBar, "RIGHTMENU", -1);
menuItemAddBefore = NewMenuItem(MenuBar, MenuId, "Add a row before", -1, 0, 0, 0);
menuItemAddAfter = NewMenuItem(MenuBar, MenuId, "Add a row after", -1, 0, 0, 0);

 

 2) in the table callback add Roberto's code. I have modified the "switch" structure with a multiple "if" because I want to recover the user's menu choice by means of the menu item variables used in point 1 above and they are not constant so cannot be used as a "case" expression:

 

 

GetTableCellFromPoint (panel, control, MakePoint (eventData2, eventData1), &focus);
if (focus.x == 0 && focus.y == 0) return 1; // Mouse not on the cells area

GetNumTableRows (panel, control, &r);

// Disable highlighting on the whole table
SetTableCellRangeAttribute (panel, control, VAL_TABLE_ENTIRE_RANGE, ATTR_TEXT_BOLD, 0);

// Highlight entire row
SetTableCellRangeAttribute (panel, control, VAL_TABLE_ROW_RANGE (focus.y), ATTR_TEXT_BOLD, 1);

if (event == EVENT_LEFT_CLICK) break;

// Context menu

choice = RunPopupMenu (MenuBar, MenuId, panel, eventData1, eventData2, 0, 0, 0, 0);
if (choice == menuItemAddBefore)
{
// code handling the add before menu selection
}
else if (choice == menuItemAddAfter)
{
// code handling the add after menu selection
}

 

Many thanks again to Roberto.

 

Bye

Marco

 

 

 

 

 

 

 

 

Message 5 of 8
(5,798 Views)

You're welcome!

 

Just a little addition: if the menu that you dynamically create in step 1 is not varying during program life, it can be created within the UIR editor. Doing so permits to use the switch instead of a chain of if since menu itemIDs are now constants. Even if some changes have to be made, you always could do it at runtime modifying some item of the static menu, preserving the use of the switch statement, which in my opinion is more readable than the concatenated ifs.

 

But I know that here we are coming into the personal way of programming, so consider this just as a suggestion. The important thing is that you managed to solve your problem.

 

Have a good day.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 6 of 8
(5,796 Views)

If you do not laugh too much Smiley Very Happy I tell you why the menu is created programmatically...

This is because I am NOT able to retrieve the MenuId to pass to the RunPopupMenu function in case the menu is created in the UIR file. Just using the constant name indicated when creating the MenuBar and the Menu (i.e. the constant name found then in the .h file) does not work.

Bye

Marco

0 Kudos
Message 7 of 8
(5,792 Views)
Solution
Accepted by topic author ElbaTech

Ah, I see! Smiley Happy

Well, the ID to pass to RunPopupMenu is the combination of the menu bar constant prefix and menu constant name as highlighted in the editor panel:

 

menueditor.PNG

 

So in this case you should pass Menu_smp to the function in order to programmatically display the menu.

I'm not laughing since I have had some problems too in identifying the correct id to use when I started using this function.

 

Greetings



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 8 of 8
(5,788 Views)