Растровое изображение на кнопке с использованием диалогового приложения MFC 2.5

Я видел другие темы по этой теме, но ни одна из них не работает с MFC 2.5 с тех пор. CButton::ModifyStyle() и CButton::SetBitmap() не существуют в MFC 2.5.

Я создаю диалоговое приложение, используя редактор ресурсов, чтобы создать диалоговое окно с несколькими кнопками. В редакторе для кнопок установлено значение «Рисование владельцем». Я использую следующий код:

void CMainDialog::OnInitDialog()
{
  // to do:  initialization
  CBitmapButton m_Processor;
  m_Processor.AutoLoad( IDC_CPU, this );

  return TRUE;
}

Приведенный выше код должен был автоматически загрузить ресурс растрового изображения, который я создал как IDB_CPU. Однако при компиляции расположение кнопки просто показывает пустое пространство, а не загружает растровое изображение.

Я также попробовал этот код:

void CMainDialog::OnInitDialog()
{
  // to do:  initialization
  CBitmapButton m_Processor;
  m_Processor.LoadBitmaps( IDB_CPU, NULL, NULL, NULL );

  return TRUE;
}

Но он дает тот же результат, только с пустым пространством. Я знаю, что изображение существует в растровом формате (например, я могу открыть его с помощью Paint), и я проверил, что идентификатор ресурса для IDB_CPU правильно установлен в файле resources.h.

Любая помощь приветствуется!

Автозагрузка пытается загрузить растровые изображения по имени (а не по идентификатору). Имена ресурсов получаются из текста кнопки (например, "OK") плюс буквальный суффикс "U", "D", "F" и "X" для состояний вверх/вниз/фокус/отключено. Чтобы это работало, ваш сценарий ресурсов должен определить эти растровые изображения с именем. В любом случае, если ваши кнопки отображаются пустыми, проблема, скорее всего, связана с вашим кодом отрисовки владельца (который мы не видим). Требуется минимально воспроизводимый пример.
IInspectable 27.06.2024 09:09

Вы можете вызвать LoadBitmap() хотя бы с первым набором аргументов. И в этом случае имена ресурсов не обязательно должны соответствовать вышеупомянутой спецификации. Возможно, вам придется использовать MAKEINTRESOURCE() для использования идентификатора ресурса. Экземпляр класса CBitmapButton нельзя удалять (поэтому его также не следует определять в функции), он должен существовать на протяжении всего срока службы диалога. Таким образом, он должен быть определен в классе, связанном с идентификатором ресурса с DDX_Control() в DoDataExchange(), и вы должны вызвать LoadBitmaps() в OnInitDialog() (после вызова OnInitDialog() базового класса).

Constantine Georgiou 28.06.2024 11:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
105
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Похоже, m_Processor является (или, по крайней мере, должен быть) членом класса CMainDialog.
Префикс m_ намекает, что такой участник у вас действительно есть, а если нет, то его следует добавить.

Однако эта строка внутри CMainDialog::OnInitDialog():

CBitmapButton m_Processor;

Объявляет локальную переменную. Он затеняет участника с таким же именем (если существует).
Растровое изображение загружается в эту локальную переменную и отбрасывается, когда оно выходит за пределы области действия при возврате метода, а не в элемент диалога, который отображается в графическом интерфейсе (при условии, что такой элемент существует).

Поэтому вам следует удалить эту строку.

Это дало мне намек на то, что я делаю это неправильно, будучи n00b и все такое. Мне удалось выяснить, как сделать m_Processor членом класса CMainDialog, но мастер Class Express позволял мне создавать только тип CButton, а не CBitmapButton. Для меня довольно странно, если компилятор поддерживает типы CBitmapButton. Мне придется поискать в Google и посмотреть, смогу ли я выяснить, как изменить тип.

Charlie Dobson 28.06.2024 00:23

@CharlieDobson Я не уверен, как это сделать, надеюсь, вы найдете это с помощью Google. Вы можете опубликовать новый вопрос по этой проблеме. Но я совершенно уверен, что то, что я написал, является ответом на ваш текущий вопрос в том виде, в котором он опубликован.

wohlstad 28.06.2024 06:05

Попробуйте просто изменить тип переменной с CButton на CBitmapButton в определении класса.

Constantine Georgiou 28.06.2024 11:48

Мне пришлось объединить оба ваших предложения, чтобы заставить его работать. Мне нужно было удалить локальную переменную в CMainDialog::OnInitDialog(), а также вручную изменить тип класса с CButton на CBitmapButton. Мне также пришлось не использовать мастер для добавления переменной-члена, а добавить ее под спецификатором protected: в классе диалога.

Charlie Dobson 30.06.2024 03:48

Это не самый распространенный способ связать элементы управления Win32 с переменными класса MFC. Вместо этого вы можете использовать мастер классов, чтобы добавить переменные-члены в класс диалога.

Что касается вашей проблемы (использование старой версии MFC без метода CButton::SetBitmap()), можно было бы сказать, используйте последнюю версию VS/MFC, но это не всегда легко. Обходной путь — вместо этого использовать сообщение Win32 BM_SETIMAGE. MFC по большей части представляет собой оболочку MFC (и довольно «тонкую», я бы сказал). И это именно то, что на самом деле делает MFC. Ниже приведена реализация CButton::SetBitmap() в файле afxwin2.inl, строка 640:

_AFXWIN_INLINE HBITMAP CButton::SetBitmap(HBITMAP hBitmap)
    { ASSERT(::IsWindow(m_hWnd)); return (HBITMAP)::SendMessage(m_hWnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap); }

То есть он просто отправляет BM_SETIMAGE элементу управления. Вы можете сделать то же самое в своем приложении:

SendDlgItemMessage(IDC_MYBUTTON, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hBitmap);

ИЛИ

SendDlgItemMessage(IDC_MYBUTTON, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)(HBITMAP)m_Bitmap);

В классе CBitmap есть оператор HBITMAP, поэтому вы можете передать переменную экземпляра CBitmap там, где ожидается HBITMAP; однако SendMessage()/SendDlgItemMessage() принимает LPARAM в качестве последнего аргумента, поэтому здесь необходимо дополнительное приведение (HBITMAP).

Сообщения BM_SETIMAGE и IMAGE_BITMAP, похоже, не поддерживаются Win16 API. Я попробовал следующий код, но мой компилятор сказал, что оба неопознаны: BOOL CMainDialog::OnInitDialog() { CDialog::OnInitDialog() // to do: initialization CBitmap h_bitmap; h_bitmap.LoadBitmap( IDB_CPU ); ::SendDlgItemMessage( IDC_PROCESSR, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)(HBITMAP)h_bitmap ); h_bitmap.DeleteObject(); return TRUE; }

Charlie Dobson 28.06.2024 00:53

Извините за плохое форматирование выше. У меня закончилось время редактирования, прежде чем я смог это исправить.

Charlie Dobson 28.06.2024 01:12

Если единственная проблема в том, что эти символы не определены, это легко: BM_SETIMAGE — это 0x00F7, а IMAGE_BITMAP — 0. Вопрос в том, поддерживаются ли они библиотекой управления ОС. Попробуйте это с вышеуказанными константами. Из заголовочных файлов видно, что они поддерживаются начиная с Win NT 4.0, но попробовать можно. Я бы не стал удалять растровое изображение (лучше создать экземпляр объекта CBitmap в своем классе, а не в OnInitDialog(), поскольку он выделен в стеке, и деструктор все равно его удалит), по крайней мере, пока я не удостоверюсь, что он больше не нужен (после звоню BM_SETIMAGE).

Constantine Georgiou 28.06.2024 10:51

Забыл упомянуть, чтобы кнопка работала, она не должна быть нарисована владельцем.

Constantine Georgiou 28.06.2024 11:49

Другие вопросы по теме