Форум: Форум C++Разное
Новые темы: 00
PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум C++

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Вывод Bitmap на экран. Windows API.
 
 автор: EvgenLog   (24.01.2007 в 00:47)   письмо автору
2.3 Кб
 
 

Ну ни как у меня не получается это сделать! А это, на сколько я понимаю, то самое, чем пользуются, при отрисовке дизайна Windows-приложений.

Я уже не знаю что ещё сделать. Вот, прикрепляю файл с кодом. Программа компилируется и запускается, но ничего на экран не выводится.

  Ответить  
 
 автор: cheops   (24.01.2007 в 02:13)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 00:47)
 

Так не пойдёт - вы должны явно указать в функции LoadBitmap() откуда вы загружаете изображение... Просто NULL указать не получится, придётся передавать дескриптор приложения hInstance, иначе функция не будет знать где брать изображение... Вынесете определение объекта
 WNDCLASSEX wc;

за пределы функции WinMain(), чтобы объект wc стал глобальным и передавайте в качестве первого параметра функции LoadBitmap() - wc.hInstance

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 11:11)   письмо автору
 
   для: cheops   (24.01.2007 в 02:13)
 

Спасбо, действительно всё заработало. Значит дизайн теперь так строить? Выводить битмапы? С сответствующими координатами....

Вот ещё вопрос. Я правильно понимаю принцип действия?

Вот например мне нужно создать свою кнопку, своей формы и т.д. Для этого мне нужно вывести картинку кнопки в "отжатом" состоянии, а при нажатии на неё обработать сообщение которое сообщает о нажатии левой кнопки мыши?

  Ответить  
 
 автор: cheops   (24.01.2007 в 13:37)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 11:11)
 

>С сответствующими координатами....
Не только координатами, если вы пользуетесь готовыми элементами управления, меню, кнопками, то вам нужно будет выводить изображеня на них, т.е. привязываться к контексту... каждый элемент управления представляет собой своебразное мини-окно и координаты у них должны быть свои. Т.е. если захотите меню разукрасить (10 глава Петцольда), то необходимо будет привязываться к меню, а не к основному окну.

>Для этого мне нужно вывести картинку кнопки в "отжатом" состоянии, а при нажатии на неё
>обработать сообщение которое сообщает о нажатии левой кнопки мыши?
Если вы полностью отрисовываете свою собственную кнопку, да именно так. Как правило подготавливают два изображения - в нажатом и отжатом состоянии (иногда, ещё вид кнопки при наведённой на неё мыши).

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 13:58)   письмо автору
 
   для: cheops   (24.01.2007 в 13:37)
 

Т.е. чтобы рисовать на заголовке окна (менять, собственно внешний вид окна в целом) и рамках, нужно делать привязку к контексту окна. В таком случае можно будет удалить с заголовка все стандартные элементы и разместить свои? Но, если создавать свою кнопку, то как опредилить, что пользователь кликнул именно на ДАННОМ обьекте? Ведь сообщение о нажатии мыши отправляется при клике в любом месте.

И ещё, можно-ли кроме Bitmap вывести ещё что-нибудь, содержащее большее количество цветов? Например JPG? Я знаю, что можно добавить в ресурсы, что угодно, но вот какими средствами вывести, не нашёл. Знаю, что существует формат битового изображения 24-bit, но он слишком много весит.

  Ответить  
 
 автор: cheops   (24.01.2007 в 14:47)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 13:58)
 

Чтобы рисовать в заголовке - вам нужно открыть окно в режиме, котором вообще ничего нет кроме области окна (как игрушки делают) - и отрисовывать заголовок окна, кнопки свернуть, выключить, на полный экран (если они вообще нужны) самостоятельно... Правда, режим не помню - нужно в справочнике рыться.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 15:02)   письмо автору
 
   для: cheops   (24.01.2007 в 14:47)
 

Ясно. Спасибо.
А на вопрос про создание своего объкта ответа так и нет. Создать новую тему? С таким вопросом. По сути он к выводу битмапов никак не относится.

  Ответить  
 
 автор: cheops   (24.01.2007 в 15:13)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 15:02)
 

Хм... а что-то не вижу... Под новые вопросы лучше всегда заводить новые темы - тогда их сложнее не заметить :)))

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 19:43)   письмо автору
 
   для: cheops   (24.01.2007 в 15:13)
 

Хм... Вот интересно, а почему изображение исчезает с экрана? Просто исчезает. Это происходит, если непрерывно менять размеры окна или таскать по нему что-нибудь, например другое перекрывающее окно. Через несколько секун таких пыток изображение исчезает. И ещё, очень раздражительно мигает картинка, при совершении подобных операций. В чём дело и как от всего этого избавиться?

  Ответить  
 
 автор: cheops   (24.01.2007 в 19:49)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 19:43)
 

У вас, я там видел, конекст не закрывается, т.е. свойство WM_PAINT выглядит так
case WM_PAINT :
  hDc = BeginPaint(hWnd, &ps);

  bmPicture = LoadBitmap(NULL, MAKEINTRESOURCE(IDB_BITMAP2));
  DrawBitmap(hDc, bmPicture, 100, 100);

  return(0);

Я когда разбирался с вашим примером, контекст закрывал
  case WM_PAINT :
  hDc = BeginPaint(hWnd, &ps);

  bmPicture = LoadBitmap(wc.hInstance, MAKEINTRESOURCE(IDB_BITMAP2));
  DrawBitmap(hDc, bmPicture, 100, 100);

  EndPaint(hWnd, &ps);

  return 0;

Сейчас таскаю - у меня ничего не пропадает - попробуйте - наверняка дело в этом.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 20:12)   письмо автору
 
   для: cheops   (24.01.2007 в 19:49)
 

Я это уже давно и исправил. У меня тоже контекст закрывается.

Вот что я заметил. Если отображать маленьку картинку (размер не более 2 кб), то всё нормально, не удаляется, хотя мигание всё равно присутсвует. Если же отображать картинку потяжелее (примерно 380 кб), то она после издевательств над окном исчезает. Я в виду своей недостаточной образованности в этой области, ничего конкретного сказать не могу, но думай, что нужен буфер.

  Ответить  
 
 автор: cheops   (24.01.2007 в 20:50)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 20:12)
 

Мне ещё не нравится, что вы выполняете функцию LoadBitmap() при каждом чихе программы - дело в том, что работая с окном - вы вызываете эту функцию десятки раз за секунду... лучше загрузить LoadBitmap() один раз в WinMain(), а затем использовать в событии WM_PAINT. Однако и это тоже может не помочь, так как Windows API вообще говоря не силён в графике - максимум, что можно сделать, это что-то вроде сапёра или косынки. Для серьёзных графических проектов используют либо OpenGL, либо DirectX. При 380 Кб от мерцания будет очень сложно избавиться.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 20:57)   письмо автору
 
   для: cheops   (24.01.2007 в 20:50)
 

Хорошо, а каким тогда образом отображаются иконки допустим в обычном окне Windows? Они ведь не мерцают при изменение размеров окна.

  Ответить  
 
 автор: cheops   (24.01.2007 в 21:07)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 20:57)
 

Они и 380 Кб не занимают :)

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 21:17)   письмо автору
 
   для: cheops   (24.01.2007 в 21:07)
 

Но они там хотябы не мерцают! :)

  Ответить  
 
 автор: cheops   (24.01.2007 в 22:19)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 21:17)
 

Понимаете там... картинка рисуется один раз, после этого, при срабатывании события WM_PAINT, перерисовываются только те участки которые изменились... Грубо говоря тащите вы окно и видите, что наложения других окон нет, размер не изменяется... в этом случае вы ничего не перерисовываете, а если требуется перерисовать - перерисовывайте. WM_PAINT может сотню раз сработать пока окно тащите... попробуйте переместить код отрисовки в события отображения окна WM_SHOWWINDOW и событие изменения его размера WM_SIZE (я тут вызов LoadBitmap() в WinMian() вынес)
switch(iMsg)
{
    case WM_SHOWWINDOW:
    case WM_SIZE:
            hDc = BeginPaint(hWnd, &ps);

DrawBitmap(hDc, bmPicture, 100, 100);
EndPaint(hWnd, &ps);
            return 0;
        case WM_PAINT :
            return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}

В этом случае изображение будет отрисовываться только при отображении окна и при изменени его размера... правда ещё потерю фокуса нужно обработать - иначе перекрытие другими окнами будет затирать окно.

  Ответить  
 
 автор: cheops   (24.01.2007 в 22:23)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 21:17)
 

Причём зачастую отрисуют окно и запоминают как оно выглядело, потом подгружают сохранённый образ и редактируют на нём только то, что подверглось изменению, не перерисовывая каждую деталь... Библиотеки MFC и VCL не зря свой хлеб едят, они действительно выполняют множество рутинной работы.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 22:32)   письмо автору
 
   для: cheops   (24.01.2007 в 22:23)
 

Ясно. Попробую, но мне кажется что не в этом проблема. Когда я окно претаскиваю, то оно не мигает и ничего не исчезает. Глюки как раз таки только при изменение размеров. Ну сейчас попробую.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 22:37)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 22:32)
 

Странно. Я переместил функцию загрузки изображения в WinMain() и теперь у меня вообще ничего не выводися на экран.

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "Paint On Window";
HBITMAP bmPicture;
HBRUSH hBrush;
HWND hwnd;
MSG msg;

bmPicture = LoadBitmap(wndclass.hInstance, MAKEINTRESOURCE(IDB_BITMAP1));

wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wndclass.lpszClassName = szAppName;
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

RegisterClassEx(&wndclass);
                                    .
                                    .
                                    .

  Ответить  
 
 автор: cheops   (24.01.2007 в 22:44)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 22:37)
 

bmPicture глобальным сделали?

  Ответить  
 
 автор: cheops   (24.01.2007 в 22:39)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 22:32)
 

При изменении размеров вообще говоря тоже нужно отслеживать, пересекает область окна изобаржение или нет - если не пересекает, то и перерисовывать его не требуется.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 22:49)   письмо автору
 
   для: cheops   (24.01.2007 в 22:39)
 

Сделал глобальной (вынес на самый верх), безрезультатно. Отслеживать пересекает или нет... Т.е. нужно использовать область отсечения или InvalidateRect?

  Ответить  
 
 автор: cheops   (24.01.2007 в 23:00)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 22:49)
 

Странно - у меня работает - прикрепите файл, в том виде, котором он у вас сейчас.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 23:03)   письмо автору
1.4 Кб
 
   для: cheops   (24.01.2007 в 23:00)
 

Вот как выглядит файл main.cpp. В архив не включены ресурсы.

  Ответить  
 
 автор: cheops   (24.01.2007 в 23:06)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 23:03)
 

Только сейчас заметил - вы используете wndclass.hInstance в LoadBitmap() до того, как он определён парой строчек ниже... поэтому в качестве первого параметра опять передаётся NULL. Поместите LoadBitmap() ниже в WinMain().

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 23:10)   письмо автору
 
   для: cheops   (24.01.2007 в 23:06)
 

Ха! Да что ты будешь делать!
Переместил

bmPicture = LoadBitmap(wndclass.hInstance, MAKEINTRESOURCE(IDB_BITMAP2));

В самый низ WinMain(), опять без результата! Может вы мне вышлите код в таком виде, в котором он у вас работает?

  Ответить  
 
 автор: cheops   (24.01.2007 в 23:16)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 23:10)
 

В самый низ нельзя :), так как программа по сути выполняется в цикле
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

Вот так напишите
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
wndclass.lpszClassName = szAppName;
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

bmPicture = LoadBitmap(wndclass.hInstance, MAKEINTRESOURCE(IDB_BITMAP1));

или просто оставьте в начале, но засобачьте вместо wndclass.hInstance - hInstance, вы же в WinMain() находитесь можете использовать оригинальный дескриптор.

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 23:20)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 23:10)
 

Опять нет результата. Я вот подумал правилен-ли вот этот код?

switch(iMsg)
{
    case WM_SHOWWINDOW:
    case WM_SIZE:
            hDc = BeginPaint(hWnd, &ps);

DrawBitmap(hDc, bmPicture, 100, 100);
EndPaint(hWnd, &ps);
            return 0;
        case WM_PAINT :
            return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}


Петзольд пишет, что нельзя вот так делать:

case WM_PAINT :
            return 0;

  Ответить  
 
 автор: cheops   (24.01.2007 в 23:25)   письмо автору
14.9 Кб
 
   для: EvgenLog   (24.01.2007 в 23:20)
 

Держите мой проект...

PS Тема уже достаточно большая наверное нужно бы новую завести для продолжения...

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 23:31)   письмо автору
 
   для: cheops   (24.01.2007 в 23:25)
 

Хм... Работает... Построчно придётся сравнивать, чтобы докапаться до ошибки. Ну да ладно, этим потом займусь, всё равно для разработки справвочника буду пользоваться графическим интерфейсом. Спасбо за помощь!

  Ответить  
 
 автор: EvgenLog   (24.01.2007 в 23:01)   письмо автору
 
   для: cheops   (24.01.2007 в 22:39)
 

Вобщем нужно помечать перекрываемую область как недействительную и перерисовывать только её?

  Ответить  
 
 автор: cheops   (24.01.2007 в 22:58)   письмо автору
 
   для: EvgenLog   (24.01.2007 в 22:32)
 

В том и дело, что WM_SIZE тоже очень много возникает - нужно перерисовывать только тогда, когда задевается рисунок, причём, если окно только расширяется и задевает изображение.

  Ответить  
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования