#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. Я пошел и прочитал о них, но не уверен, почему вы их добавили. Я играл с ними, и на данный момент они не имеют никакого значения. Прямо сейчас я их прокомментировал, и я могу понять, что с ними делать.