将 hFont (CreateFontA) 传递给 CreateWindowEx

Passing hFont (CreateFontA) to CreateWindowEx

已解决!!!

我最初的问题是 CreateFont 函数是否可以与 CreateWindow 函数一起使用。我在文档中找到的所有内容都让我相信它只适用于文本函数。

由于我无法实施所提供的建议并且在我的问题上没有取得任何进展,我采用了一种新方法。我创建了我的测试代码,这样我就可以轻松地在 WM_CREATE: 和 WM_PAINT: 中所做的更改之间切换。现在可以更轻松地破解我在文档、搜索和脑海中突然出现的内容。

以下是我的测试代码。添加和删​​除 styleSelection 的评论让我 select 我正在做的事情。

全局:HFONT hFont;

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  HDC hdc;

  string styleSelection = "WM_CREATE";
 //styleSelection = "WM_PAINT";

  switch(uMsg) {
     case WM_CLOSE: {
      DeleteObject(hFont);
      DestroyWindow(hWnd);
      break;
    }
    case WM_COMMAND: {
      DeleteObject(hFont);
      PostQuitMessage(0);
      break;
    }
    case WM_CREATE: {
      HINSTANCE hIns = ((LPCREATESTRUCT)lParam)->hInstance;
      if((styleSelection == "WM_CREATE") && (hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE")))) {

        int textHStart = 20; int textLineSpace = 16;
        vector < int > textVStart = { 20,60,100,120,160 };
        vector < string > newStrings;
        newStrings = getDynamicData();                    // Get the strings for output

        for(int i = 0; i < newStrings.size(); i++) {
          CreateWindowEx(NULL, TEXT("Static"), newStrings[i].c_str(), WS_CHILD | WS_VISIBLE, textHStart, textVStart[i], newStrings[i].length() * 10, textLineSpace, hWnd, (HMENU)IDC_USER_LABEL, hIns, NULL);
        }
      }

      HWND hButton = CreateWindowA(_T("button"), _T("Exit"), WS_CHILD | WS_VISIBLE, 385, 250, 60, 25, hWnd, (HMENU)IDC_BUTTON, hIns, 0);
      return 0;
    } 
    case WM_DESTROY: {
      DeleteObject(hFont);
      PostQuitMessage(0);
      break;
    }
    case WM_CTLCOLORSTATIC: { 
      HDC hEdit = (HDC)wParam;
      SetTextColor(hEdit, RGB(0, 0, 0)); 
      //SetBkColor(hEdit, RGB(0xFF, 0x00, 0x00)); 
      SetBkMode(hEdit, TRANSPARENT);
      return (INT_PTR)GetStockObject(HOLLOW_BRUSH);
    }
    case WM_PAINT: {
      PAINTSTRUCT ps;
      hdc = BeginPaint(hWnd, &ps);


      if((styleSelection == "WM_PAINT") && (hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE")))) {
          HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
        
        HDC hEdit = (HDC)wParam;
        SetTextColor(hdc, RGB(0, 0, 0));
        //SetBkColor(hdc, RGB(0xFF, 0x00, 0x00));
        SetBkMode(hdc, TRANSPARENT);
        
        int index = 7;                       // Vertical spaces and number of lines for the array
        const char* cpaText[7] = { "Hello,","", "What I want to do", "is to format this text." };

        for(int iLoopCounter = 0; cpaText[iLoopCounter] != 0; iLoopCounter++, index += 20) {
          TextOutA(hdc, 5, index, cpaText[iLoopCounter], strlen(cpaText[iLoopCounter]));
        }
        SelectObject(hdc, hOldFont);
      }
      EndPaint(hWnd, &ps);
      break;
    }
    default: {
      return DefWindowProcA(hWnd, uMsg, wParam, lParam);
      break;
    }
  }
  return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}

////---- this is  the data to be printed.
vector < string > getDynamicData() {
  vector < string > retvec;
  retvec.push_back("This is a test.");
  retvec.push_back("I am trying to change the text");
  return retvec;
}

我最终想出的解决方案在答案部分。

您不应在 WM_PAINT 处理程序期间调用 CreateWindow

相反,您需要做的是将您创建的字体保存在 WM_CREATE 处理程序中,然后在您获得 WM_PAINT 时使用该字体。 GetWindowLongPtr/SetWindowLongPtrGWLP_USERDATA 是执行此类数据保存的规范方法。

例如:

LRESULT WINAPI MyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg)
  {
  case WM_CREATE:
  {
    if(-1 == DefWindowProc(hWnd, WM_CREATE, wParam, lParam))
    return -1;
    HFONT hFont = CreateFont(...);
   SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)hFont);
  }
    break;

  case WM_DESTROY:
    DestroyObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
    return DefWindowProc(hWnd, WM_DESTROY, wParam, lParam);

  case WM_PAINT:
  {
    DefWindowProc(hWnd, WM_PAINT, wParam, lParam);
    HFONT hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
    ...
  }
    break;

  default:
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

  return 0;
}

也可以在实际创建 window 的任何代码中创建 HFONT,并将 HFONT 作为 lParam 参数传递给 CreateWindow 然后在处理 WM_CREATE 时按照描述保存它(而不是在处理 WM_CREATE 时实际创建 HFONT)。

对于文本框,它已完成

    HFONT newFont = CreateFont(22, 0, 0, 0,0 , FALSE, FALSE, FALSE, DEFAULT_CHARSET,
    OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY,
    DEFAULT_PITCH | FF_DECORATIVE, L"Lucida Console");
    ::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0);

你应该在别处创建所有这些

并使用WS_EX_COMPOSITED

将此 ::PostMessage(hc,WM_SETFONT,(WPARAM)newFont,(LPARAM)0); 添加到您的 for 循环中,直到结束。但不是 hc ofc

我的工作解决方案:

我的一个问题是 WM_PAINT 中的 TextOut 没有使用动态文本。回顾之前使用 Jonathan Potter 在 Add dynamic text to WM_CREATE in C++ using variables 中的建议解决的问题,我终于意识到同样适用于 TextOut。

在我使用 TextOut 处理动态文本后,下一个选择是保留 WM_CREATE 用于标准字体样式,或者将所有内容迁移到 WM_PAINT。我决定迁移到 WM_PAINT 将是更清洁的解决方案。以下是我最终得到的结果:

全局:HFONT hFont;

   LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    HDC hdc;

    string styleSelection = "standardFont";
    styleSelection = "specialFont";

    switch(uMsg) {
      case WM_CREATE: {
        if(-1 == DefWindowProc(hWnd, WM_CREATE, wParam, lParam))
          return -1;
        hFont = CreateFontA(18, 0, 0, 0, FW_DONTCARE, 1, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH, TEXT("DONTCARE"));
        SetWindowLongPtr(hWnd, GWLP_USERDATA, (LPARAM)hFont);
      }
      break;case WM_CLOSE: {
        DeleteObject(hFont);
        DestroyWindow(hWnd);
        break;
      }
      case WM_COMMAND: {
        DeleteObject(hFont);
        PostQuitMessage(0);
        break;
      }
      case WM_DESTROY: {
        //DestroyObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
        DeleteObject((HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA));
        return DefWindowProc(hWnd, WM_DESTROY, wParam, lParam);
      }
      case WM_PAINT: {
        PAINTSTRUCT ps;
        hdc = BeginPaint(hWnd, &ps);
        HDC hEdit = (HDC)wParam;
          SetBkMode(hdc, TRANSPARENT); 


        if(styleSelection == "standardFont") {
          SetTextColor(hdc, RGB(0, 0, 0));   

          int textHStart = 20; int textLineSpace = 16;
          vector < int > textVStart = { 20,60,100,120,160 };
          vector < string > newStrings;
          newStrings = getDynamicData();                    // Get the strings for output

          for(int i = 0; i < newStrings.size(); i++) {
            TextOutA(hdc, textHStart, textVStart[i], newStrings[i].c_str(), newStrings[i].size());
          }
        }
        else {
          DefWindowProc(hWnd, WM_PAINT, wParam, lParam);
          hFont = (HFONT)GetWindowLongPtr(hWnd, GWLP_USERDATA);
          HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
          SetTextColor(hdc, RGB(0xFF, 0x00, 0x00)); 

          int textHStart = 20; int textLineSpace = 16;
          vector < int > textVStart = { 20,60,100,120,160 };
          vector < string > newStrings;
          newStrings = getDynamicData();                    // Get the strings for output

          for(int i = 0; i < newStrings.size(); i++) {
            TextOutA(hdc, textHStart, textVStart[i], newStrings[i].c_str(), newStrings[i].size());
          }
          SelectObject(hdc, hOldFont);
          DeleteObject(hFont);

        }


        EndPaint(hWnd, &ps);
        break;
      }
      default: {
        return DefWindowProcA(hWnd, uMsg, wParam, lParam);
        break;
      }

以上代码也实现了 SoronelHaetir 的一些建议。我会仔细研究一下 SoronelHaetir 的其他建议 我仍然需要处理可能的内存泄漏问题和其他一些平滑项目,但这适用于我想做的事情。所需要的只是阅读、耐心和足够的坚持,直到我弄明白为止。