текст перекладу
Ця стаття присвячена питанню, яке я знайшов під час онлайн-оцінки для BNY. У завданні було одне легке, два середніх і одне важке питання, і це питання відноситься до середніх.
Тоді я не зміг вирішити його, але воно не виходило з моєї голови. Я не зустрічав жодних статей або схожих питань на платформах для програмістів, тому вирішив поділитись ним тут.
Умова задачі:
Вам дано масив розміру n. Ваше завдання — знайти такий підмасив даного масиву, розмір якого не перевищує 'k' і сума всіх елементів цього підмасиву є максимальною серед усіх можливих підмасивів. Тобто, знайти підмасив з максимальною сумою елементів, розмір якого менший або рівний k.
Приклад вхідних даних:
n k
arr0 arr1 arr 2 . . .
7 4
10 1 -9 3 5 -2 7
Приклад вихідних даних:
13
Моє початкове припущення:
Моє початкове припущення було використати стандартний алгоритм Кадена до тих пір, поки розмір підмасиву не досягне ліміту 'k'. Після цього, щоб додати ще один елемент, я би видаляв елемент з іншого кінця, що виглядало б як:
. . . [4 -2 -1 7] 3 . . → . . . 4 [-2 -1 7 3] . .
Звісно, немає сенсу залишати відразу негативні елементи після видалення елемента, оскільки вони не мають впливу на максимізацію суми. Але просто видаляти негативні елементи недостатньо, адже можуть бути більші негативні елементи, сховані за позитивними.
Необхідно знайти та видалити цілу частину підмасиву, чия сума стала негативною після видалення елемента:
. . . [10 -1 3 -9 5] 4 . . → . . . 10 -1 [3 -9 5 4] . .
Як ви можете бачити, 3 приховує -9 від видалення.
Мій підхід полягав у відстеженні мінімального значення поточного підмасиву і при видаленні перевірці, чи стає мінімальне значення непозитивним після віднімання видаленого елемента. Якщо воно непозитивне, я видаляю всю частину підмасиву до мінімуму разом із самим мінімумом.
Проблема цього підходу в тому, що це лише дає нам знання, що частина до мінімуму стала негативною, але не гарантує, що права частина буде позитивною. Очевидно, ми не можемо шукати точку перегину в підмасиві, оскільки це призведе до рішення з часом O(N²).
Остаточне рішення:
Розглянемо наступний графік:
Вищезгадана крива представляє масив префіксних сум, де крива піднімається, коли масив містить позитивні значення, і опускається, коли містить негативні.
Тепер, якщо ми подивимось на криву в межах вікна розміру k і виділимо максимуми кривої:
Тепер, як видно, A — це найбільше значення префіксної суми для перших k значень. Отже, буде правильно припустити, що для перших k елементів максимальний підмасив суми буде існувати між точками O і A. Тому все, що нам потрібно зробити — це порівняти суму від O до A з глобальним максимумом. Але є підступ, лінія між O і A може виглядати так:
У цьому випадку максимальний підмасив суми буде між x і A.
Це означає, що ми повинні перевірити суму підмасиву, сформованого кожним елементом від O до A з A. Це дасть нам найкращу суму між O і A. Але, коли ми рухаємось від точки O до O+1, наша зона пошуку зменшується з k до k-1. Тому ми повинні також зрушити наше вікно на крок вперед від k до k+1.
Перша ітерація: (вікно: від O до K, сума підмасиву: від O до A)
Друга ітерація: (вікно від O+1 до K+1,
сума підмасиву: від O+1 до A)
Коли ми це робимо, ми також повинні оновити список максимумів, з якими працюємо, оскільки взаємодіємо з новими елементами з масиву. Якщо з’являється, скажімо, ще один елемент C з префіксної суми, який більший за A, ми перевіримо суму від O+1 до C, замість перевірки від O+1 до A.
текст перекладу
У майбутньому, якщо я буду реалізовувати систему вкладок, як у Notepad++, у нас буде список TextEditor в нашому MainWindow або в іншому батьківському вікні, яке буде дочірнім до MainWindow.
Ієрархія
Перед тим, як продовжити, будь ласка, переконайтесь, що ви знаєте, що таке вікно?
Добре, давайте продовжимо
Налаштування
Деякі зміни були внесені в CMakeLists.txt, як ви можете побачити нижче:
cmake_minimum_required(VERSION 3.29.2)
project(ProtoText)
# Визначення для Unicode
add_definitions(-DUNICODE -D_UNICODE)
# Прапорець /MANIFEST:NO вказує компілятору не генерувати та не вбудовувати маніфест.
if (WIN32)
set(CMAKE_SHARED_LINKER_FLAGS /MANIFEST:NO)
endif()
file(GLOB SRC "src/*.cpp")
include_directories(include)
add_executable(${PROJECT_NAME} WIN32 ${SRC})
# Зробити додаток DPI-освідомленим
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND "mt.exe" -manifest \"${CMAKE_SOURCE_DIR}/dpiAware.manifest\" -outputresource:"${CMAKE_SOURCE_DIR}/out/build/x64-Debug/${PROJECT_NAME}.exe"\;\#1
COMMENT "Додавання маніфесту..."
)
# Лінкуємо необхідні бібліотеки
target_link_libraries(${PROJECT_NAME}
User32
Gdi32
Kernel32
Advapi32
DWrite
)
Я коротко поясню деякі зміни з останнього разу.
- if оператор та addcustomcommand оператор: Мета цих змін — зробити наш додаток освідомленим до DPI. В кореневій директорії проекту буде файл з назвою dpiAware.manifest, вміст якого можна знайти на сторінці документації за посиланням. Оператор if вимикає генерацію чи вбудовування маніфестів, тому що addcustomcommand має виконати цю операцію.
- targetlinklibraries: Я видалив розширення .lib, оскільки мені сказали, що це погана практика, адже CMake може самостійно визначити необхідні параметри.
текст перекладу
Також, якщо ми реалізуємо систему вкладок, як у Notepad++, у нас буде список TextEditor в нашому MainWindow або в іншому батьківському вікні, яке буде дочірнім до MainWindow.
Ієрархія
Перед тим, як продовжити, будь ласка, переконайтесь, що ви знаєте, що таке вікно?
Добре, давайте продовжимо
Налаштування
Деякі зміни були внесені в CMakeLists.txt, як ви можете побачити нижче:
cmake_minimum_required(VERSION 3.29.2)
project(ProtoText)
# Визначення для Unicode
add_definitions(-DUNICODE -D_UNICODE)
# Прапорець /MANIFEST:NO вказує компілятору не генерувати та не вбудовувати маніфест.
if (WIN32)
set(CMAKE_SHARED_LINKER_FLAGS /MANIFEST:NO)
endif()
file(GLOB SRC "src/*.cpp")
include_directories(include)
add_executable(${PROJECT_NAME} WIN32 ${SRC})
# Зробити додаток DPI-освідомленим
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND "mt.exe" -manifest \"${CMAKE_SOURCE_DIR}/dpiAware.manifest\" -outputresource:"${CMAKE_SOURCE_DIR}/out/build/x64-Debug/${PROJECT_NAME}.exe"\;\#1
COMMENT "Додавання маніфесту..."
)
# Лінкуємо необхідні бібліотеки
target_link_libraries(${PROJECT_NAME}
User32
Gdi32
Kernel32
Advapi32
DWrite
)
Я коротко поясню деякі зміни з останнього разу.
- if оператор та addcustomcommand оператор: Мета цих змін — зробити наш додаток освідомленим до DPI. В кореневій директорії проекту буде файл з назвою dpiAware.manifest, вміст якого можна знайти на сторінці документації за посиланням. Оператор if вимикає генерацію чи вбудовування маніфестів, тому що addcustomcommand має виконати цю операцію.
- targetlinklibraries: Я видалив розширення .lib, оскільки мені сказали, що це погана практика, адже CMake може самостійно визначити необхідні параметри.
текст перекладу
Тепер давайте подивимось
Основний код
#ifndef UNICODE
#define UNICODE
#endif
#include
#include "MainWindow.h"
#include "WindowCircle.h"
static int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
ProtoText::MainWindow mainWindow;
ProtoText::WindowCreateSettings settings(hInstance, L"Proto Text", WS_OVERLAPPEDWINDOW);
if(!mainWindow.Create(settings))
{
return 0;
}
//https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
ShowWindow(mainWindow.WindowHandle(), nCmdShow);
//Запускаємо цикл повідомлень
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Припустимо, що пояснення не потрібні, давайте тепер подивимось
Головне Вікно
Заголовок:
#ifndef _PROTO_MAIN_WINDOW_
#define _PROTO_MAIN_WINDOW_
#include
#include
#include "Window.h"
#include "CommCtrl.h"
#include "TextEditor.h"
#define IDM_NEW 1001
#define IDM_OPEN 1002
#define IDM_SAVE 1003
namespace ProtoText
{
class MainWindow : public ProtoText::Window
{
private:
HWND CreateToolbar();
HWND CreateTextEditor(HWND hwndToolbar);
TextEditor m_TextEditor;
HWND m_hwndToolbar;
HWND m_hwndTextEditor;
public:
PCWSTR ClassName() const;
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
MainWindow();
};
}
#endif
Декілька моментів, на які слід звернути увагу:
- Задані визначення не мають великого значення.
текст перекладу
Також ви можете побачити DWrite, який використовується для відображення тексту у вікні.
З нашою готовою конфігурацією CMakeLists.txt, ми можемо перейти до основної частини, а саме
Основний код
#ifndef UNICODE
#define UNICODE
#endif
#include
#include "MainWindow.h"
#include "WindowCircle.h"
static int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
ProtoText::MainWindow mainWindow;
ProtoText::WindowCreateSettings settings(hInstance, L"Proto Text", WS_OVERLAPPEDWINDOW);
if(!mainWindow.Create(settings))
{
return 0;
}
//https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
ShowWindow(mainWindow.WindowHandle(), nCmdShow);
//Запускаємо цикл повідомлень
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Припускаючи, що пояснень не потрібно, давайте тепер подивимось
Головне Вікно
Заголовок:
#ifndef _PROTO_MAIN_WINDOW_
#define _PROTO_MAIN_WINDOW_
#include
#include
#include "Window.h"
#include "CommCtrl.h"
#include "TextEditor.h"
#define IDM_NEW 1001
#define IDM_OPEN 1002
#define IDM_SAVE 1003
namespace ProtoText
{
class MainWindow : public ProtoText::Window
{
private:
HWND CreateToolbar();
HWND CreateTextEditor(HWND hwndToolbar);
TextEditor m_TextEditor;
HWND m_hwndToolbar;
HWND m_hwndTextEditor;
public:
PCWSTR ClassName() const;
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
MainWindow();
};
}
#endif
Декілька моментів, на які слід звернути увагу:
- Задані визначення не мають великого значення.
текст перекладу
return 0;
}
case WMCREATE:
{
mhwndToolbar = MainWindow::CreateToolbar();
mhwndTextEditor = MainWindow::CreateTextEditor(mhwndToolbar);
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
//Усі операції малювання виконуються тут, між BeginPaint і EndPaint
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 9));
EndPaint(hwnd, &ps);
return 0;
}
//Коли головне вікно змінює розмір
case WM_SIZE:
{
//Отримуємо координати зміненої області головного вікна
RECT mainWindowRect;
GetClientRect(hwnd, &mainWindowRect);
RECT toolbarRect;
GetClientRect(m_hwndToolbar, &toolbarRect);
int toolbarHeight = toolbarRect.bottom - toolbarRect.top;
//Змінюємо розміри панелі інструментів і текстового редактора
MoveWindow(mhwndToolbar, 0, 0, mainWindowRect.right, toolbarHeight, TRUE);
MoveWindow(mhwndTextEditor, toolbarRect.left, toolbarRect.bottom, mainWindowRect.right, mainWindowRect.bottom, TRUE);
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
```
Щоб краще зрозуміти цей код, будь ласка, ознайомтесь з функцією MoveWindow, а також з структурою RECT. Функція MoveWindow() також викликає WMSIZE_ в дочірньому TextEditor, тому реалізуйте його логіку зміни розміру та малювання там.
Також зверніть увагу на рядок:
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 9));
COLORWINDOW + 1_ заповнює вікно білим кольором, а COLORWINDOW + 9_ заповнює вікно синім. Я використовував це для налагодження. Я заповнив головне вікно синім кольором і текстовий редактор білим, щоб перевірити, чи правильно відображаються вікна. Спочатку текстовий редактор не з'являвся, про що свідчив синій колір. Він з'явився після того, як я використав MoveWindow(). Тому ви можете використовувати це для налагодження.
Сподіваюся, код зрозумілий завдяки коментарям.
текст перекладу
Текстовий редактор
Заголовок:
#ifndef _PROTO_TEXT_EDITOR_
#define _PROTO_TEXT_EDITOR_
#include
#include "Window.h"
#include
#include
namespace ProtoText
{
class TextEditor : public ProtoText::Window
{
private:
IDWriteFactory* mp_dWriteFactory; //Створює ресурси DWrite
IDWriteTextFormat* mp_dWriteTextFormat; //Для налаштування властивостей тексту
WCHAR* mp_text; //Текст, що буде відображатися
UINT32 m_textLength; //Довжина тексту, що буде відображатися
ID2D1Factory* mp_d2d1Factory; //Фабрика Direct2D, що створює всі ресурси Direct2D
ID2D1HwndRenderTarget* mp_hwndRenderTarget; //Ціль, на яку буде відображено вміст
ID2D1SolidColorBrush* mp_blackBrush; //Пензель, який використовується для малювання на цілі
HRESULT Initialize();
HRESULT OnResize();
void CleanUp();
void RenderText();
public:
TextEditor();
PCWSTR ClassName() const;
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
};
}
#endif //!_PROTO_TEXT_EDITOR_
А тепер код:
#include "TextEditor.h"
ProtoText::TextEditor::TextEditor()
:mp_dWriteFactory(nullptr), mp_dWriteTextFormat(nullptr), mp_d2d1Factory(nullptr),
mp_hwndRenderTarget(nullptr), mp_blackBrush(nullptr), mp_text(nullptr), m_textLength(0)
{
}
HRESULT ProtoText::TextEditor::Initialize()
{
HWND hwndTextEditor = TextEditor::WindowHandle();
/*
ПРИСТРОЙНО-НЕНАВІСНІ РЕСУРСИ
*/
HRESULT hr;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &mp_d2d1Factory);
if (SUCCEEDED(hr))
{
hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory),
reinterpret_cast(&mp_dWriteFactory));
mp_text = L"Hello World ! This is Proto Text";
m_textLength = (UINT32)wcslen(mp_text);
hr = mp_dWriteFactory->CreateTextFormat(
L"Gabriola",
NULL,
DWRITE_FONT_WEIGHT_REGULAR,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
72.0f,
L"en-us",
&mp_dWriteTextFormat
);
mp_dWriteTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
mp_dWriteTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
}
/*
ПРИСТРОЙНО-ЗАЛЕЖНІ РЕСУРСИ
*/
RECT rc;
GetClientRect(hwndTextEditor, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
if (!mp_hwndRenderTarget)
{
hr = mp_d2d1Factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(hwndTextEditor,size), &mp_hwndRenderTarget);
if (SUCCEEDED(hr))
{
hr = mp_hwndRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mp_blackBrush);
}
}
return hr;
}
HRESULT ProtoText::TextEditor::OnResize()
{
HWND hwndTextEditor = TextEditor::WindowHandle();
RECT rc;
GetClientRect(hwndTextEditor, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
HRESULT hr = mp_hwndRenderTarget->Resize(size);
mp_hwndRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mp_blackBrush);
//Не думаю, що два наступні рядки щось роблять.
текст перекладу
Ви можете перевірити це самі
mp_dWriteTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
mp_dWriteTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
InvalidateRect(hwndTextEditor, nullptr, TRUE);
return hr;
}
void ProtoText::TextEditor::RenderText()
{
HWND hwndTextEditor = TextEditor::WindowHandle();
FLOAT dpiX, dpiY;
mp_d2d1Factory->GetDesktopDpi(&dpiX, &dpiY);
FLOAT dpiScaleX = dpiX / 96.0f;
FLOAT dpiScaleY = dpiY / 96.0f;
RECT rc;
GetClientRect(hwndTextEditor, &rc);
D2D1_RECT_F textAreaSize = D2D1::RectF(
static_cast< FLOAT >(rc.left) / dpiScaleX,
static_cast< FLOAT >(rc.top) / dpiScaleY,
static_cast< FLOAT >(rc.right - rc.left) / dpiScaleX,
static_cast< FLOAT >(rc.bottom - rc.top) / dpiScaleY
);
mp_hwndRenderTarget->DrawText(mp_text, m_textLength, mp_dWriteTextFormat, textAreaSize, mp_blackBrush);
}
void ProtoText::TextEditor::CleanUp()
{
SafeRelease(&mp_hwndRenderTarget);
SafeRelease(&mp_blackBrush);
}
PCWSTR ProtoText::TextEditor::ClassName() const
{
return L"TextEditor";
}
LRESULT ProtoText::TextEditor::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND hwnd = TextEditor::WindowHandle();
switch (uMsg)
{
case WM_CREATE:
{
Initialize();
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
//FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
mp_hwndRenderTarget->BeginDraw();
mp_hwndRenderTarget->SetTransform(D2D1::IdentityMatrix());
mp_hwndRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
RenderText();
mp_hwndRenderTarget->EndDraw();
EndPaint(hwnd, &ps);
return 0;
}
case WM_SIZE:
{
InvalidateRect(hwnd, nullptr, TRUE);
OnResize();
return 0;
}
case WM_DESTROY:
{
CleanUp();
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Сподіваюся, код зрозумілий завдяки коментарям, а документація допоможе вам повністю зрозуміти процес. Перед тим як завершити, я надам код для WindowCircle, який малює коло на екрані. Це код прямо з документації, і я надаю його просто для довідки. Я використовую це як посилання для програм на Direct2D. Я не надаватиму нічого, що потрібно робити в main(), лише код у якості бонусної секції. Ви можете розібратися з цим самі.
текст перекладу
Давайте подивимося
WindowCircle
Заголовок:
#include
#include
#pragma comment(lib, "d2d1")
#include "Window.h"
namespace ProtoText
{
class WindowCircle : public ProtoText::Window
{
private:
ID2D1Factory *pFactory;
ID2D1HwndRenderTarget *pRenderTarget;
ID2D1SolidColorBrush *pBrush;
D2D1_ELLIPSE ellipse;
void CalculateLayout();
HRESULT CreateGraphicsResources();
void DiscardGraphicsResources();
void OnPaint();
void Resize();
public:
WindowCircle() : pFactory(nullptr), pRenderTarget(nullptr), pBrush(nullptr)
{
}
LPCWSTR ClassName() const override;
LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
};
}
А ось і вихідний код:
#include "WindowCircle.h"
void ProtoText::WindowCircle::CalculateLayout()
{
if (pRenderTarget != nullptr)
{
D2D1_SIZE_F size = pRenderTarget->GetSize();
const float x = size.width / 2;
const float y = size.height / 2;
const float radius = min(x, y);
ellipse = D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius);
}
}
HRESULT ProtoText::WindowCircle::CreateGraphicsResources()
{
HRESULT hr = S_OK;
if (pRenderTarget == nullptr)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
hr = pFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&pRenderTarget);
if (SUCCEEDED(hr))
{
const D2D1_COLOR_F color = D2D1::ColorF(1.0f, 1.0f, 0);
hr = pRenderTarget->CreateSolidColorBrush(color, &pBrush);
if (SUCCEEDED(hr))
{
CalculateLayout();
}
}
}
return hr;
}
void ProtoText::WindowCircle::DiscardGraphicsResources()
{
SafeRelease(&pRenderTarget);
SafeRelease(&pBrush);
}
void ProtoText::WindowCircle::OnPaint()
{
HRESULT hr = CreateGraphicsResources();
if (SUCCEEDED(hr))
{
PAINTSTRUCT ps;
BeginPaint(m_hwnd, &ps);
pRenderTarget->BeginDraw();
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
pRenderTarget->FillEllipse(ellipse, pBrush);
hr = pRenderTarget->EndDraw();
if (FAILED(hr) || hr == D2DERR_RECREATE_TARGET)
{
DiscardGraphicsResources();
}
EndPaint(m_hwnd, &ps);
}
}
void ProtoText::WindowCircle::Resize()
{
if (pRenderTarget != nullptr)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right, rc.bottom);
pRenderTarget->Resize(size);
CalculateLayout();
InvalidateRect(m_hwnd, nullptr, FALSE);
}
}
LPCWSTR ProtoText::WindowCircle::ClassName() const
{
return L"Circle Window Class";
}
LRESULT ProtoText::WindowCircle::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HWND hwnd = WindowCircle::WindowHandle();
switch (uMsg)
{
case WM_CREATE:
if (FAILED(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pFactory)))
{
return -1;
}
return 0;
case WM_DESTROY:
DiscardGraphicsResources();
SafeRelease(&pFactory);
PostQuitMessage(0);
return 0;
case WM_PAINT:
OnPaint();
return 0;
case WM_SIZE:
Resize();
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Висновок
Отже, ми бачили код для Window, MainWindow, TextEditor та бонусного WindowCircle. Я надав відповідні посилання на джерела для всіх використаних функцій та структур. Я також зібрав усі необхідні посилання на документацію в розділі “Посилання” нижче. Зверніть увагу, що я уникнув пояснень концепцій або функцій, оскільки ця стаття не є "уроком з нуля", а скоріше орієнтована на використання як посібник із того, як я робив певну річ для досягнення певного результату.
текст перекладу
Щоб досягти цього, я доводилося звертатися до різних розділів і документацій, тому я хочу, щоб моя стаття стала центральною точкою для посилань, щоб усі майбутні учні могли правильно орієнтуватися.
Я хочу ще раз підкреслити: НЕ ПРОПУСКАЙТЕ документацію. Спробуйте зробити це самостійно, читаючи документацію, і використовуйте цю статтю лише як неформальне посилання. Переконайтеся, що ви розумієте такі концепції, як вікна, HWND, черги повідомлень тощо, щоб зрозуміти, як працюють програми Win32 загалом.
Наступного разу ми, сподіваюся, зустрінемося, коли я реалізую курсори, введення тексту з клавіатури та текст, відображений подібно до будь-якого текстового редактора. Тому, дорогий читачу, ми, сподіваюся, зустрінемося скоро.
Хочу подякувати вам за те, що залишилися до кінця. Бажаю вам удачі на вашому шляху з Win32. Дякую і гарного дня.
Але перш ніж ви підете, подивіться на
Посилання
Почніть тут і переконайтеся, що ви все зрозуміли. Переконайтеся, що ви прочитали і зробили це самостійно, і не думайте навіть слідувати, поки не прочитаєте це: Початок роботи з Win32 і C++ — Win32 додатки | Microsoft Learn
Для панелей інструментів дотримуйтесь цього: Панель інструментів — Win32 додатки | Microsoft Learn. Можливо, спробуйте зрозуміти: Елементи управління вікнами — Win32 додатки | Microsoft Learn
Щодо дочірніх вікон (легке читання): Використання вікон — Win32 додатки | Microsoft Learn
І нарешті, для DirectWrite: Посібник з початку роботи з DirectWrite — Win32 додатки | Microsoft Learn
Перекладено з: Win32 Text Editor— Text Rendering in a Child Window using DirectWrite