CVI如何多个控件共用一个回调函数

CVI代码怎么写,能够让多个控件共用一个回调函数,步骤请详细一点,希望能有个实例,方便本人理解(语言-开发语言)

核心就一句:
// 假设要让 txt1, txt2, 按钮btn1 共用一个回调函数 CallBackFunction:
txt1.SetActiveCallback (CallBackFunction);
txt2.SetActiveCallback (CallBackFunction);
btn1.SetActiveCallback (CallBackFunction);

在LabVIEW中,可以使用Event Structure来实现多个控件共用一个回调函数的功能。以下是使用Event Structure实现此功能的实例:

  1. 将所有控件的事件都连接到Event Structure的输入端口;

  2. 在Event Structure中添加一个Case,此Case的Condition设置为“Any”,即任何事件都可以进入此Case;

  3. 将要共用的回调函数放到此Case中,即可实现多个控件使用一个回调函数的功能。

CVI (LabWindows/CVI) 是 National Instruments 公司开发的一款基于 C 语言的图形用户界面开发工具。

如果你想让多个控件共用一个回调函数,你可以使用“回调数据”(callback data),该功能允许回调函数获取有关调用该函数的控件的信息。

下面是一个示例,以实现多个按钮共用一个回调函数的代码:


#include <ansi_c.h>
#include <cvirte.h> 
#include <userint.h>

int panelHandle;

void CVICALLBACK buttonCallback (int panel, int control, int event,
    void *callbackData, int eventData1, int eventData2)
{
    int buttonID = *(int*)callbackData;
    switch (buttonID)
    {
        case 1:
            // 按钮1被点击时的代码
            break;
        case 2:
            // 按钮2被点击时的代码
            break;
        // ...
    }
}

int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0)
        return -1;    /* out of memory */

    panelHandle = LoadPanel (0, "my_panel.uir", PANEL);
    if (panelHandle < 0)
        return -1;
    int buttonID1 = 1, buttonID2 = 2;
    SetCtrlAttribute (panelHandle, PANEL_BUTTON_1, ATTR_CALLBACK_DATA, &buttonID1);
    SetCtrlAttribute (panelHandle, PANEL_BUTTON_2, ATTR_CALLBACK_DATA, &buttonID2);
    SetCtrlCallback (panelHandle, PANEL_BUTTON_1, buttonCallback);
    SetCtrlCallback (panelHandle, PANEL_BUTTON_2, buttonCallback);

    DisplayPanel (panelHandle);
    RunUserInterface ();
    DiscardPanel (panelHandle);
    return 0;
}

您好,关于多个控件调用同一个回调函数,您可以参考以下回调函数代码:

int CVICALLBACK ChangeCallback (int panel, int control, int event,
                                         void *callbackData, int eventData1,
                                         int eventData2)
{
    int      currentItem;
    MyStruct *tempItem;
    
    switch (event)
        {
        case EVENT_COMMIT:
            if (!g_myList)
                return 0;
            GetCtrlVal(panel, PANEL_DISPLAYITEM, ¤tItem);
            tempItem = ListGetPtrToItem (g_myList, currentItem);
            if (tempItem) 
                {
                if (control == PANEL_ITEMINTEGER) 
                    GetCtrlVal (panel, PANEL_ITEMINTEGER,
                                &tempItem->integerValue);
                else if (control == PANEL_ITEMDOUBLE) 
                    GetCtrlVal (panel, PANEL_ITEMDOUBLE,
                                &tempItem->doubleValue);
                else if (control == PANEL_ITEMSTRING) 
                    GetCtrlVal (panel, PANEL_ITEMSTRING,
                                tempItem->stringValue);
                }    
            
            break;
        }
    return 0;
}

其中,panel参数是面板标识,control参数是控件的标识,event参数是事件标识,因此你可以通过control参数区分不同的控件。

该回答引用ChatGPT
在 Windows API 中,您可以使用子窗口消息处理(Subclassing Window Messages)来让多个控件共享同一个回调函数。下面是一个示例,演示了如何使用该技术实现多个按钮共用同一个回调函数:

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case 100:
                    MessageBox(hWnd, TEXT("Button 1"), TEXT("Message"), MB_OK);
                    break;
                case 200:
                    MessageBox(hWnd, TEXT("Button 2"), TEXT("Message"), MB_OK);
                    break;
                case 300:
                    MessageBox(hWnd, TEXT("Button 3"), TEXT("Message"), MB_OK);
                    break;
            }
            break;
        }
        case WM_CLOSE:
            DestroyWindow(hWnd);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = TEXT("WindowClass");
    wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

    if (!RegisterClassEx(&wcex))
    {
        MessageBox(NULL, TEXT("Window Registration Failed!"), TEXT("Error"), MB_ICONEXCLAMATION | MB_OK);
        return 1;
    }

    HWND hWnd = CreateWindow(
        TEXT("WindowClass"),
        TEXT("Window"),
        WS_OVERLAPPEDWINDOW


在 CVI 中,您可以使用回调函数处理多个控件的事件。以下是一个例子:

首先,在 CVI 中创建一个回调函数,它可以处理多个控件的事件:


```c
#include <userint.h>

int CVICALLBACK handleButtonEvents(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
    if (event == EVENT_COMMIT)
    {
        int controlID = GetControlID(control);
        switch (controlID)
        {
            case IDC_BUTTON1:
                // 处理按钮1事件的代码
                break;
            case IDC_BUTTON2:
                // 处理按钮2事件的代码
                break;
            case IDC_BUTTON3:
                // 处理按钮3事件的代码
                break;
        }
    }
    return 0;
}


然后,为每个控件分别设置回调函数:

SetCtrlAttribute(panel, IDC_BUTTON1, ATTR_CALLBACK_DATA, (void *)&callbackData);
SetCtrlAttribute(panel, IDC_BUTTON1, ATTR_CALLBACK_FUNCTION, handleButtonEvents);

SetCtrlAttribute(panel, IDC_BUTTON2, ATTR_CALLBACK_DATA, (void *)&callbackData);
SetCtrlAttribute(panel, IDC_BUTTON2, ATTR_CALLBACK_FUNCTION, handleButtonEvents);

SetCtrlAttribute(panel, IDC_BUTTON3, ATTR_CALLBACK_DATA, (void *)&callbackData);
SetCtrlAttribute(panel, IDC_BUTTON3, ATTR_CALLBACK_FUNCTION, handleButtonEvents);


在回调函数中,您可以使用 GetControlID 函数获取控件的 ID,并通过判断控件 ID 来处理不同的事件。在这个例子中,您可以使用 switch 语句根据不同的控件 ID 来执行不同的代码。

请注意,上面的代码仅作为参考,您可以根据自己的需求修改回调函数和代码逻辑。

#include <utility.h>
#include <userint.h>

int panelHandle;
int button1Handle, button2Handle;

int CVICALLBACK MyCallback (int panel, int control, int event,
        void *callbackData, int eventData1, int eventData2)
{
    if (event == EVENT_COMMIT) {
        if (control == button1Handle)
            MessagePopup("Button 1", "Button 1 was clicked");
        else if (control == button2Handle)
            MessagePopup("Button 2", "Button 2 was clicked");
    }
    return 0;
}

int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0)
        return -1;    /* out of memory */

    panelHandle = LoadPanel (0, "MyPanel.uir", PANEL);

    button1Handle = GetCtrlHandle (panelHandle, PANEL_BUTTON1);
    button2Handle = GetCtrlHandle (panelHandle, PANEL_BUTTON2);

    SetCtrlAttribute (panelHandle, PANEL_BUTTON1, ATTR_CALLBACK_DATA, (void *) 1);
    SetCtrlAttribute (panelHandle, PANEL_BUTTON2, ATTR_CALLBACK_DATA, (void *) 2);

    SetCtrlAttribute (panelHandle, PANEL_BUTTON1, ATTR_CALLBACK_FUNCTION, MyCallback);
    SetCtrlAttribute (panelHandle, PANEL_BUTTON2, ATTR_CALLBACK_FUNCTION, MyCallback);

    DisplayPanel (panelHandle);
    RunUserInterface ();

    DiscardPanel (panelHandle);
    return 0;
}

在该代码中,MyCallback函数为两个按钮实现了事件响应,当每个按钮被单击时,它将弹出一个消息框来显示按钮的标识。在main函数中,我们使用GetCtrlHandle获取每个按钮的句柄,然后使用SetCtrlAttribute设置每个按钮的回调函数。

在CVI中,可以通过设置控件的回调函数,使多个控件共用一个回调函数。步骤如下:

定义回调函数:在代码的开头定义一个回调函数,该函数将在控件事件发生时被调用

int CVICALLBACK commonCallback(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
    // 在此处编写回调函数的代码
    // 例如,可以使用switch语句根据事件类型进行不同的处理
    switch (event)
    {
        case EVENT_COMMIT:
            // 在此处编写事件处理代码
            break;
    }
    return 0;
}

设置控件的回调函数:使用CVI函数SetCtrlAttribute设置控件的回调函数,该函数接受三个参数:面板号,控件号和回调函数指针


// 设置第一个控件的回调函数
SetCtrlAttribute(panel, control1, ATTR_CALLBACK_FUNCTION, commonCallback);

// 设置第二个控件的回调函数
SetCtrlAttribute(panel, control2, ATTR_CALLBACK_FUNCTION, commonCallback);

// 设置第三个控件的回调函数
SetCtrlAttribute(panel, control3, ATTR_CALLBACK_FUNCTION, commonCallback);

以上代码即可让多个控件共用一个回调函数。在回调函数中,您可以通过判断控件的参数,确定是哪个控件发生了事件,并对事件进行相调
或者使用
在 CVI 中,一个回调函数可以被多个控件共用,你可以利用控件句柄来判断是哪个控件触发了回调函数


#include <cvirte.h>     
#include <userint.h>

int panelHandle;
int button1Handle, button2Handle;

int CVICALLBACK callbackFunc(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
  switch (event)
  {
    case EVENT_COMMIT:
      if (control == button1Handle)
      {
        // Button 1 was pressed
        MessagePopup("Button 1", "Button 1 was pressed.");
      }
      else if (control == button2Handle)
      {
        // Button 2 was pressed
        MessagePopup("Button 2", "Button 2 was pressed.");
      }
      break;
  }
  
  return 0;
}

int main (int argc, char *argv[])
{
  if (InitCVIRTE (0, argv, 0) == 0)
    return -1;    /* out of memory */

  panelHandle = LoadPanel (0, "Example.uir", PANEL);
  
  button1Handle = GetCtrlHandle(panelHandle, PANEL_BUTTON1);
  button2Handle = GetCtrlHandle(panelHandle, PANEL_BUTTON2);
  
  SetCtrlAttribute(panelHandle, PANEL_BUTTON1, ATTR_CALLBACK_DATA, (void*) 0);
  SetCtrlAttribute(panelHandle, PANEL_BUTTON2, ATTR_CALLBACK_DATA, (void*) 1);
  
  SetCtrlAttribute (panelHandle, PANEL_BUTTON1, ATTR_CALLBACK_FUNCTION, callbackFunc);
  SetCtrlAttribute (panelHandle, PANEL_BUTTON2, ATTR_CALLBACK_FUNCTION, callbackFunc);

  DisplayPanel (panelHandle);
  RunUserInterface ();
  
  DiscardPanel (panelHandle);
  return 0;
}

上面的代码中,两个按钮都使用了同一个回调函数 callbackFunc,并且在回调函数内部使用了控件句柄判断是哪个按钮被按下。

该代码在按下按钮1时会显示 "Button 1 was pressed",在按下按钮2时会显示 "Button 2 was pressed"

在CVI中,可以使用回调函数来处理用户操作,如单击按钮等。要让多个控件共用一个回调函数,可以使用控件ID来区分不同的控件,然后在回调函数中根据控件ID执行相应的操作。下面是一个简单的示例:

1.在CVI中创建两个控件,一个是按钮,一个是列表框,分别添加到不同的面板上。

2.给两个控件设置ID,可以在属性窗口中设置。

3.在代码中定义回调函数,例如:

int CVICALLBACK MyCallbackFunc(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
    switch (control)
    {
        case BUTTON_ID:
            // 按钮控件被单击
            break;
        case LISTBOX_ID:
            // 列表框控件发生事件
            break;
        // 其他控件
        default:
            break;
    }
    return 0;
}

其中,BUTTON_ID和LISTBOX_ID是前面设置的控件ID。

4.在主函数中将回调函数与控件关联起来,例如:

int main(int argc, char *argv[])
{
    // 创建面板
    int panel = LoadPanel(0, "MyUI.uir", PANEL_ID);
    // 将回调函数与按钮控件关联
    InstallCallback(panel, PANEL_ID, BUTTON_ID, MyCallbackFunc, 0);
    // 将回调函数与列表框控件关联
    InstallCallback(panel, PANEL_ID, LISTBOX_ID, MyCallbackFunc, 0);
    // 显示面板
    DisplayPanel(panel);
    // 运行主循环
    RunUserInterface();
    return 0;
}

其中,PANEL_ID是面板的ID。

这样,无论是单击按钮还是列表框发生事件,都会调用同一个回调函数,通过控件ID可以区分不同的控件,执行相应的操作。
如果我的回答解决了您的问题,请采纳我的答案

CVI(C语言编译器)是一个基于C语言的开发环境,用于编写测试和测量应用程序。在CVI中,可以通过编写回调函数来响应控件的事件。

如果希望多个控件共用一个回调函数,可以按照以下步骤操作:

在回调函数所在的源文件中,定义一个枚举类型变量,用于标识每个控件。例如:

typedef enum {
    BUTTON_1,
    BUTTON_2,
    ...
} ControlID;


在每个控件的属性对话框中,设置一个自定义的ID号,用于标识该控件。这个ID号可以是任意整数,但要保证不同控件的ID号不同。例如,设置按钮控件的ID号为1和2。

在每个控件的回调函数中,通过GetCtrlAttribute函数获取控件的ID号,并根据ID号来确定是哪个控件触发了事件。例如:


int panelHandle = 0;  // 界面句柄
int id;  // 控件ID号
GetPanelHandleFromTabPage (panelHandle, TAB_PAGE_1, &panelHandle);
GetCtrlAttribute (panelHandle, controlHandle, ATTR_CTRL_ID, &id);
switch (id) {
    case BUTTON_1:
        // 处理按钮1的事件
        break;
    case BUTTON_2:
        // 处理按钮2的事件
        break;
    ...
}

在每个控件的属性对话框中,将事件回调函数设置为共用的回调函数。例如,设置按钮1和按钮2的回调函数都为同一个回调函数。

SetCtrlAttribute (panelHandle, BUTTON_1, ATTR_CALLBACK_FUNCTION_POINTER, &ButtonCallback);
SetCtrlAttribute (panelHandle, BUTTON_2, ATTR_CALLBACK_FUNCTION_POINTER, &ButtonCallback);


完整的示例代码如下:


typedef enum {
    BUTTON_1,
    BUTTON_2,
} ControlID;

int panelHandle = 0;

int CVICALLBACK ButtonCallback (int controlHandle, int event, void *callbackData, int eventData1, int eventData2)
{
    int id;
    GetPanelHandleFromTabPage (panelHandle, TAB_PAGE_1, &panelHandle);
    GetCtrlAttribute (panelHandle, controlHandle, ATTR_CTRL_ID, &id);
    switch (id) {
        case BUTTON_1:
            if (event == EVENT_COMMIT) {
                MessagePopup ("Button 1", "Button 1 clicked!");
            }
            break;
        case BUTTON_2:
            if (event == EVENT_COMMIT) {
                MessagePopup ("Button 2", "Button 2 clicked!");
            }
            break;
    }
    return 0;
}

int main (int argc, char *argv[])
{
    if ((panelHandle = LoadPanel (0, "MyPanel.uir", TAB_PAGE_1)) < 0) {
        return -1;
    }
    SetCtrlAttribute (panelHandle, BUTTON_1, ATTR_CALLBACK_FUNCTION_POINTER, &ButtonCallback);
    SetCtrlAttribute (panelHandle, BUTTON_2, ATTR_CALLBACK_FUNCTION_POINTER, &ButtonCallback);
    DisplayPanel


#include <cvirte.h>    
#include <userint.h>
#include <utility.h>

static int panelHandle;
static int textBoxHandle;

int CVICALLBACK buttonCallback(int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
    if (event == EVENT_COMMIT)
    {
        char buf[10];
        sprintf(buf, "%d", control);
        SetCtrlVal(textBoxHandle, 0, buf);
    }
    return 0;
}

int main (int argc, char *argv[])
{
    if (InitCVIRTE (0, argv, 0) == 0)
        return -1;
    
    panelHandle = LoadPanel (0, "example.uir", 0);
    textBoxHandle = GetCtrlHandleFromPanel(panelHandle, 1);
    
    SetCtrlAttribute(panelHandle, 2, ATTR_CALLBACK_FUNCTION_POINTER, buttonCallback);
    SetCtrlAttribute(panelHandle, 3, ATTR_CALLBACK_FUNCTION_POINTER, buttonCallback);
    SetCtrlAttribute(panelHandle, 2, ATTR_CALLBACK_DATA, (void*)2);
    SetCtrlAttribute(panelHandle, 3, ATTR_CALLBACK_DATA, (void*)3);
    
    DisplayPanel (panelHandle);
    RunUserInterface ();
    DiscardPanel (panelHandle);
    return 0;
}