Jak nakreslit semi transparentní čtverec? – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Jak nakreslit semi transparentní čtverec? – C / C++ – Fórum – Programujte.comJak nakreslit semi transparentní čtverec? – C / C++ – Fórum – Programujte.com

 

oxidián0
Grafoman
19. 9. 2015   #1
-
0
-

Co znamená toto:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms534453%28v=vs.85%29.aspx

"Graphics class:

Applies to: desktop apps only"

Co je to "desktop apps"?

A k čemu je header "objidl"? (zde https://msdn.microsoft.com/en-us/library/windows/desktop/ms533895%28v=vs.85%29.aspx)

K otázce, mám okno s mapou 256x256 px. A chci udělat výběr určité oblasti, tzn. zvýraznit vybranou část. Kdyby to bylo na webovou stránku, udělal bych to tak, že bych přes obrázek mapy dal png s alfa vrstvou. Čtverec bych nakreslil do normální vrstvy. Ale tady?

Našel jsem toto:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd183351%28v=vs.85%29.aspx

Ale to nevyhovuje, to je funkce, která jede jen na Windows Server a Windows XP professional (desktop apps only). A já chci aby můj projekt mohl kompilovat i člověk který má obyčejné XP Home. Takže jak to vyřešit?

Nějaký kod mám.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms534453%28v=vs.85%29.aspxHDC hDC;  
data.mapbmp = NULL;
hDC = GetWindowDC(window);
data.copydc = CreateCompatibleDC(hDC);
ReleaseDC(window, hDC);

// Function to create bitmap (map) with the terrain and units is called
// so data.mapbmp is a valid bitmap with image (256 colors)
// there are this functions:
// data.mapbmp = CreateCompatibleBitmap(dcdest, data.bmpsize, data.bmpsize);
// SelectObject(data.copydc, data.mapbmp);
// data.mapbmp = CreateCompatibleBitmap(dcdest, data.bmpsize, data.bmpsize);
// FillRect(data.copydc, &area, tBrushes[parse->cnst]);

// Draw the map
PAINTSTRUCT ps;
hDC = BeginPaint(window, &ps);
SelectObject(data.copydc, data.mapbmp);
BitBlt(hDC, data.offsetx, data.offsety, data.bmpsize, data.bmpsize,
	data.copydc, 0, 0, SRCCOPY);
Nahlásit jako SPAM
IP: 78.45.87.–
Radek Chalupa
~ Redaktor
+1
Super člen
20. 9. 2015   #2
-
0
-

#1 oxidián
Stačí použít GDI plus, je součástí všech verzí Windows od XP.

Přidáš header a lib:

#include <gdiplus.h>
#pragma comment (lib, "gdiplus.lib")

Na začátku programu potřeba inicializovat:

Gdiplus::GdiplusStartupInput gdiplus_startup_input;
ULONG_PTR gdiplus_token = 0;
Gdiplus::GdiplusStartup(&gdiplus_token, &gdiplus_startup_input, nullptr);

A jako ukázka obsluha WM_PAINT - vykreslí poloprůhledný žlutý obdélník přes obrázek, hodnota 120 je alfa kanál (v rozsahu 0-255)

PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rect;
GetClientRect(hWnd, &rect);
Gdiplus::SolidBrush b(Gdiplus::Color(120, 255, 255, 0));
Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(L"<cesta k souboru>");
Gdiplus::Graphics* g = new Gdiplus::Graphics(hdc);
g->DrawImage(bmp, 0, 0, rect.right, rect.bottom);
g->FillRectangle(&b, Gdiplus::Rect(100, 100, rect.right - 200, rect.bottom - 200));
delete bmp;
delete g;
EndPaint(hWnd, &ps);

PS: Samozřejmě v praxi není nejlepší při každém překreslení znova načítat tu bitmapu, ostatně asi ji máš nějak vytvořenou jinak než načtením souboru, A samozřejmě přidat testování návratových hodnot na chyby.

Radek Chalupa

- individuální konzultace, školení programování (C/C++, WinAPI, COM, ActiveX, ATL, C#, NET Framework, MFC)

- vývoj software na zakázku

http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
oxidián0
Grafoman
20. 9. 2015   #3
-
0
-

Díky za odpověď, ale nejede mi to GDI+. Chyby se objevují v souboru gdiplusimaging.h jako error C4430: missing type specifier; error C2440: 'initializing' : cannot convert etc. je toho spousta. Nejspíš je třeba ještě něco includovat. Můj soubor začíná takto:

#ifndef VIEW_MAPVIEW_H
#define VIEW_MAPVIEW_H

#define WIN32_LEAN_AND_MEAN
#define OEMRESOURCE	// OCR_NORMAL, this is needed by windows.h

#ifndef MOD_NOREPEAT 
  #define MOD_NOREPEAT 0x4000
#endif

#include "../model/wrapper_struct.h"
#include "../view/makewindows.h"
#include "../view/mapview.h"

makewindows.h includuje vše v souvislosti s okny.

Nahlásit jako SPAM
IP: 78.45.87.–
Radek Chalupa
~ Redaktor
+1
Super člen
20. 9. 2015   #4
-
0
-

#3 oxidián
Měl bys napsat jaké vývojové prostředí používáš a uvést alespoň ty řádky na kterých to vypisuje zmíněné chyby...

Jnak určitě bych vyhodil tu definici WIN32_LAEN_AND_MEAN - to mělo význam v době 486:-)

V GDI+ jsem bez problémů dělal už ve ve VIsual Studiu 2008. Do projektu vygenerovaném VS (typu Win32 windows aplikace) stačí přídat jiiž zmíněné:

#include <gdiplus.h>

#pragma comment (lib, "gdiplus.lib")

Radek Chalupa
- individuální konzultace, školení programování (C/C++, WinAPI, COM, ActiveX, ATL, C#, NET Framework, MFC)
- vývoj software na zakázku
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
oxidián0
Grafoman
20. 9. 2015   #5
-
0
-

VS 2010. Problém vyřešen, bylo to tím WIN32_LEAN_AND_MEAN.

Iniciaci jsem udělal takhle:

struct GDI_STRUCT
{
  Gdiplus::GdiplusStartupInput gdiplus_startup_input;
  ULONG_PTR gdiplus_token;  
};

struct MapViewData
{
    Scenario * scen;
    GDI_STRUCT gdi;
    HDC copydc;
    HBITMAP mapbmp;//bitmap storage for map

    ...

} data;

void OnWM_Create(HWND window, CREATESTRUCT * cs)
{
    HDC hDC;
    data.gdi.gdiplus_token = 0;
    Gdiplus::GdiplusStartup(&data.gdi.gdiplus_token, &data.gdi.gdiplus_startup_input, nullptr);  

}

Nahlásit jako SPAM
IP: 78.45.87.–
oxidián0
Grafoman
20. 9. 2015   #6
-
0
-

 Příkazem vytváříš bitmapu typu Gdiplus::Bitmap

Gdiplus::Bitmap* bmp = new Gdiplus::Bitmap(L"<cesta k souboru>");

jak bych to měl udělat když v programu už existuje bitmapa typu HBITMAP? Toto je kod ve kterém se vytváří:

data.mapbmp = CreateCompatibleBitmap(dcdest, data.bmpsize, data.bmpsize);
SelectObject(data.copydc, data.mapbmp);
for (x = 0; x < data.scen->map.x; x++)
	{
		parse = data.scen->map.terrain[x];
		for (y = 0; y < data.scen->map.y; y++, parse++)
		{
			if (setts.view.rotation_0)
				rotate(half, x, y, rx, ry);
			else
			if (setts.view.rotation_315)
			{
			unrotate(data.scen->map.x, x, y, urx, ury);
			rx = urx;
			ry = ury;
			}
			else
			if (setts.view.rotation_45)
			{ rx = x*2; ry = (data.scen->map.y-y)*2; }
       
			area.left = rx;
			area.right = rx + 2 * setts.zoom;
			area.top = ry;
			area.bottom = ry + 2 * setts.zoom;
			FillRect(data.copydc, &area, tBrushes[parse->cnst]);
		} // for 2
	} // for 1

Myslím že by to chtělo by to udělat kopii toho data.mapbmp ; kopie by se mohla jmenovat řekněme data.gdi.mapcopy; dále bych asi měl vytvořit novou bitmapu typu Gdiplus::Bitmap a do té bych kreslil "selection mask". Pak bych použil "selection mask" pro vytvoření blanding effektu přes ten obrázek mapy data.gdi.mapcopy a ten bych vykreslil.

Přesněji - není mi jasný jestli vykreslit data.mapbmp nebo data.gdi.mapcopy. data.mapbmp je vlastně vytvořený z okna z hDC = GetDC(window); tak bych asi měl vykreslit mapbmp. Mám tedy potom zkopírovat tu mapu nakreslenou pomocí GDI+ do mapbmp? Tzn. při každém novém výběru mapy bych překopíroval data z Gdiplus::Bitmap do HBITMAP a to se potom automaticky překreslí.

Takže teď je otázka jak zkopírovat obrázek typu HBITMAP do obrázku typu Gdiplus::Bitmap a jak vytvořit novou čistou bitmapu typu Gdiplus::Bitmap o velikosti data.scen->map.x x data.scen->map.x

Edit:

Tu kopii spíš potřebuju kvůli tomu, abych mohl provést deselekt posledního výběru. Jako když vezmeš že selekci budu provádět pomocí ctrl+lmouse + drag a nebo pomocí ctrl+shift+lmouse + drag tak když budu chtít vrátit poslední čtverec zpět, tak proto potřebuju mít někde uložený originál té mapy, tj kopii.

Nahlásit jako SPAM
IP: 78.45.87.–
Radek Chalupa
~ Redaktor
+1
Super člen
20. 9. 2015   #7
-
0
-

#6 oxidián
Stačí se podívat do dokumentace. Třída Bitmap má statickou metodu FromHBITMAP, která vytvoří objekt na základě HBITMAP a vrátí pointr na objekt Bitmap.

A vytvoření "čisté" bitmapy, opět dle dokumentace jedním z konstruktorů:

new Bitmap(sirka, vyska, PixelFormat32bppARGB); // nebo jiný žádaný formát

Radek Chalupa
- individuální konzultace, školení programování (C/C++, WinAPI, COM, ActiveX, ATL, C#, NET Framework, MFC)
- vývoj software na zakázku
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
oxidián0
Grafoman
21. 9. 2015   #8
-
0
-

Chci se tě zeptat jestli rozumíš této funkci, nechápu totiž proč tam je tento příkaz:

SelectObject(data.copydc, data.mapbmp);

Chápu, že bitmapa je vybrána to kontextu zařízení data.copydc, ale nechápu proč. Nikde v tom kódu totiž nevidím, že by ta bitmapa byla použita nebo se s ní jakkoliv pracovalo. Znamená to, že když vyberu bitmapu do kontextu zařízení, že se s ní pracuje, ale nepřímo, tj. pracuje se s ní přes ten kontext zařízení data.copydc?

void PaintMap(HDC dcdest)
{
	int half;
	unsigned int y, x; // unsigned
	unsigned int urx, ury; // (unsigned)

	int rx, ry;	//rotated
	Map::Terrain *parse;
	RECT area;

	// Create a bitmap
	data.bmpsize = 2 * data.scen->map.x * setts.zoom + 1;
	// (HBITMAP) mapbmp
  data.mapbmp = CreateCompatibleBitmap(dcdest, data.bmpsize, data.bmpsize);
	half = data.scen->map.x / 2;

	// DO THE PAINTING
  // Select object (HBITMAP) data.mapbmp 
  // into device context (HDC) data.copydc
	SelectObject(data.copydc, data.mapbmp);
	for (x = 0; x < data.scen->map.x; x++)
	{
		parse = data.scen->map.terrain[x];
		for (y = 0; y < data.scen->map.y; y++, parse++)
		{
			if (setts.view.rotation_0)
				rotate(half, x, y, rx, ry);
			else
			if (setts.view.rotation_315)
			{
			unrotate(data.scen->map.x, x, y, urx, ury);
			rx = urx;
			ry = ury;
			}
			else
			if (setts.view.rotation_45)
			{ rx = x*2; ry = (data.scen->map.y-y)*2; }
       
			area.left = rx;
			area.right = rx + 2 * setts.zoom;
			area.top = ry;
			area.bottom = ry + 2 * setts.zoom;
			FillRect(data.copydc, &area, tBrushes[parse->cnst]);
		} // for 2
	} // for 1

	PaintUnits(data.copydc);
}

Probíhá tedy kreslení do bitmapy nebo do okna?

Pozn. PaintUnits dělá to samé, akorát že vykresluje objekty ve smyslu FillRect(
data.copydc, &area, pBrushes[p.color]);

A u deklarace je tam napsané toto:

HDC copydc;    //DC used for saving what's under a highlight, etc.
 HBITMAP mapbmp;//bitmap storage for map

Edit:

Už to asi začínám chápat, tam už jedna kopie bitmapy je, čili to data.copydc ... Je to protože, když uživatel vybere objetk, který se zvýrazní na mapě, tak pak když to je třeba uvést zpět jak to bylo, tak se to načte z data.copydc. Takže toto mohu použít taky jako originál a kreslit ty poloprůhledné čtverce mohu asi přímo na obrazovku? Ale jak? Co musím vybrat za zařízení aby se to nakreslilo přímo do okna?

Edit2:

Kreslící funkce začíná takto (komentáře jsem tam přidal já):

  // hDC se používá na kreslení přímo do okna
  // tj. zvýraznění vybraného objektu
  // sem tedy mohu vykreslit poloprůhledné čtverce
  hDC = GetWindowDC(window);

  // CHÁPU TO SPRÁVNĚ?
  // data.copydc je jakkdyby kopie okna,
  // v tom smyslu, že to obsahuje bitmapu
  // do které mohu kreslit, tzn.
  // sem se kreslí originál mapy
  data.copydc = CreateCompatibleDC(hDC);
  ReleaseDC(window, hDC);
  // Proč je tu ReleaseDC?
Nahlásit jako SPAM
IP: 78.45.87.–
Radek Chalupa
~ Redaktor
+1
Super člen
22. 9. 2015   #9
-
0
-

Kreslení probíhá do kontextu zařízení (HDC). Tím že do něj vybereš bitmapu (fce SelectObject) můžeš pak provádět bitové operace s daty bitmapy. Ten kontext může být buď paměťový nebo vázaný na okno (funkcí BeginPaint nebo GetDC popř. GetWindowDC.

Pro eliminaci problikávání při více kreslících operacích do jednoho HDC se používá tzv. buffering, tj vše se nakreslí do paměťového HDC a ten se pak překopíruje (BitBlt) do konextu okna. Viz. např.zde:

http://www.radekchalupa.cz/clanek/gdi-buffering

Radek Chalupa
- individuální konzultace, školení programování (C/C++, WinAPI, COM, ActiveX, ATL, C#, NET Framework, MFC)
- vývoj software na zakázku
http://www.radekchalupa.cz

Nahlásit jako SPAM
IP: 89.177.51.–
oxidián0
Grafoman
22. 9. 2015   #10
-
0
-

Díky moc,hlavně za ten článek

Nahlásit jako SPAM
IP: 78.45.87.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 33 hostů

Podobná vlákna

Jak nakreslit tečky? — založil oxidián

Vytiskni čtverec * — založil klara

Čtverec podle čísla — založil LeArnie

Java shape čtverec — založil Honza

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý