|
HarveySaayman wrote: What is up with that?
"The Load event occurs after the control is created, but before the control becomes visible for the first time."
Drawing on an invisible control will be, well, invisible
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
haha, now i get it!
Harvey Saayman - South Africa
Junior Developer
.Net, C#, SQL
think BIG and kick ASS
you.suck = (you.passion != Programming)
|
|
|
|
|
Hi,
here are my guidelines for painting in general:
there are several steps to draw something so it becomes visible on the screen:
1.
decide upon what object you want to draw; it normally is a Control (e.g. a Panel) or a
Form itself. I prefer to add a Panel to a Form, then draw on the Panel.
2.
create some variables (Rectangle, struct, class, whatever) that hold the parameters of
your drawing. For a rectangle that could be top and left coordinate, and width+height,
or just a Rectangle. etc.
3.
create a Paint handler for that Panel, and do all your drawing in there, using the
Graphics class and your variables.
4.
when you want to change things, modify the variables and call Panel.Invalidate() or
one of its overloads (for selective invalidation).
5.
If you want to animate things, perform the move (step 4) inside the Tick handler
of a Windows.Forms.Timer
BTW: if you need to create some objects (Fonts, Pens, Brushes, ...) either keep them
alive in class members (hence create them only once); or create them inside the Paint
handler and don't forget to call Dispose() on them.
Remark: you very rarely need CreateGraphics; OnPaint offers a Graphics object for free.
Luc Pattyn [Forum Guidelines] [My Articles]
This month's tips:
- before you ask a question here, search CodeProject, then Google;
- the quality and detail of your question reflects on the effectiveness of the help you are likely to get;
- use PRE tags to preserve formatting when showing multi-line code snippets.
|
|
|
|
|
Hey there,
thanx allot!
this will defiantly help me with the drawing of things,
im gona try drawing my time line on a panel now...
thanx again
Harvey Saayman - South Africa
Junior Developer
.Net, C#, SQL
think BIG and kick ASS
you.suck = (you.passion != Programming)
|
|
|
|
|
HarveySaayman wrote: Graphics graphics = this.CreateGraphics();
I don't understand why so many people use this method. It is *wrong*. What led you to use it ? Is there an MS sample out there that uses it ?
As you've discovered, handling hte paint event is the right way to draw your form. CreateGraphics is good to draw something temporary, like a rubberband. What you draw is lost on the first paint event.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
Christian Graus wrote: What led you to use it
exploration, im new to drawing so im "playing" around with what im able to do and getting suggestions from you guys, so that i can use these newly discovered "puzzle pieces" in a real world application.
the idea is to explore the drawing class and better understand how it works so that i can write a better control for my application.
im not using Graphics graphics = this.CreateGraphics(); anymore, ive seen the errors in my way
thanx
Harvey Saayman - South Africa
Junior Developer
.Net, C#, SQL
think BIG and kick ASS
you.suck = (you.passion != Programming)
|
|
|
|
|
That's cool - I'm not having a shot at you, just generally curious why so many people seem to 'discover' this way of drawing, if there's some book or sample at the bottom of it.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
its cool,
i know ur not having a shot at me, but its not always clear to others that theres actually method to my madness i do things like this on purpose so that i can learn from it and what others have done in the past
Harvey Saayman - South Africa
Junior Developer
.Net, C#, SQL
think BIG and kick ASS
you.suck = (you.passion != Programming)
|
|
|
|
|
Hai,
I am about to design an Source filter. May i know how to create a source filter which should be able to distinguish whether my transport stream is from an live source(ie from an ASI port) or is from the local disk. Please help me.
Thanks and Regards
Angeline
|
|
|
|
|
A DirectShow source filter? What transport stream?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Following is the piece of code i am using to render grayscale video onto screen. The pixel values are stored as 'int' in the variable disp_frame whose declaration is given below. 50 pixel buffers of size 176 X 144 is used.
I thought of creating bitmap out of these pixels and then use BitBlt to render it to the screen. But the CreateDIBSection is creating an exception when running in Debug code. It should be some syntax error. Could anyone debug it out.
int p=0,i=0,j=0,q=0;
extern int disp_frame[50][144][176];
///////////////////////
BITMAPINFOHEADER bmi;
BITMAPINFO bm;
RGBQUAD rgbarray[256];
bmi.biSize = sizeof(BITMAPINFOHEADER);
bmi.biWidth = 176;
bmi.biHeight = 144;
bmi.biPlanes = 1;
bmi.biBitCount = 8;
bmi.biCompression = BI_RGB;
bmi.biSizeImage = 0;
bmi.biXPelsPerMeter = 0;
bmi.biYPelsPerMeter = 0;
bmi.biClrUsed = 0;
bmi.biClrImportant = 0;
bm.bmiHeader = bmi;
for (int color_index = 0; color_index < 256; color_index++)
{
rgbarray[color_index].rgbBlue = i;
rgbarray[color_index].rgbGreen = i;
rgbarray[color_index].rgbRed = i;
rgbarray[color_index].rgbReserved = 0;
}
bm.bmiColors[1] = rgbarray[0];
/////////////////////
CRect rcClient;
GetClientRect(rcClient); // See Note 1
rcClient.right=176;
rcClient.bottom=144;
/*****************Doubtful routine starts here*******
HDC hDC;
hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
HDC memDC = CreateCompatibleDC(hDC);
CreateDIBSection(hDC,bitmap,DIB_PAL_COLORS,ppbits,NULL,0);
HBITMAP memBM = CreateCompatibleBitmap(hDC,176,144);
SelectObject(memDC,memBM);
BitBlt(memDC,150,100,176,144,hDC,0,0,SRCCOPY);
|
|
|
|
|
jossion wrote: CreateDIBSection(hDC,bitmap,DIB_PAL_COLORS,ppbits,NULL,0);
What is "bitmap"?
A BITMAPINFO has a BITMAPINFOHADER in it. It also has 1 of the 256 RGBQUAD
structs you need already in it. You need to allocate this all in one contiguous section
of memory.
The initialization of the color table is wrong, unless you want all black.
This line is all wrong and useless - "bm.bmiColors[1] = rgbarray[0];"
You are rendering in the wrong direction, unless you're trying to copy pixels from that DISPLAY dc to a memory dc.
That "DISPLAY" DC ... why not just use the DC for the client area of a window?
You should use DIB_RGB_COLORS when creating the dibsection so the call doesn't overwrite your grayscale color table.
You never use the dibsection you create.
Something like this should help you create the DIBsection....I don't know what you're trying to render so I
can't provide an example for that until you clear that up ...
BITMAPINFO *bm = (BITMAPINFO *)new BYTE[sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD)];
bm->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bm->bmiHeader.biWidth = 176;
bm->bmiHeader.biHeight = 144;
bm->bmiHeader.biPlanes = 1;
bm->bmiHeader.biBitCount = 8;
bm->bmiHeader.biCompression = BI_RGB;
bm->bmiHeader.biSizeImage = 0;
bm->bmiHeader.biXPelsPerMeter = 0;
bm->bmiHeader.biYPelsPerMeter = 0;
bm->bmiHeader.biClrUsed = 0;
bm->bmiHeader.biClrImportant = 0;
for (int color_index = 0; color_index < 256; color_index++)
{
bm->bmiColors[color_index].rgbBlue = color_index; <font color="Green">
bm->bmiColors[color_index].rgbGreen = color_index; <font color="Green">
bm->bmiColors[color_index].rgbRed = color_index; <font color="Green">
</font> bm->bmiColors[color_index].rgbReserved = 0;
}
BYTE *pBitmapBits;
HBITMAP hBitmap = ::CreateDIBSection(NULL, bm, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0);
if (hBitmap)
{
<font color="Green">
::DeleteObject(hBitmap);
}
delete[] (BYTE *)bm;
Tell me what you want to do rendering-wise and I'll try to fill in the sample code.
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I have pixel values of successive frames of video stored in int disp_frame[50][144[176], 50 buffers of size 176X144. Under a timer of 40ms I was doing all the stuff which i posted. Previously I was using setpixel to draw the video. Now for better speed I thought of doing BitBlt. So there came a ncessity to convert the raw pixel values to bitmap. That is what should happen in the rendering section. Creating DC,then Creating DIB then copying to memory DC, then using BitBlt or optional zooming with StretchBlt. I know that there are still excellent ways of doing it. But I thought of learning all techniques by coding it and seeing the performance. So I would like you to fill the rendering area with BitBlt(including routines for DC creation) for displaying pixels in disp_frame.As I have read the pixel values should be copied to (void**)&pBitmapBits. Basically I am not a person with programming background. that's why my code might have irritated you a bit. Anyhow a small apology for my mistakes.
bitmap is of type BITMAPINFO *bitmap.
|
|
|
|
|
First, your code didn't irritate me. You stated "Could anyone debug it out." and
I tried to do that.
Here's a breakdown of the rendering problem...
SetPixel is a really bad choice for rendering video, so moving to a bit-block-transfer
implementation is the right direction.
To use BitBlt()/StretchBlt(), you need a source DC with a bitmap containing the pixels
you want to render selected into it.
Since your pixel data comes in raw int format, you need a HBITMAP bitmap that allows you direct access
to its pixel data - thats what a DIBSection is for.
Once you have all that, there's more that can be optimized - You don't have to recreate the DIB section
every time you render a frame. It can be created once, before you start rendering frames.
Same applies to the memory DC - it only needs to be created once and have the DIBSection selected into it.
That means every 40ms, you only need to copy the pixel bits to the DIBSection, get a destination DC
for where you're going to draw, and blt.
Here's an expanded example...
<span style="color: Green;">
extern int disp_frame[50][144][176];
LONG VideoWidth = 176;
LONG VideoHeight = 144;
WORD BitsPerPixel = 8;
LONG BytesPerDIBSectionRow = (((VideoWidth * (long)BitsPerPixel + 31L) & (~31L)) / 8L);
BITMAPINFO *pBMI = 0;
BYTE *pBitmapBits = 0;
HBITMAP hDIBSection = 0;
HGDIOBJ hOldMemBitmap = 0;
HDC memDC = 0;
bool InitVideoRenderer()
{
pBMI = (BITMAPINFO *)new BYTE[sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD)];
pBMI->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBMI->bmiHeader.biWidth = VideoWidth;
pBMI->bmiHeader.biHeight = VideoHeight;
pBMI->bmiHeader.biPlanes = 1;
pBMI->bmiHeader.biBitCount = BitsPerPixel;
pBMI->bmiHeader.biCompression = BI_RGB;
pBMI->bmiHeader.biSizeImage = 0;
pBMI->bmiHeader.biXPelsPerMeter = 0;
pBMI->bmiHeader.biYPelsPerMeter = 0;
pBMI->bmiHeader.biClrUsed = 0;
pBMI->bmiHeader.biClrImportant = 0;
for (int color_index = 0; color_index < 256; color_index++)
{
pBMI->bmiColors[color_index].rgbBlue = color_index;
pBMI->bmiColors[color_index].rgbGreen = color_index;
pBMI->bmiColors[color_index].rgbRed = color_index;
pBMI->bmiColors[color_index].rgbReserved = 0;
}
hDIBSection = ::CreateDIBSection(NULL, pBMI, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0);
if (hDIBSection)
{
memDC = ::CreateCompatibleDC(0);
hOldMemBitmap = ::SelectObject(memDC, hDIBSection);
return true;
}
else
{
delete[] (BYTE *)pBMI;
pBMI = 0;
return false;
}
}
void RenderFrame(int FrameIndex, HWND destwnd, int x, int y)
{
<span style="color: Green;">
BYTE *pCurDIBSectionRow = pBitmapBits;
for (int row = 0; row < VideoHeight; row++)
{
for (int col = 0; col < VideoWidth; col++)
{
pCurDIBSectionRow[col] = (BYTE)(disp_frame[FrameIndex][row][col] >> 24); <span style="color: Green;">
}
pCurDIBSectionRow += BytesPerDIBSectionRow;
}
<span style="color: Green;">
HDC ClientDC = ::GetDC(destwnd);
::BitBlt(ClientDC, x, y, pBMI->bmiHeader.biWidth, pBMI->bmiHeader.biHeight, memDC, 0, 0, SRCCOPY);
::ReleaseDC(destwnd, ClientDC);
}
void CleanupVideoRenderer()
{
if (hDIBSection)
{
::SelectObject(memDC, hOldMemBitmap);
hOldMemBitmap = 0;
::DeleteDC(memDC);
memDC = 0;
::DeleteObject(hDIBSection);
hDIBSection = 0;
delete[] (BYTE *)pBMI;
pBMI = 0;
}
}
<span style="color: Green;">
if (InitVideoRenderer())
{
RenderFrame(0, *this, 0, 0); <span style="color: Green;">
CleanupVideoRenderer();
}
*edit* fixed 32bpp source to 8bpp destination pixel data conversion
Last modified: 10hrs 52mins after originally posted --
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
thank you very much. This is the first time I am getting a complete solution from Codeproject. cheers.
|
|
|
|
|
No problem!
I just realized I treated your source data as 16bpp when it's 32bpp (int!) LOL I'll change that.
Cheers,
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi Salsbery,
For the past one year the piece of code you gave me satisfied my requirements excellently. Now I have come up with a problem of displaying colour video. I will need help once again in modifying the code to colour. The main problem is how I should arrange the pixels and where to write it. What are the BITMAPINFO parameters that I have to change. Hope to get a reply at the earliest.
|
|
|
|
|
jossion wrote: modifying the code to colour
How many bits per pixel?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
8 bit per pixel in RGB format
|
|
|
|
|
I'm experiencing a wierd problem when capturing a screen from within a desktop app running on terminal server.
Here's my code:
Public Shared Function CaptureControlImage(ByVal pControl As Control, Optional ByVal pstrFilename As String = "") As System.Drawing.Image<br />
' Returns the image contained with the referenced controls client rectangle and optionally saves it to JPEG file<br />
<br />
Dim g As Graphics<br />
Dim picture As PictureBox<br />
Dim img As Image<br />
<br />
' Create a new PictureBox control. This is used to manipulate the captured bitmap<br />
picture = New PictureBox<br />
picture.Image = New Bitmap(pControl.ClientRectangle.Width, pControl.ClientRectangle.Height)<br />
<br />
' Create a GDI+ drawing surface based on the PictureBox control<br />
g = Graphics.FromImage(picture.Image)<br />
<br />
' BitBlt the screen image at the co-ordinates representing the referenced controls client rectangle<br />
' into the drawing surface, which is the PictureBox control<br />
g.CopyFromScreen(pControl.PointToScreen(New Point(pControl.ClientRectangle.X, pControl.ClientRectangle.Y)), _<br />
New Point(0, 0), _<br />
New Size(pControl.ClientRectangle.Width, pControl.ClientRectangle.Height))<br />
<br />
' Creates an image object from the PictureBox surface<br />
img = picture.Image<br />
<br />
If Not IsNothing(img) AndAlso pstrFilename <> String.Empty Then<br />
' Save the image to disk if required<br />
img.Save(pstrFilename, Drawing.Imaging.ImageFormat.Jpeg)<br />
End If<br />
<br />
Return img<br />
End Function<br />
It works just fine when running locally, but when the app is deployed on another server and it's access via terminal server, then this is what you get:
http://www.threefivefive.com/gallery/data/500/medium/capture_ts.jpg[^]
Can anyone tell me why?
|
|
|
|
|
Hi I have searched everywhere and cannot find a way to progamatically mirror the screen. What I need is to be able to look into a mirror at the screen and view it correctly. i.e Everything on the screen must be from right to left and not left to right. Thank you
|
|
|
|
|
Maybe this article will help you:
http://www.microsoft.com/middleeast/msdn/mirror.aspx[^]
you could copy the content of your screen to an image, flip this image and draw it back to the screen. no problem there, if you just want the screen to show everything mirrored. of course you won't be able to use the controls, since just the mirrored image is drawn back to the screen while the controls are still in their original place.
"I love deadlines. I like the whooshing sound they make as they fly by." (DNA)
modified on Thursday, February 28, 2008 5:43 PM
|
|
|
|
|
I want to ask one more thing that i am using this code ... where height is the Font height and startPoint_x and startPoint_y is the point where text is to be display
CsGL.OpenGL.GDITextureFont myGDITextureFont;
Font newFont;
newFont = new System.Drawing.Font("Microsoft Sans Serif", (float)height);
myGDITextureFont = new GDITextureFont(newFont, 'a', 'z');
GL.glTranslatef((float)startPoint_x, (float)startPoint_y, 0);
myGDITextureFont.DrawString(text);
and in this way text displayed but when i click on it it turns into solid bar .... What is the problem with this code ....
|
|
|
|
|
I am using C#, OpenGL and want to draw the Text on screen ... I went to OpenGL site and see the GLFont and other methods. Problem I face in these are:
They give Code in C++ that uses pointers and references that are not supported in C# and it call them as unmanaged code, i write unsafe modifier in front of it but other problem arises. So, these codes are not helpful unless they are in C# language.
if anyone know the method how to draw text in openGL or how to use C++ code in C# language then tell me .... I will be very pleased for your help ....
|
|
|
|
|
Yasir Nawazish Ali wrote: if anyone know the method how to draw text in openGL or how to use C++ code in C# language then tell me .... I will be very pleased for your help ....
one way[^]
another.[^]
_________________________
Asu no koto o ieba, tenjo de nezumi ga warau.
Talk about things of tomorrow and the mice in the ceiling laugh. (Japanese Proverb)
|
|
|
|
|