Как ускорить перерисовку фонового изображения в CFormView ⇐ C++
Как ускорить перерисовку фонового изображения в CFormView
У меня есть одно приложение-шаблон документа. Основное представление наследует CFormView, который рисует png-изображение на фоне. Кроме того, я хочу поместить объект на основе CDialog в этот CFormView. Этот объект, Fragment, имеет элемент управления CStic, текст которого я хочу обновить. Фон этого элемента управления сделан прозрачным. Я обнаружил, что в случае фонового изображения в CFormView текст элемента управления Fragment накладывается на себя при обновлении. Я пытался сделать недействительной соответствующую область как в CStic, так и в Fragment, но это не помогает — похоже, что текст рисуется на родительском фоне. Итак, я начал аннулировать регион CFormView.
Это помогает, но есть проблема: при обновлении текста CStatic мигает, как будто он (или его фон) рисуется с задержкой (или слишком медленно), и я хочу избежать этого мигания. (Пыталась записать гифку, но на ней не видно моргания.)
Вот код:
fragment.h:
#pragma один раз #include "afxdialogex.h" #include "Фрагмент.h" #include "resource.h" Фрагмент класса: публичный CDialog { публика: Фрагмент(CWnd* pParent = nullptr): CDialog(IDD_FRAGMENT1, pParent) {} HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); недействительным OnBnClickedButton1 (); #ifdef AFX_DESIGN_TIME перечисление { ИДД = IDD_FRAGMENT1 }; #endif защищено: DECLARE_DYNAMIC (фрагмент) DECLARE_MESSAGE_MAP() void DoDataExchange(CDataExchange* pDX); CStatic m_label; }; fragment.cpp:
#include "pch.h" #include "Фрагмент.h" IMPLEMENT_DYNAMIC (фрагмент, CDialog) BEGIN_MESSAGE_MAP (фрагмент, CDialog) ON_WM_CTLCOLOR() ON_BN_CLICKED(IDC_BUTTON1, &Fragment::OnBnClickedButton1) END_MESSAGE_MAP() void Fragment::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LABEL, m_label); } void Fragment::OnBnClickedButton1() { для (int я = 0; я < 10; ++i) { CString текст; text.Format(L"Привет, статический — %d%%", i); m_label.SetWindowText(текст); CRect прямой; m_label.GetWindowRect(&rect); GetParent()->ScreenToClient(&rect); GetParent()->InvalidateRect(&rect); GetParent()->UpdateWindow(); Сон(1000); } } Фрагмент HBRUSH::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { pDC->SetBkMode(ПРОЗРАЧНЫЙ); вернуть (HBRUSH) GetStockObject (NULL_BRUSH); } 'MainView.h':
#pragma один раз #include класс Фрагмент; класс MainView: общедоступный CFormView { публика: #ifdef AFX_DESIGN_TIME перечисление {IDD = IDD_TRANSPARENTDIALOG_FORM}; #endif MainDoc* GetDocument() const; виртуальный BOOL PreCreateWindow(CREATESTRUCT& cs); защищено: MainView() нет кроме; DECLARE_DYNCREATE (главное представление) void DoDataExchange(CDataExchange* pDX); недействительный OnInitialUpdate(); защищено: DECLARE_MESSAGE_MAP() Фрагмент* фрагмент = nullptr; std::unique_ptr m_backgroundImage = nullptr; BOOL MainView::OnEraseBkgnd(CDC* dc); }; 'MainView.cpp':
#include "pch.h" #include "framework.h" #include "resource.h" #include "Фрагмент.h" #include "TransparentDialog.h" #include "MainDoc.h" #include "MainView.h" IMPLEMENT_DYNCREATE(MainView, CFormView) BEGIN_MESSAGE_MAP (MainView, CFormView) ON_WM_ERASEBKGND() END_MESSAGE_MAP() Gdiplus::Image* LoadImageFromMemory(данные uint8_t*, размер ULONG) { IStream* MemoryStream = nullptr; УЛОНГ написано = 0; auto createStreamResult = CreateStreamOnHGlobal (NULL, TRUE, &memoryStream); если (createStreamResult != S_OK) { вернуть нульптр; } HRESULT hr = MemoryStream-> Write(данные, размер, & записано); если (!УСПЕШНО(ч)) { MemoryStream-> Release(); вернуть нульптр; } автоматическое изображение = новый Gdiplus::Image(memoryStream); MemoryStream-> Release(); вернуть изображение; } Gdiplus::Image* LoadPngFromResources(UINT resourcesId) { Gdiplus::Image* image = nullptr; HRSRC resourcesHandle = FindResource(NULL, MAKEINTRESOURCE(resourceId), L"PNG"); если (resourceHandle) { HGLOBAL ресурс = LoadResource(NULL, resourcesHandle); если (ресурс) { uint8_t* resourcesData = reinterpret_cast(LockResource(resource)); если (resourceData) { изображение = LoadImageFromMemory(resourceData, SizeofResource(NULL, resourcesHandle)); } } } вернуть изображение; } MainView::MainView() noException : CFormView(IDD_TRANSPARENTDIALOG_FORM) { m_backgroundImage = std::unique_ptr(LoadPngFromResources(IDB_PNG1)); } void MainView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); } BOOL MainView::PreCreateWindow(CREATESTRUCT& cs) { вернуть CFormView::PreCreateWindow(cs); } void MainView::OnInitialUpdate() { CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); фрагмент = новый фрагмент (это); фрагмент-> Создать (IDD_FRAGMENT1, это); фрагмент->ShowWindow(истина); } BOOL MainView::OnEraseBkgnd(CDC* dc) { Gdiplus::Графика графика(dc->m_hDC); графика.DrawImage( m_backgroundImage.get(), 0, 0, m_backgroundImage.get()->GetWidth(), m_backgroundImage.get()->GetHeight()); вернуть истину; } MainDoc* MainView::GetDocument() const { вернуть (MainDoc*)m_pDocument; } Примечание: обновление текста при нажатии кнопки 10 раз с перерывом в режиме ожидания предназначено только для целей тестирования. После удаления Sleep и настройки обновления текста только один раз при нажатии кнопки мерцание все равно сохранится.
Кроме того, я обнаружил, что обновление текста здесь не имеет значения: мерцание сохраняется даже при простом обновлении родительского окна с помощью следующего кода:
void Fragment::OnBnClickedButton1() { CRect прямой; m_label.GetWindowRect(&rect); GetParent()->ScreenToClient(&rect); GetParent()->InvalidateRect(&rect); GetParent()->UpdateWindow(); }
У меня есть одно приложение-шаблон документа. Основное представление наследует CFormView, который рисует png-изображение на фоне. Кроме того, я хочу поместить объект на основе CDialog в этот CFormView. Этот объект, Fragment, имеет элемент управления CStic, текст которого я хочу обновить. Фон этого элемента управления сделан прозрачным. Я обнаружил, что в случае фонового изображения в CFormView текст элемента управления Fragment накладывается на себя при обновлении. Я пытался сделать недействительной соответствующую область как в CStic, так и в Fragment, но это не помогает — похоже, что текст рисуется на родительском фоне. Итак, я начал аннулировать регион CFormView.
Это помогает, но есть проблема: при обновлении текста CStatic мигает, как будто он (или его фон) рисуется с задержкой (или слишком медленно), и я хочу избежать этого мигания. (Пыталась записать гифку, но на ней не видно моргания.)
Вот код:
fragment.h:
#pragma один раз #include "afxdialogex.h" #include "Фрагмент.h" #include "resource.h" Фрагмент класса: публичный CDialog { публика: Фрагмент(CWnd* pParent = nullptr): CDialog(IDD_FRAGMENT1, pParent) {} HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor); недействительным OnBnClickedButton1 (); #ifdef AFX_DESIGN_TIME перечисление { ИДД = IDD_FRAGMENT1 }; #endif защищено: DECLARE_DYNAMIC (фрагмент) DECLARE_MESSAGE_MAP() void DoDataExchange(CDataExchange* pDX); CStatic m_label; }; fragment.cpp:
#include "pch.h" #include "Фрагмент.h" IMPLEMENT_DYNAMIC (фрагмент, CDialog) BEGIN_MESSAGE_MAP (фрагмент, CDialog) ON_WM_CTLCOLOR() ON_BN_CLICKED(IDC_BUTTON1, &Fragment::OnBnClickedButton1) END_MESSAGE_MAP() void Fragment::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_LABEL, m_label); } void Fragment::OnBnClickedButton1() { для (int я = 0; я < 10; ++i) { CString текст; text.Format(L"Привет, статический — %d%%", i); m_label.SetWindowText(текст); CRect прямой; m_label.GetWindowRect(&rect); GetParent()->ScreenToClient(&rect); GetParent()->InvalidateRect(&rect); GetParent()->UpdateWindow(); Сон(1000); } } Фрагмент HBRUSH::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { pDC->SetBkMode(ПРОЗРАЧНЫЙ); вернуть (HBRUSH) GetStockObject (NULL_BRUSH); } 'MainView.h':
#pragma один раз #include класс Фрагмент; класс MainView: общедоступный CFormView { публика: #ifdef AFX_DESIGN_TIME перечисление {IDD = IDD_TRANSPARENTDIALOG_FORM}; #endif MainDoc* GetDocument() const; виртуальный BOOL PreCreateWindow(CREATESTRUCT& cs); защищено: MainView() нет кроме; DECLARE_DYNCREATE (главное представление) void DoDataExchange(CDataExchange* pDX); недействительный OnInitialUpdate(); защищено: DECLARE_MESSAGE_MAP() Фрагмент* фрагмент = nullptr; std::unique_ptr m_backgroundImage = nullptr; BOOL MainView::OnEraseBkgnd(CDC* dc); }; 'MainView.cpp':
#include "pch.h" #include "framework.h" #include "resource.h" #include "Фрагмент.h" #include "TransparentDialog.h" #include "MainDoc.h" #include "MainView.h" IMPLEMENT_DYNCREATE(MainView, CFormView) BEGIN_MESSAGE_MAP (MainView, CFormView) ON_WM_ERASEBKGND() END_MESSAGE_MAP() Gdiplus::Image* LoadImageFromMemory(данные uint8_t*, размер ULONG) { IStream* MemoryStream = nullptr; УЛОНГ написано = 0; auto createStreamResult = CreateStreamOnHGlobal (NULL, TRUE, &memoryStream); если (createStreamResult != S_OK) { вернуть нульптр; } HRESULT hr = MemoryStream-> Write(данные, размер, & записано); если (!УСПЕШНО(ч)) { MemoryStream-> Release(); вернуть нульптр; } автоматическое изображение = новый Gdiplus::Image(memoryStream); MemoryStream-> Release(); вернуть изображение; } Gdiplus::Image* LoadPngFromResources(UINT resourcesId) { Gdiplus::Image* image = nullptr; HRSRC resourcesHandle = FindResource(NULL, MAKEINTRESOURCE(resourceId), L"PNG"); если (resourceHandle) { HGLOBAL ресурс = LoadResource(NULL, resourcesHandle); если (ресурс) { uint8_t* resourcesData = reinterpret_cast(LockResource(resource)); если (resourceData) { изображение = LoadImageFromMemory(resourceData, SizeofResource(NULL, resourcesHandle)); } } } вернуть изображение; } MainView::MainView() noException : CFormView(IDD_TRANSPARENTDIALOG_FORM) { m_backgroundImage = std::unique_ptr(LoadPngFromResources(IDB_PNG1)); } void MainView::DoDataExchange(CDataExchange* pDX) { CFormView::DoDataExchange(pDX); } BOOL MainView::PreCreateWindow(CREATESTRUCT& cs) { вернуть CFormView::PreCreateWindow(cs); } void MainView::OnInitialUpdate() { CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); фрагмент = новый фрагмент (это); фрагмент-> Создать (IDD_FRAGMENT1, это); фрагмент->ShowWindow(истина); } BOOL MainView::OnEraseBkgnd(CDC* dc) { Gdiplus::Графика графика(dc->m_hDC); графика.DrawImage( m_backgroundImage.get(), 0, 0, m_backgroundImage.get()->GetWidth(), m_backgroundImage.get()->GetHeight()); вернуть истину; } MainDoc* MainView::GetDocument() const { вернуть (MainDoc*)m_pDocument; } Примечание: обновление текста при нажатии кнопки 10 раз с перерывом в режиме ожидания предназначено только для целей тестирования. После удаления Sleep и настройки обновления текста только один раз при нажатии кнопки мерцание все равно сохранится.
Кроме того, я обнаружил, что обновление текста здесь не имеет значения: мерцание сохраняется даже при простом обновлении родительского окна с помощью следующего кода:
void Fragment::OnBnClickedButton1() { CRect прямой; m_label.GetWindowRect(&rect); GetParent()->ScreenToClient(&rect); GetParent()->InvalidateRect(&rect); GetParent()->UpdateWindow(); }
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение