Рисование цветного текста в c win32

#c #winapi

#c #winapi

Вопрос:

Возможно ли нарисовать цветной текст в соответствии с тем, что я уже сделал?

Я пробовал WM_CTLCOLORSTATIC , CreateSolidBrush() , и несколько других функций.

 //-----------------------------------
// Learning the win32 API for C  
//
// Created by: Cosmic Cruizer
//-----------------------------------

#include <windows.h>
#include <tchar.h>

// Function declarations
bool SetUpWindowClass (char*, int, int, int);         // Remove window structure from WinMain and put into function
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM)  // Pre-declare Windows procedure/function

// Global variables
const char CLASS_NAME[] = "My Window Class Array";    // declared for window class; Can be static or const


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){
  //Step 1: Registering the Window Class
  HWND hwnd{};                                       // This is the handle for our window
  MSG msg{};                                         // Handle for messages to the application
  SetUpWindowClass (NULL, NULL, NULL, NULL);         // The Window structure - removed from main and made into a function

  // Step 2: Creating the Window
  hwnd = CreateWindowEx(             // returns a handle to the new window, or zero if the function fails
    WS_EX_CLIENTEDGE,                // Optional window styles. Can be set to 0
    CLASS_NAME,                      // Name of window class, see set 1b. Also set as the constant
    "My First C   Windows App",      // Window title text
    WS_OVERLAPPEDWINDOW,             // Window style, title bar, a border, a system menu, and Minimize and Maximize buttons.
    200, 200, 500, 400,              // Size and position
    NULL, NULL, hInstance, NULL);    // Parent window, Menu, Instance handle, Additional app data

  // Add an exit button
   CreateWindow(
    "BUTTON",                        // Predefined class; Unicode assumed
    "EXIT",                          // Button text
    WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,  // Styles
    200, 200, 60, 25,                // x position, y position, Button width, Button height
    hwnd,                            // Parent window
    NULL,                            // No menu.
    (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE), NULL);   // Pointer not needed.

  ShowWindow(hwnd, nCmdShow);        // Make the window visible on the screen


  // Step 3: The Message Loop
  while(GetMessage(amp;msg, NULL, 0, 0) != 0)  {       // Run the message loop. It will run until GetMessage() returns 0
    TranslateMessage(amp;msg);          // Translate virtual-key messages into character messages
    DispatchMessage(amp;msg);           // Send message to WindowProcedure
  }

  return msg.wParam;
}

//---------- Functions ----------//

// Setup the window structure
bool SetUpWindowClass (char *cpTitle, int iR, int iG, int iB) {
  //Step 1a:  The Window structure
  WNDCLASSEX wc{};                            // Data structure for the windowclass
  wc.cbSize            = sizeof(WNDCLASSEX);  // Sets the size of the Windows API
  wc.style             = 0;                   // define additional elements of the window class
  wc.lpfnWndProc       = WndProc;             // defines most of the behavior of the window. See setp 4 "LRESULT CALLBACK WndProc" function
  wc.cbClsExtra        = 0;                   // No extra bytes after the window class
  wc.cbWndExtra        = 0;                   // structure for the window instance
  wc.hInstance         = GetModuleHandle (NULL); // handle to the application instance.
  wc.hIcon             = LoadIcon(NULL, IDI_APPLICATION);   // handle to icon class, if NULL, system provides a default icon.
  wc.hCursor           = LoadCursor(NULL, IDC_ARROW);       // handle to cursor class
  wc.hbrBackground     = (HBRUSH)(COLOR_WINDOW 18);         // Add color as the background of the window
  wc.lpszMenuName      = NULL;                // No menu
  wc.lpszClassName     = CLASS_NAME;          // string that identifies the window class
  wc.hIconSm           = LoadIcon(NULL, IDI_APPLICATION);

  //Step 1b:  Register the window class, and if it fails quit the program
  if (RegisterClassEx (amp;wc)) return true;
  else return false;
}


// Step 4: the Window Procedure in this function
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
  switch(uMsg){
    case WM_CLOSE:{
      DestroyWindow(hwnd);
      break;
    }
    case WM_COMMAND:{               // Close the window when exit is pressed
      if (MessageBox(hwnd, "Really quit?", "Exit Warning", MB_OKCANCEL) == IDOK){ // what the hell, just wanted this.
        PostQuitMessage(0);
       }
         break;
    }
    case WM_DESTROY:{
      PostQuitMessage(0);
      break;
    }

//--- trying to create colored text ---//
    case WM_CTLCOLORSTATIC:{
      HDC hdcStatic = (HDC) wParam;             // handle to display context
      hwnd = (HWND) lParam; // handle to control window
      SetTextColor(hdcStatic, RGB(100,255,255));
      SetBkColor(hdcStatic, RGB(250,250,6));
      return (INT_PTR)CreateSolidBrush(RGB(250,250,100));
    }
    case WM_CTLCOLOREDIT:{
      HDC hdcStatic = (HDC) wParam;
      SetTextColor(hdcStatic, RGB(0,0,255));
      SetBkColor(hdcStatic, RGB(0,230,0));
      return (INT_PTR)CreateSolidBrush(RGB(0,230,0));
    }


    case WM_PAINT:{                     // All painting (text) occurs here, between BeginPaint and EndPaint.
      PAINTSTRUCT ps;                   // Holds info about current painting session.
      HDC hdc = BeginPaint(hwnd, amp;ps);  // Create the device context (DC)

      // Each character is added to the cpaText array. Then the for loop goes through and paints each character
      int iY = 7;                       // Vertical spaces and number of lines for the array
      const char *cpaText [iY] = {      // changed from char to const char to get rid of warning. and added 1 for each line and a return
        "Hello Peoples",
        "",
        "This is my first attempt to program using the Win32 API.",
        "I can only hope it gets better with time.",
        "",
        "Created by "The" Cosmic Cruizer"
      };
      for (int iLoopCounter = 0; cpaText [iLoopCounter] != 0; iLoopCounter  , iY  = 20) {
        TextOut (hdc, 5, iY, cpaText [iLoopCounter], strlen (cpaText [iLoopCounter]));
      }

      EndPaint(hwnd, amp;ps);              // Free up HDC created with BeginPaint
      break;
    }
    default:{
      return DefWindowProc(hwnd, uMsg, wParam, lParam); // Return is needed either here or at the end
      break;
    }
  }

  return DefWindowProc(hwnd, uMsg, wParam, lParam); // Return is needed either here or in the default case
}
  

Комментарии:

1. очевидно, вы используете SetTextColor

2. @user253751 важной частью является то, что он должен быть в WM_PAINT обработчике после того, как вы создали HDC, но перед вызовом TextOut .

3. кстати, поздравляю вас с тем, что вы провели свое исследование и не задали глупый вопрос. Например. когда кто-то сказал использовать WM_CTLCOLORSTATIC , вы на самом деле написали для него разумный обработчик, а не просто пытались вставить слово WM_CTLCOLORSTATIC в случайные места в вашем коде, как это сделали бы некоторые люди 🙂 (Я думаю, что ваш обработчиквсе еще протекают кисти)

Ответ №1:

WM_CTLCOLORSTATIC и WM_CTLCOLOREDIT являются уведомительными сообщениями, используемыми STATIC / EDIT controls , ни одно из которых у вас нет в вашем окне, поэтому вы никогда не получите эти сообщения и должны удалить эти обработчики из своего кода.

Вы пытаетесь нарисовать цветной текст непосредственно в своем окне, используя TextOutA() WM_PAINT обработчик, и это нормально. Но согласно TextOutA() документации:

Функция вывода текста записывает строку символов в указанное место, используя выбранный в данный момент шрифт, цвет фона и цвет текста.

Ваш WM_PAINT обработчик ничего не выбирает в HDC BeginPaint() возвращаемом, прежде чем пытаться рисовать на нем. Ему просто нужно настроить желаемые значения шрифта / цвета по желанию, например:

 HFONT hFont;

LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){
  switch(uMsg){
    ...
    case WM_CREATE:{
      hFont = CreateFont(...); // or CreateFontIndirect()
      break;
    }

    case WM_DESTROY:{
      DeleteObject(hFont);
      PostQuitMessage(0);
      break;
    }

    case WM_SETTINGCHANGE:
    case WM_FONTCHANGE:{
      DeleteObject(hFont);
      hFont = CreateFont(...); // or CreateFontIndirect()
      InvalidateRect(hwnd, NULL, TRUE);
      break;
    }

    case WM_PAINT:{
      PAINTSTRUCT ps;
      HDC hdc = BeginPaint(hwnd, amp;ps);

      HFONT hOldFont = (HFONT) SelectObject(hdc, hFont);
      SetTextColor(hdc, ...);
      SetBkColor(hdc, ...);

      int iY = 7;
      const char *cpaText [iY] = {
        "Hello Peoples",
        "",
        "This is my first attempt to program using the Win32 API.",
        "I can only hope it gets better with time.",
        "",
        "Created by "The" Cosmic Cruizer"
      };
      for (int iLoopCounter = 0; cpaText [iLoopCounter] != 0; iLoopCounter  , iY  = 20) {
        TextOutA (hdc, 5, iY, cpaText [iLoopCounter], strlen (cpaText [iLoopCounter]));
      }

      SelectObject(hdc, hOldFont);

      EndPaint(hwnd, amp;ps);
      return 0;
    }
    ...
  }

  return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
  

Комментарии:

1. Это было слишком просто после всех дней, когда я бодался головой. Изначально я пробовал SetTextColor и SetBkColor в WM_PAINT, но полностью пропустил CreateFont и SelectObject. Я удалил операторы case для WM_CTLCOLORSTATIC и WM_CTLCOLOREDIT. Все еще работаю / играю с HFONT hFont = CreateFont(…) . Есть много интересных опций, но это работает! Спасибо за объяснение TexOut. После того, как вы объяснили это и показали мне, что делать, это было похоже на удар по лбу. Кроме того, спасибо, что убедились, что я выполнил очистку. Это было у меня на уме, но ваше дополнение убедило, что оно не было забыто.

2. Вы действительно не хотите делать CreateFont внутри WM_PAINT обработчика, который будет вызываться много-много раз за время существования окна. Достаточно получить HFONT один раз, пока вы вызываете SelectObject с помощью in для каждого WM_PAINT . Педантично, вы должны DeleteFont и CreateFont снова на WM_SETTINGCHANGE и WM_FONTCHANGE , но большинство запусков программы, вероятно, не увидят ни одного из этих сообщений даже один раз.

3. @BenVoigt хороший момент о создании шрифта только один раз. Я обновил свой пример, чтобы продемонстрировать это.

4. Я попытался переместить CreateFont в WM_CREATE, но я получаю сообщение об ошибке. (Не собираюсь объяснять причину ошибки, я хочу попытаться решить ее самостоятельно.) Нужно прекратить играть сегодня, но, надеюсь, вернемся к нему завтра. Спасибо!

5. Понял мою ошибку. Это было просто. Необходимо объявить hFont. Я разместил его под своими глобальными переменными. Теперь я вижу, что у вас это есть, я просто не уловил. Вы также добавили WM_SETTINGCHANGE и WM_FONTCHANGE. Я пошел и прочитал о них, но не уверен, почему вы их добавили. Я играл с ними, и на данный момент они не имеют никакого значения. Прямо сейчас я их прокомментировал, и я могу понять, что с ними делать.