|
Hello. It may seem like a beginner question, but I'd like to know how to draw a line. Simple? I've been looking all over the net, and through these books I have, (also CodeProject) and nothing "works". Please help, thanks in advance.
- I love D-flat!
|
|
|
|
|
Hi,
for the Form, Panel, or whatever Control you want to draw on, use the OnPaint handler
(or add a new handler to the Paint event); it will give you a PaintEventArgs offering
a Graphics object, then use Graphics.DrawLine() and the like.
If you need examples, there are plenty around at CP. My Sokoban article also has some
line drawing.
[ADDED] just noticed some essential info got hidden in the subject line;
for XNA things are a bit more complicated, but they do provide some documentation,
so this may help[^].
[/ADDED]
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.
modified on Sunday, January 13, 2008 5:03:32 PM
|
|
|
|
|
Oh, I know how to draw lines there. That's easy. BUT, in XNA, it's a whole new territory.
To your added reply, I've seen that, and tried, but wasn't sure what type the variables were when previously declared (they didn't show it there).
Example: points?
(My bad, I had pointList; it was points)
- I love D-flat!
modified on Sunday, January 13, 2008 5:10:42 PM
|
|
|
|
|
Not sure if this can be done simply, but hoping it can be. I want to draw shapes anywhere on the screen, regardless of my forms location. I want to be able to draw off the form. Can anyone provide guidance or even an example?
|
|
|
|
|
The ANZAC wrote: I want to draw shapes anywhere on the screen, regardless of my forms location. I want to be able to draw off the form.
You can't. You can only draw on your form.
|
|
|
|
|
|
i don't know, if this is what you are looking for, but i found that piece of vb.net-code on a cd:
<br />
Private Declare Function GetDC Lib "user32" Alias "GetDC" (ByVal hwnd As Integer) As IntPtr<br />
Private Declare Function ReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hwnd As Integer, ByVal hdc As IntPtr) As Integer<br />
<br />
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click<br />
Dim blackPen As New Pen(Color.Black, 3)<br />
Dim dc As IntPtr<br />
Dim g As Graphics<br />
<br />
Dim rnd As New Random()<br />
Dim i As Integer<br />
dc = GetDC(0)<br />
g = Graphics.FromHdc(dc)<br />
For i = 0 To 1000<br />
g.DrawLine(blackPen, rnd.Next(600), rnd.Next(600), rnd.Next(600), rnd.Next(600))<br />
Next<br />
g.Dispose()<br />
ReleaseDC(0, dc)<br />
End Sub<br />
click on the button to draw a bunch of lines to the screen, independent of your form.
is this of any help?
"I love deadlines. I like the whooshing sound they make as they fly by." (DNA)
|
|
|
|
|
hey,
can someone suggest good book or online material on 3d mesh manipulation that starts from basic concepts
thanks
|
|
|
|
|
The book 3D Computer Graphics, by Alan Watt, published by Addison Wesley, is really excellent.
|
|
|
|
|
I'm using GDI+, and want to edit the pixels of an 8 bit-per-pixel, grayscale bitmap which I read from a file. I can get the pixels using the Bitmap::LockBits and BitmapUnlockBits methods and a BitmapData object. However, there doesn't seem to be any support for 8 bit-per-pixel bitmaps that do not necessarily use a palette (i.e. grayscale).
I see that the pixel format can be set to PixelFormat8bppIndexed, and used along with a palette (the palette type can even be set to PaletteFlagsGrayScale). However, it is unnecessary to use a palette with these bitmaps, as the palette just contains all possible gray levels. It seems inefficient to have to associate a palette with these bitmaps and pass it back and forth each time the pixels are retrieved (the pixels are frequently and repeatedly passed back and forth for editing in my program).
Does anyone know:
1) Are there any other flags or methods for using BitmapData objects with 8 bit-per-pixel grayscale bitmaps but without a palette?
2) When the PaletteFlagsGrayScale flag is used, can I assume the palette entries are always the same (all possible gray levels)? Or can they be re-scaled? (I understand that these entries are DWORDs using alpha | red | green | blue, with the red, green and blue values equal to each other.)
Thanks!
|
|
|
|
|
Hi,
I have a windows CE device for which I am wrinting a C# .Net CF 2.0 application.
This device has an inclinometer chip connected to it, which reads the angles my device is at, and sends me the X and Y tilt values of the inclinometer.
Depending on those values, I want to display a picture. (.png). For now now I'm just using the X value (tiltX global variable)
The image is being updated every 150ms
So for a prototype I've being doing the following:
//TiltX is being passed in to RotateGauge as an Int.
private void RotateGauge(int side)
{
if (side > -5 & side < 5)
{
string number = Convert.ToString(side);
Stream sidePic = _assembly.GetManifestResourceStream("Rotate_Test.images.gauge.sideTilt" + (number) + ".png");
Bitmap bmp = new Bitmap(sidePic);
Graphics g = CreateGraphics();
g.DrawImage(bmp, 42,116); //draw image
bmp.Dispose();
sidePic.Close();
g.Dispose();
}
}
The above function RotateGauge() gets called from a timer. (interival 150ms)
The problem is its using up a lot of memory. I don't think I'm properly disposing of things.
Any suggestions how to : Efficiently rewrite the above code so when something gets created on a timer_tick it also gets disposed of properly
|
|
|
|
|
Hi,
I don't see anything wrong with your object disposal, so I expect the garbage collector
will clean up memory if need be.
However I think you are spending way too much CPU power to achieve your goals. This is
how I would do it:
- replace the PictureBox by a simple Panel (or an inherited Panel that sets its
ControlStyles to double-buffered for better graphics);
- do the drawing in the Panel's OnPaint method, based on a single class member (int side);
it gives you a Graphics for free (which you should not dispose!);
- when you want to change the gauge, change the variable (side) and call your Panel's
Invalidate method
If you only have a dozen PNG images, you may even consider keeping them alive in memory
all the time.
|
|
|
|
|
Hey Luc. Congratulations on your MVP status. It's well deserved.
|
|
|
|
|
Hi Pete, thanks. Congrats to you too.
I see several of us have reached the next station.
Mine came as a surprise, wasn't aware how many there would be, but even then...
|
|
|
|
|
Luc Pattyn wrote: Mine came as a surprise
Not to me. I had good money riding on you getting it.
It's nice not to have the yokel icon beside the names now. I like being a yellow diamond.
|
|
|
|
|
Pete O'Hanlon wrote: I had good money riding on you getting it.
Who is taking those bets? is that what is going on in the dark hours at the lounge?
Pete O'Hanlon wrote: It's nice not to have the yokel icon beside the names now. I like being a yellow diamond
Had to look that up, but I fully agree; it was/is not the nicest icon available.
BTW I think the golden diamond writer personality title I currently carry is the one I
like most (prolific fixture sounds really weird to me, I'll try to avoid it).
|
|
|
|
|
forgot to mention, I did notice how you skilfully reverted the topic to make it really fit
the graphics forum. A worthy diamond.
|
|
|
|
|
Hi Luc,
Thanks for your reply. I got overly excited when I saw 6 replies to my post as i've spent a lot of time trying to figure this out.
I attempted what you suggested, however the Compact Framework has me limited in what I can do.
The line of code I hoped to use for drawing in the panel is
g = panel1.CreateGraphics();
however, CreateGraphics is not availble to my panel in the CF. I'll keep looking, I'm very new to c# (programming in general) so there may be a solution for me somewhere.
Regards
Gemma
|
|
|
|
|
Hi, maybe you should read my original reply once more. The whole point was NOT to use
CreateGraphics, but OnPaint() instead.
|
|
|
|
|
Hi Luc,
I've since gone off and done some reading on .net CF graphics, in the process I came across some code which I've implemented into my project.
private Bitmap LoadBitmapResource(string strName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
string strRes = "Rotate_Test.images.gauge." + strName;
Stream stream = assembly.GetManifestResourceStream(strRes);
Bitmap bmp = null;
try
{
bmp = new Bitmap(stream);
}
catch { }
stream.Close();
return bmp;
}
private void DisposeBitmap(ref Bitmap bmp)
{
if (bmp != null)
{
bmp.Dispose();
}
bmp = null;
}
In the Panel Paint method I have the following.
private void panel1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
DisposeBitmap(ref bmpDraw);
//Get the Bitmap to draw
bmpDraw = LoadBitmapResource("backTilt" + (strResNum) + ".bmp");
g.DrawImage(bmpDraw, 10, 10);
}
The above is still using up memory for every image which is displayed, it seems like nothing is being freed up. I haven't started looking at double buffering as for now I'm more concerned with relasing the memory used.
Thanks for your suggestion
regards
Gemma
|
|
|
|
|
Hi Gemma,
1.
your code looks fine to me, with one comment: if every OnPaint does a Disposeand a Load,
and assuming bmpDraw is not used elsewhere, why not do it after the DrawImage (hence:
load,draw,dispose)?
2.
calling Dispose is good, it frees unmanaged resources immediately (if any), and marks
managed objects for garbage collection, which only occurs when the garbage collector feels
a need (i.e. when memory is low when a new object is being created, say in a "new" statement).
So it is not abnormal to see a high memory usage, as long as it comes down every so often,
and does not lead to an "out of memory" situation.
As a test, you could add a big object to your main class (to occupy memory) and see
how well the app does under those circumstances, so add a line such as:
private byte[] dummyBytes=new byte[1024*1024]; // permanently occupies 1MB
3.
If you are still not satisfied, here are some questions:
- what is it that makes you worry?
- how many images are there?
- how big is each image (in pixels and in file size)?
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.
|
|
|
|
|
Thanks for the useful information and checking my code for me.
I've no peers to learn from or show my code to, (one man show here) so its great to get advice.
|
|
|
|
|
You're welcome.
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.
|
|
|
|
|
Below is the code snippet i use to create the gray scale image (8bpp) from scratch using CreateDIBSection and displays it onto the screen.
Image that is displayed has most of it data grey in color and the image data seems to be merged with lot of noise... I doubt the issue is with the image creation....
need some help on this, all help appreciated
Let me know the flaws in the code, I am new to Windows graphic programming.
btw, i work with MFC
Code :
struct ImageData
{
int rows;
int cols;
int bpp;
.
.
.
.
.
.
}; // Other fields are not relevant for Image Display
int pixmap[256]; // Palette to be used
ImageData curimage; // Member Variable in the App Dialog Class
void CExampleDlg::SetBitmapInfo (LPBITMAPINFO DIB_info, ImageData *imageptr)
{
DIB_info->bmiHeader.biSize = 40;
DIB_info->bmiHeader.biPlanes = 1;
DIB_info->bmiHeader.biBitCount = imageptr->bpp; // only 8 (handling only 8bpp images)
DIB_info->bmiHeader.biWidth = imageptr->cols;
DIB_info->bmiHeader.biHeight = imageptr->rows;
DIB_info->bmiHeader.biCompression = BI_RGB;
DIB_info->bmiHeader.biSizeImage = imageptr->rows * imageptr->cols;
DIB_info->bmiHeader.biXPelsPerMeter = 0;//0xb12; //(72ppi)
DIB_info->bmiHeader.biYPelsPerMeter = 0;//0xb12;
DIB_info->bmiHeader.biClrUsed = 256;
DIB_info->bmiHeader.biClrImportant = 256;
DIB_info->bmiColors[0].rgbBlue = 0;
DIB_info->bmiColors[0].rgbGreen = 0;
DIB_info->bmiColors[0].rgbRed = 0;
DIB_info->bmiColors[0].rgbReserved = 0;
}
void CExampleDlg::GetDIBmp (unsigned char *bmp,
CBitmap *pimage,
ImageData *imageptr,
int height,
int width)
{
BITMAPINFO DIB_info;
HBITMAP hBitmap = NULL;
HDC hMemDC = NULL;
HGDIOBJ hOldObj = NULL;
// Set the BitmapInfo
SetBitmapInfo (&DIB_info, imageptr);
DIB_info.bmiHeader.biHeight = height;
DIB_info.bmiHeader.biWidth = width;
hMemDC = ::CreateCompatibleDC(NULL);
// create device independent bitmap section
hBitmap = ::CreateDIBSection(hMemDC,
&DIB_info,
DIB_RGB_COLORS,
NULL,
NULL,
SRCCOPY);
if ( !hBitmap )
{
exit (-1);
}
DIB_info.bmiHeader.biHeight = imageptr->rows;
DIB_info.bmiHeader.biWidth = imageptr->cols;
//CreateDIBTable (DIB_info,hMemDC,bmp);
hOldObj = ::SelectObject(hMemDC, hBitmap);
StretchDIBits(hMemDC, 0, 0,
width, height, 0, 0,
DIB_info.bmiHeader.biWidth,
DIB_info.bmiHeader.biHeight,
bmp,&DIB_info,
DIB_RGB_COLORS,
SRCCOPY);
// restore DC object
::SelectObject(hMemDC, hOldObj);
// clean up
::DeleteObject(hMemDC);
pimage->Attach(hBitmap);
}
void CExampleDlg::GetPalette (BITMAPINFO DIB_info,
CBitmap *bitmap,
CPalette *pal)
{
unsigned long nColors = DIB_info.bmiHeader.biClrUsed;
// Create a halftone palette if colors > 256.
CClientDC dc(NULL); // Desktop DC
if( nColors > 256 )
pal->CreateHalftonePalette( &dc );
else
{
// Create the palette
RGBQUAD *pRGB = new RGBQUAD[nColors];
CDC memDC;
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject( bitmap );
::GetDIBColorTable( memDC, 0, nColors, pRGB );
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = pixmap[i];
pLP->palPalEntry[i].peGreen = pixmap[i];
pLP->palPalEntry[i].peBlue = pixmap[i];
pLP->palPalEntry[i].peFlags = 0;
}
pal->CreatePalette( pLP );
delete[] pLP;
delete[] pRGB;
}
}
void CExampleDlg::CreateDIBTable (BITMAPINFO DIB_info,HDC hMemDC,
unsigned char *bmp)
{
if (DIB_info.bmiHeader.biBitCount <= 8)
{
HPALETTE hPalette =
(HPALETTE) GetCurrentObject(hMemDC, OBJ_PAL);
if (hPalette)
{
PALETTEENTRY pPaletteEntries[0x100];
UINT nEntries = GetPaletteEntries(hPalette,
0, DIB_info.bmiHeader.biClrUsed,
pPaletteEntries);
if (nEntries)
{
ASSERT(nEntries <= 0x100);
for (UINT nIndex = 0; nIndex < nEntries; nIndex++)
{
pPaletteEntries[nIndex].peRed = pixmap [nIndex];
pPaletteEntries[nIndex].peGreen = pixmap [nIndex];
pPaletteEntries[nIndex].peBlue = pixmap [nIndex];
pPaletteEntries[nIndex].peFlags = 0;
}
int entries = SetDIBColorTable(hMemDC, 0,
0x100, (RGBQUAD*) pPaletteEntries);
VERIFY(entries == nEntries);
}
}
}
}
void CExampleDlg::ShowImage()
{
unsigned char *bmp;
CGdiObject *oldDC;
BITMAPINFO dib;
bmp = ViewImage(&curimage);
CBitmap *pimage = new CBitmap;
GetDIBmp (bmp,pimage,&curimage,
100 /* Height */,
100 /* Width */);
// Identifies the device context(dialog) of client area
CPaintDC dc(this);
CDC pMemDC;
pMemDC.CreateCompatibleDC ( &dc );
oldDC = pMemDC.SelectObject ( pimage );
CPalette pal;
this->GetPalette (dib,pimage,&pal);
if((dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE) && pal.m_hObject != NULL )
{
dc.SelectPalette( &pal, FALSE );
int entry = dc.RealizePalette();
}
dc.StretchBlt (30,30,
100,
100,
&pMemDC,
0,
0,
curimage.cols,
curimage.rows,
SRCCOPY);
::SelectObject (pMemDC.m_hDC,oldDC);
DeleteObject (pMemDC.m_hDC);
delete []bmp;
delete pimage;
}
|
|
|
|
|
There's a bunch of problems there, but the biggest one I immediately
see is in CExampleDlg::GetDIBmp().
Instead of
BITMAPINFO DIB_info;
you need to add room for the 256 entry color table you've specified when
creating the DIBSection, something like:
BITMAPINFO *pDIB_info = (BITMAPINFO *)new BYTE[sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 255];
...
delete[] (BYTE*)pDIB_info;
You can then iterate through the DIB_info->bmiColors[] array and set the
color table to grayscale values...
for (int i = 0; i < 256; i++)
{
DIB_info->bmiColors[i].rgbBlue = i;
DIB_info->bmiColors[i].rgbGreen = i;
DIB_info->bmiColors[i].rgbRed = i;
DIB_info->bmiColors[i].rgbReserved = 0;
}
Then create the DIB section.
You may be able to simplify this whole thing....
What format is the ImageData pixels data? Is it already 8-bit grayscale
or is it 8-bit indexes into a color palette? Do you eventually want to be able to
convert 24-bit RGB to 8 bit grayscale?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|