Win32 GUI 和 C++ 回调功能

发布于 2024-10-24 09:14:03 字数 2124 浏览 2 评论 0原文

所以,基本上我正在使用这样的代码。这是一个简单的小窗口,您只能在其中更改编辑框中的文本,然后按一个按钮来回调函数(DoSomethingCallback(text))。

#include <windows.h>

#define ID_EDIT 1
#define ID_BUTTON 2

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

  static HWND hwndEdit;
  static HWND hwndButton;
  static int len;
  static TCHAR text[30];


  switch(msg)
  {
    case WM_CREATE:
    hwndEdit = CreateWindow(TEXT("Edit"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
                50, 50, 150, 20, hwnd, (HMENU) ID_EDIT,
                NULL, NULL);

    hwndButton = CreateWindow(
        TEXT("button"), TEXT("Set Title"),       
        WS_VISIBLE | WS_CHILD,  
        50, 100, 80, 25,        
        hwnd, (HMENU) ID_BUTTON, NULL, NULL);      

    break;

    case WM_COMMAND:    
           if (HIWORD(wParam) == BN_CLICKED) {
               SetWindowText(hwnd, "Working...");
               GetWindowText(hwndEdit, text, len);
               DoSomethingCallback(text);
               SetWindowText(hwnd, "Finished");
           }
    break;

    case WM_DESTROY:
        PostQuitMessage(0);
    break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
            LPSTR lpCmdLine, int nCmdShow )
{
  MSG  msg ;    
  WNDCLASS wc = {0};
  wc.lpszClassName = TEXT( "Edit Control" );
  wc.hInstance     = hInstance ;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc ;
  wc.hCursor       = LoadCursor(0,IDC_ARROW);


  RegisterClass(&wc);
  CreateWindow( wc.lpszClassName, TEXT("Edit control"),
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                220, 220, 280, 200, 0, 0, hInstance, 0);  

  while( GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}

问题是,当运行该回调时,窗口将显示为“无响应”,如果您尝试关闭或按下按钮,窗口甚至会出现延迟。我理解发生这种情况的原因,回调需要时间,并且接收循环不存在来检查用户的输入。我已经寻找了一种“修复”此问题的方法,但找不到任何方法。我很确定这很愚蠢,但我必须尝试问一下。

一个明显的方法是进行更快的回调。但是是否还有另一种方法,例如检查 DoSomethingCallback() 内部的用户输入,或者我必须使用多个线程?

很抱歉提出了令人困惑的问题。

So, basically I'm using a code like this one. It's a little simple window where you can only change text inside of an edit box and press a button that will make a callback to a function (DoSomethingCallback(text)).

#include <windows.h>

#define ID_EDIT 1
#define ID_BUTTON 2

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

  static HWND hwndEdit;
  static HWND hwndButton;
  static int len;
  static TCHAR text[30];


  switch(msg)
  {
    case WM_CREATE:
    hwndEdit = CreateWindow(TEXT("Edit"), NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
                50, 50, 150, 20, hwnd, (HMENU) ID_EDIT,
                NULL, NULL);

    hwndButton = CreateWindow(
        TEXT("button"), TEXT("Set Title"),       
        WS_VISIBLE | WS_CHILD,  
        50, 100, 80, 25,        
        hwnd, (HMENU) ID_BUTTON, NULL, NULL);      

    break;

    case WM_COMMAND:    
           if (HIWORD(wParam) == BN_CLICKED) {
               SetWindowText(hwnd, "Working...");
               GetWindowText(hwndEdit, text, len);
               DoSomethingCallback(text);
               SetWindowText(hwnd, "Finished");
           }
    break;

    case WM_DESTROY:
        PostQuitMessage(0);
    break;
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
            LPSTR lpCmdLine, int nCmdShow )
{
  MSG  msg ;    
  WNDCLASS wc = {0};
  wc.lpszClassName = TEXT( "Edit Control" );
  wc.hInstance     = hInstance ;
  wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  wc.lpfnWndProc   = WndProc ;
  wc.hCursor       = LoadCursor(0,IDC_ARROW);


  RegisterClass(&wc);
  CreateWindow( wc.lpszClassName, TEXT("Edit control"),
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                220, 220, 280, 200, 0, 0, hInstance, 0);  

  while( GetMessage(&msg, NULL, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return (int) msg.wParam;
}

The problem is that when running that Callback the window will appear as "Not responsive" and even laggy if you try to close or press the button. I understand the reason why this might be happening, the callback takes time and the receiving loop isn't there to check the input of the user. I've searched a way to 'fix' this and I couldn't find any. I'm pretty sure it's something dumb, but I have to try and ask.

An obvious way would be making a faster callback. But is there another one like checking the user input inside of a DoSomethingCallback() while, or I have to use multiple threads?

Sorry for the confusing question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅忆 2024-10-31 09:14:03

我会去打电话 QueueUserWorkItem() 来处理它。如果 DoSomethingCallback() 太长,则在 DoSomethingCallback() 工作时无法使窗口做出响应,因为只有一个线程来运行代码。祝你好运!

I would go for calling QueueUserWorkItem() to handle it. If your DoSomethingCallback() is too long, there is no way to make your window responsive while DoSomethingCallback() is working since there is only one thread to run the code. Good Luck!

烟沫凡尘 2024-10-31 09:14:03

如果可能,您可以在 DoSomethingCallback 内定期处理消息队列,这将使 UI 保持响应。只要有可能就运行原始消息循环,即 while( GetMessage(...),但请确保禁用该按钮,以便用户不会再次单击...这将导致递归。

If possible, you can process the message queue at intervals within DoSomethingCallback which will keep the UI responsive. Just run the original message loop i.e. while( GetMessage(... whenever you can but make sure you disable the button so the user does not click a second time... this will lead to recursion.

情魔剑神 2024-10-31 09:14:03

您可以通过不时调用 PeekMessage() 来查看消息队列,让窗口相信您还活着并且还在运行。这假设您可以在 DoSomethingCallback() 中执行此操作,即主线程不会完全挂起。将下面的循环视为伪代码,并发挥您的想象力将其转换为您的需要。

void DoSomethingCallback()
{
  // Loop that takes a long time
  while (true) {
    DoSomeStuff();
    MSG msg;
    PeekMessage(&msg, nil, 0, 0, PM_NOREMOVE);
    if (ShouldBreak()) {
      break;
    }
  }
}

You can peek at the message queue to convince windows that you are still alive and kicking, by calling PeekMessage() from time to time. This assumes that you can do this in your DoSomethingCallback(), i.e. that the main thread doesn't hang completely. Regard the loop below as pseudo code and use your imagination to transform it to your needs.

void DoSomethingCallback()
{
  // Loop that takes a long time
  while (true) {
    DoSomeStuff();
    MSG msg;
    PeekMessage(&msg, nil, 0, 0, PM_NOREMOVE);
    if (ShouldBreak()) {
      break;
    }
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文