Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Interfejsów API kompozycji środowiska uruchomieniowego Windows (nazywanych również Visual Layer) można używać w aplikacjach Win32, aby tworzyć nowoczesne środowiska, które zachwycą użytkowników systemu Windows.
Kompletny kod do tego samouczka jest dostępny na GitHubie: Win32 HelloComposition przykład.
Aplikacje uniwersalne systemu Windows, które wymagają dokładnej kontroli nad kompozycją interfejsu użytkownika, mają dostęp do przestrzeni nazw Windows.UI.Composition , aby wywierać precyzyjną kontrolę nad sposobem komponowania i renderowania interfejsu użytkownika. Ten interfejs API kompozycji nie jest jednak ograniczony do aplikacji platformy UWP. Aplikacje klasyczne Win32 mogą korzystać z nowoczesnych systemów kompozycji w systemach UWP i Windows.
Wymagania wstępne
Interfejs API hostingu platformy UWP ma te wymagania wstępne.
- Zakładamy, że masz pewną znajomość tworzenia aplikacji przy użyciu win32 i platformy UWP. Aby uzyskać więcej informacji, zobacz:
- Windows 10 w wersji 1803 lub nowszej
- Windows 10 SDK 17134 lub nowszy
Jak używać interfejsów API kompozycji z aplikacji desktopowej Win32
W tym samouczku utworzysz prostą aplikację Win32 C++ i dodasz do niej elementy kompozycji platformy UWP. Fokus polega na poprawnym konfigurowaniu projektu, tworzeniu kodu międzyoperacyjnego i rysowaniu czegoś prostego przy użyciu interfejsów API kompozycji systemu Windows. Gotowa aplikacja wygląda następująco.
Tworzenie projektu Win32 języka C++ w programie Visual Studio
Pierwszym krokiem jest utworzenie projektu aplikacji Win32 w programie Visual Studio.
Aby utworzyć nowy projekt aplikacji Win32 w języku C++ o nazwie HelloComposition:
Otwórz program Visual Studio i wybierz pozycję Plik >Nowy>Projekt.
Otwiera się okno dialogowe Nowy projekt.
W kategorii Zainstalowane rozwiń węzeł Visual C++, a następnie wybierz pozycję Windows Desktop.
Wybierz szablon aplikacji klasycznej systemu Windows.
Wprowadź nazwę HelloComposition, a następnie kliknij przycisk OK.
Program Visual Studio tworzy projekt i otwiera edytor dla głównego pliku aplikacji.
Konfigurowanie projektu do używania interfejsów API środowiska uruchomieniowego systemu Windows
Aby używać interfejsów API środowiska Uruchomieniowego systemu Windows (WinRT) w aplikacji Win32, używamy języka C++/WinRT. Musisz skonfigurować projekt programu Visual Studio, aby dodać obsługę języka C++/WinRT.
(Aby uzyskać szczegółowe informacje, zobacz Get started with C++/WinRT - Modify a Windows Desktop application project to add C++/WinRT support (Wprowadzenie do języka C++/WinRT — modyfikowanie projektu aplikacji klasycznych systemu Windows w celu dodania obsługi języka C++/WinRT).
W menu Project (Projekt ) otwórz właściwości projektu (HelloComposition Properties) i upewnij się, że następujące ustawienia są ustawione na określone wartości:
- W sekcji Configurationwybierz opcję Wszystkie konfiguracje. Dla platformywybierz Wszystkie platformy.
- Właściwości konfiguracji>Ogólne>Windows SDK w wersji = 10.0.17763.0 lub nowszej
ustaw wersję SDK

-
C/C++ Language Standard C++ Language Standard ISO C++ 17 Standard (/stf:c++17)
- konsolidator>wejściowe>dodatkowe zależności musi zawierać "windowsapp.lib". Jeśli nie znajduje się ona na liście, dodaj ją.
Aktualizowanie prekompilowanego nagłówka
Zmień odpowiednio nazwy
stdafx.histdafx.cppnapch.hipch.cpp.Ustaw właściwość projektu C/C++>Nagłówki prekompilowane>Plik nagłówka prekompilowanego na pch.h.
Znajdź i zastąp
#include "stdafx.h"na#include "pch.h"we wszystkich plikach.(Edytowanie>Znajdowanie i Zastępowanie>Znajdowanie w Plikach)
W
pch.huwzględnijwinrt/base.hiunknwn.h.// reference additional headers your program requires here #include <unknwn.h> #include <winrt/base.h>
Dobrym pomysłem jest utworzenie projektu w tym momencie, aby upewnić się, że nie ma żadnych błędów przed rozpoczęciem pracy.
Tworzenie klasy do hostowania elementów kompozycji
Aby hostować zawartość tworzoną za pomocą warstwy wizualnej, utwórz klasę (CompositionHost), aby zarządzać międzyoperacją i tworzyć elementy kompozycji. Większość konfiguracji do hostowania interfejsów API kompozycji odbywa się tutaj, w tym:
- pobieranie compositor, który tworzy obiekty i zarządza nimi w przestrzeni nazw Windows.UI.Composition.
- tworzenie DispatcherQueueController/DispatcherQueue do zarządzania zadaniami dla interfejsów API WinRT.
- Tworzenie DesktopWindowTarget i kontenera kompozycji w celu wyświetlenia obiektów kompozycji.
Staramy się, aby ta klasa była singletonem, aby uniknąć problemów z wątkami. Na przykład można utworzyć tylko jedną kolejkę dyspozytora na wątek, więc utworzenie drugiego wystąpienia obiektu CompositionHost w tym samym wątku spowoduje błąd.
Wskazówka
Jeśli chcesz, sprawdź kompletny kod na końcu samouczka, aby upewnić się, że cały kod znajduje się w odpowiednich miejscach podczas pracy z samouczkiem.
Dodaj nowy plik klasy do projektu.
- W Eksploratorze rozwiązań kliknij prawym przyciskiem myszy projekt HelloComposition .
- W menu kontekstowym wybierz pozycję Dodaj>klasę....
- W oknie dialogowym Dodaj klasę nadaj klasie nazwę CompositionHost.cs, a następnie kliknij Dodaj.
Uwzględnij nagłówki i przy użyciu wymagane do współdziałania kompozycji.
- W pliku CompositionHost.h dodaj te zawiera w górnej części pliku.
#pragma once #include <winrt/Windows.UI.Composition.Desktop.h> #include <windows.ui.composition.interop.h> #include <DispatcherQueue.h>- W CompositionHost.cpp dodaj te przy użyciu w górnej części pliku, po zawiera.
using namespace winrt; using namespace Windows::System; using namespace Windows::UI; using namespace Windows::UI::Composition; using namespace Windows::UI::Composition::Desktop; using namespace Windows::Foundation::Numerics;Edytuj klasę, aby używać wzorca singleton.
- W pliku CompositionHost.h ustaw konstruktor jako prywatny.
- Zadeklaruj publiczną statyczną metodę GetInstance .
class CompositionHost { public: ~CompositionHost(); static CompositionHost* GetInstance(); private: CompositionHost(); };- W CompositionHost.cpp dodaj definicję metody GetInstance .
CompositionHost* CompositionHost::GetInstance() { static CompositionHost instance; return &instance; }W pliku CompositionHost.h zadeklaruj prywatne zmienne członkowskie dla Compositor, DispatcherQueueController i DesktopWindowTarget.
winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr }; winrt::Windows::System::DispatcherQueueController m_dispatcherQueueController{ nullptr }; winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_target{ nullptr };Dodaj publiczną metodę do inicjalizacji obiektów kompozycji międzyoperacyjnej.
Uwaga / Notatka
Podczas inicjalizacjiwywołujesz metody EnsureDispatcherQueue, CreateDesktopWindowTargetoraz CreateCompositionRoot. Te metody są tworzone w następnych krokach.
- W pliku CompositionHost.h zadeklaruj metodę publiczną o nazwie Initialize , która przyjmuje HWND jako argument.
void Initialize(HWND hwnd);- W CompositionHost.cpp dodaj definicję metody Initialize .
void CompositionHost::Initialize(HWND hwnd) { EnsureDispatcherQueue(); if (m_dispatcherQueueController) m_compositor = Compositor(); CreateDesktopWindowTarget(hwnd); CreateCompositionRoot(); }Utwórz kolejkę dyspozytora w wątku, który będzie używać kompozycji systemu Windows.
Kompozytor musi zostać utworzony w wątku, który ma kolejkę dyspozycyjną, więc ta metoda jest wywoływana jako pierwsza podczas początkowej inicjalizacji.
- W pliku CompositionHost.h zadeklaruj metodę prywatną o nazwie EnsureDispatcherQueue.
void EnsureDispatcherQueue();- W CompositionHost.cpp dodaj definicję metody EnsureDispatcherQueue .
void CompositionHost::EnsureDispatcherQueue() { namespace abi = ABI::Windows::System; if (m_dispatcherQueueController == nullptr) { DispatcherQueueOptions options { sizeof(DispatcherQueueOptions), /* dwSize */ DQTYPE_THREAD_CURRENT, /* threadType */ DQTAT_COM_ASTA /* apartmentType */ }; Windows::System::DispatcherQueueController controller{ nullptr }; check_hresult(CreateDispatcherQueueController(options, reinterpret_cast<abi::IDispatcherQueueController**>(put_abi(controller)))); m_dispatcherQueueController = controller; } }Zarejestruj okno aplikacji jako element docelowy kompozycji.
- W pliku CompositionHost.h zadeklaruj metodę prywatną o nazwie CreateDesktopWindowTarget , która przyjmuje HWND jako argument.
void CreateDesktopWindowTarget(HWND window);- W CompositionHost.cpp dodaj definicję metody CreateDesktopWindowTarget .
void CompositionHost::CreateDesktopWindowTarget(HWND window) { namespace abi = ABI::Windows::UI::Composition::Desktop; auto interop = m_compositor.as<abi::ICompositorDesktopInterop>(); DesktopWindowTarget target{ nullptr }; check_hresult(interop->CreateDesktopWindowTarget(window, false, reinterpret_cast<abi::IDesktopWindowTarget**>(put_abi(target)))); m_target = target; }Utwórz główny kontener wizualizacji do przechowywania obiektów wizualnych.
- W pliku CompositionHost.h zadeklaruj metodę prywatną o nazwie CreateCompositionRoot.
void CreateCompositionRoot();- W CompositionHost.cpp dodaj definicję metody CreateCompositionRoot .
void CompositionHost::CreateCompositionRoot() { auto root = m_compositor.CreateContainerVisual(); root.RelativeSizeAdjustment({ 1.0f, 1.0f }); root.Offset({ 124, 12, 0 }); m_target.Root(root); }
Skompiluj teraz projekt, aby upewnić się, że nie ma żadnych błędów.
Te metody umożliwiają skonfigurowanie składników wymaganych do współdziałania między warstwą wizualizacji platformy UWP i interfejsami API Win32. Teraz możesz dodać zawartość do aplikacji.
Dodawanie elementów kompozycji
Po zainstalowaniu infrastruktury możesz teraz wygenerować zawartość kompozycji, którą chcesz wyświetlić.
W tym przykładzie dodasz kod, który tworzy losowo kolorowy kwadrat SpriteVisual z animacją, która powoduje spadek po krótkim opóźnieniu.
Dodaj element kompozycji.
- W pliku CompositionHost.h zadeklaruj metodę publiczną o nazwie AddElement, która przyjmuje 3 wartości typu float jako argumenty.
void AddElement(float size, float x, float y);- W CompositionHost.cpp dodaj definicję metody AddElement .
void CompositionHost::AddElement(float size, float x, float y) { if (m_target.Root()) { auto visuals = m_target.Root().as<ContainerVisual>().Children(); auto visual = m_compositor.CreateSpriteVisual(); auto element = m_compositor.CreateSpriteVisual(); uint8_t r = (double)(double)(rand() % 255);; uint8_t g = (double)(double)(rand() % 255);; uint8_t b = (double)(double)(rand() % 255);; element.Brush(m_compositor.CreateColorBrush({ 255, r, g, b })); element.Size({ size, size }); element.Offset({ x, y, 0.0f, }); auto animation = m_compositor.CreateVector3KeyFrameAnimation(); auto bottom = (float)600 - element.Size().y; animation.InsertKeyFrame(1, { element.Offset().x, bottom, 0 }); using timeSpan = std::chrono::duration<int, std::ratio<1, 1>>; std::chrono::seconds duration(2); std::chrono::seconds delay(3); animation.Duration(timeSpan(duration)); animation.DelayTime(timeSpan(delay)); element.StartAnimation(L"Offset", animation); visuals.InsertAtTop(element); visuals.InsertAtTop(visual); } }
Tworzenie i wyświetlanie okna
Teraz możesz dodać przycisk i zawartość kompozycji platformy UWP do interfejsu użytkownika win32.
W HelloComposition.cpp na początku pliku załącz CompositionHost.h, zdefiniuj BTN_ADD i uzyskaj wystąpienie CompositionHost.
#include "CompositionHost.h" // #define MAX_LOADSTRING 100 // This is already in the file. #define BTN_ADD 1000 CompositionHost* compHost = CompositionHost::GetInstance();W metodzie
InitInstancezmień rozmiar utworzonego okna. (W tym wierszu zmień wartośćCW_USEDEFAULT, 0na900, 672.)HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 900, 672, nullptr, nullptr, hInstance, nullptr);W funkcji WndProc dodaj
case WM_CREATEdo bloku przełącznika komunikatu. W takim przypadku zainicjujesz CompositionHost i utworzysz przycisk.case WM_CREATE: { compHost->Initialize(hWnd); srand(time(nullptr)); CreateWindow(TEXT("button"), TEXT("Add element"), WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON, 12, 12, 100, 50, hWnd, (HMENU)BTN_ADD, nullptr, nullptr); } break;Ponadto w funkcji WndProc obsłuż kliknięcie przycisku, aby dodać element kompozycji do interfejsu użytkownika.
Dodaj
do bloku przełącznika wmId w bloku w WM_COMMAND. case BTN_ADD: // addButton click { double size = (double)(rand() % 150 + 50); double x = (double)(rand() % 600); double y = (double)(rand() % 200); compHost->AddElement(size, x, y); break; }
Teraz możesz skompilować i uruchomić aplikację. Jeśli chcesz, sprawdź kompletny kod na końcu samouczka, aby upewnić się, że cały kod znajduje się we właściwych miejscach.
Po uruchomieniu aplikacji i kliknięciu przycisku powinny zostać wyświetlone animowane kwadraty dodane do interfejsu użytkownika.
Dodatkowe zasoby
- Przykład HelloComposition Win32 (GitHub)
- Rozpocznij pracę z Win32 i C++
- Wprowadzenie do aplikacji systemu Windows (UWP)
- Ulepsz swoją aplikację desktopową dla systemu Windows (UWP)
- przestrzeń nazw Windows.UI.Composition (UWP)
Kompletny kod
Oto kompletny kod dla klasy CompositionHost i metody InitInstance.
CompositionHost.h
#pragma once
#include <winrt/Windows.UI.Composition.Desktop.h>
#include <windows.ui.composition.interop.h>
#include <DispatcherQueue.h>
class CompositionHost
{
public:
~CompositionHost();
static CompositionHost* GetInstance();
void Initialize(HWND hwnd);
void AddElement(float size, float x, float y);
private:
CompositionHost();
void CreateDesktopWindowTarget(HWND window);
void EnsureDispatcherQueue();
void CreateCompositionRoot();
winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr };
winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget m_target{ nullptr };
winrt::Windows::System::DispatcherQueueController m_dispatcherQueueController{ nullptr };
};
CompositionHost.cpp
#include "pch.h"
#include "CompositionHost.h"
using namespace winrt;
using namespace Windows::System;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Composition::Desktop;
using namespace Windows::Foundation::Numerics;
CompositionHost::CompositionHost()
{
}
CompositionHost* CompositionHost::GetInstance()
{
static CompositionHost instance;
return &instance;
}
CompositionHost::~CompositionHost()
{
}
void CompositionHost::Initialize(HWND hwnd)
{
EnsureDispatcherQueue();
if (m_dispatcherQueueController) m_compositor = Compositor();
if (m_compositor)
{
CreateDesktopWindowTarget(hwnd);
CreateCompositionRoot();
}
}
void CompositionHost::EnsureDispatcherQueue()
{
namespace abi = ABI::Windows::System;
if (m_dispatcherQueueController == nullptr)
{
DispatcherQueueOptions options
{
sizeof(DispatcherQueueOptions), /* dwSize */
DQTYPE_THREAD_CURRENT, /* threadType */
DQTAT_COM_ASTA /* apartmentType */
};
Windows::System::DispatcherQueueController controller{ nullptr };
check_hresult(CreateDispatcherQueueController(options, reinterpret_cast<abi::IDispatcherQueueController**>(put_abi(controller))));
m_dispatcherQueueController = controller;
}
}
void CompositionHost::CreateDesktopWindowTarget(HWND window)
{
namespace abi = ABI::Windows::UI::Composition::Desktop;
auto interop = m_compositor.as<abi::ICompositorDesktopInterop>();
DesktopWindowTarget target{ nullptr };
check_hresult(interop->CreateDesktopWindowTarget(window, false, reinterpret_cast<abi::IDesktopWindowTarget**>(put_abi(target))));
m_target = target;
}
void CompositionHost::CreateCompositionRoot()
{
auto root = m_compositor.CreateContainerVisual();
root.RelativeSizeAdjustment({ 1.0f, 1.0f });
root.Offset({ 124, 12, 0 });
m_target.Root(root);
}
void CompositionHost::AddElement(float size, float x, float y)
{
if (m_target.Root())
{
auto visuals = m_target.Root().as<ContainerVisual>().Children();
auto visual = m_compositor.CreateSpriteVisual();
auto element = m_compositor.CreateSpriteVisual();
uint8_t r = (double)(double)(rand() % 255);;
uint8_t g = (double)(double)(rand() % 255);;
uint8_t b = (double)(double)(rand() % 255);;
element.Brush(m_compositor.CreateColorBrush({ 255, r, g, b }));
element.Size({ size, size });
element.Offset({ x, y, 0.0f, });
auto animation = m_compositor.CreateVector3KeyFrameAnimation();
auto bottom = (float)600 - element.Size().y;
animation.InsertKeyFrame(1, { element.Offset().x, bottom, 0 });
using timeSpan = std::chrono::duration<int, std::ratio<1, 1>>;
std::chrono::seconds duration(2);
std::chrono::seconds delay(3);
animation.Duration(timeSpan(duration));
animation.DelayTime(timeSpan(delay));
element.StartAnimation(L"Offset", animation);
visuals.InsertAtTop(element);
visuals.InsertAtTop(visual);
}
}
HelloComposition.cpp (częściowe)
#include "pch.h"
#include "HelloComposition.h"
#include "CompositionHost.h"
#define MAX_LOADSTRING 100
#define BTN_ADD 1000
CompositionHost* compHost = CompositionHost::GetInstance();
// Global Variables:
// ...
// ... code not shown ...
// ...
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance; // Store instance handle in our global variable
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, 900, 672, nullptr, nullptr, hInstance, nullptr);
// ...
// ... code not shown ...
// ...
}
// ...
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
// Add this...
case WM_CREATE:
{
compHost->Initialize(hWnd);
srand(time(nullptr));
CreateWindow(TEXT("button"), TEXT("Add element"),
WS_VISIBLE | WS_CHILD | BS_PUSHBUTTON,
12, 12, 100, 50,
hWnd, (HMENU)BTN_ADD, nullptr, nullptr);
}
break;
// ...
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
// Add this...
case BTN_ADD: // addButton click
{
double size = (double)(rand() % 150 + 50);
double x = (double)(rand() % 600);
double y = (double)(rand() % 200);
compHost->AddElement(size, x, y);
break;
}
// ...
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code that uses hdc here...
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// ...
// ... code not shown ...
// ...
Windows developer