Solved

Reading the file and drawing the grid in GDI+

Posted on 2011-03-19
13
598 Views
Last Modified: 2012-05-11
In GDI+, How can I read the file and draw a grid

Thanks.
0
Comment
Question by:pgmerLA
  • 7
  • 5
13 Comments
 
LVL 8

Expert Comment

by:SunnyDark
ID: 35172891
Step three of the tutorial
0
 
LVL 8

Expert Comment

by:SunnyDark
ID: 35172917
Since reading the file is not the focus of this tutorial I will just post the code without much explanations:
First put the following includes at the top of the file (where other includes are):

#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <ctime>
using namespace std;

Open in new window



Then put the following definitions where all other function definitions are:
void LoadData();

struct PointData
{
	time_t datetime;
	double open;
	double high;
	double low;
	double close;
	int up;
	int down;
};
std::list<PointData> pointList;

Open in new window


Add the data loading function somewhere in the file:
void LoadData()
{
	string line;
	ifstream myfile ("C:\\OCENY.txt");
	int linepos = 0;
	if (myfile.is_open())
	{
		while ( myfile.good() )
		{
			getline (myfile,line);
			// Parse the line
			if (linepos > 0) // Skip the first header line
			{
				PointData pt;
				struct tm t;
				ZeroMemory(&t, sizeof(tm));
				int fields = sscanf(line.c_str(), "%d/%d/%d,%2d%2d,%le,%le,%le,%le,%d,%d",&t.tm_mon, &t.tm_mday,&t.tm_year,&t.tm_hour,&t.tm_min, &pt.open, &pt.high, &pt.low, &pt.close, &pt.up, &pt.down);
				if (fields == 11)
				{
					t.tm_year -= 1900;
					pt.datetime = mktime ( &t );
					pointList.push_back(pt);
				}
			}
			linepos++;
		}
		myfile.close();
	}
}

Open in new window


Don't forget to change the filename to the actual filename on your computer.

Then just call the LoadData function from the InitInstance function right after the GdiplusStartup call.
Tell me when this is accomplished.
0
 

Author Comment

by:pgmerLA
ID: 35172983
I add the code.
And I add void LoadData(); on the line 31.

Could you double check my code to make sure there is no mistake?
It compiled fine though.

What is the next step?
// GDIGraph.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "GDIGraph.h"
#pragma comment(lib,"gdiplus.lib")
#include<gdiplus.h>
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <ctime>
using namespace std;
using namespace Gdiplus;


#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR			gdiplusToken;

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);
void LoadData();

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;
	HACCEL hAccelTable;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_GDIGRAPH, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIGRAPH));

	// Main message loop:
	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	GdiplusShutdown(gdiplusToken);
	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDIGRAPH));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_GDIGRAPH);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
   LoadData();
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND	- process the application menu
//  WM_PAINT	- Paint the main window
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_ABOUT:
			DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
			break;
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_PAINT:
		{
		hdc = BeginPaint(hWnd, &ps);
		
		// TODO: Add any drawing code here...
		int width = ps.rcPaint.right - ps.rcPaint.left;
		int height = ps.rcPaint.bottom - ps.rcPaint.top;
		Bitmap memoryBitmap(width, height);
		Graphics gr(&memoryBitmap);
		gr.Clear(Color::White); // Clear to white background
        Pen pen(Color::Red); // This is the pen we will use to draw
        gr.DrawRectangle(&pen, 10,10,100,100); // Draw rectangle from 10,10 to 110,110
		Graphics grScreen(hdc);
		grScreen.DrawImage(&memoryBitmap, 0,0);
		EndPaint(hWnd, &ps);
		}
		break;
	case WM_ERASEBKGND:
		return TRUE;
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
		{
			EndDialog(hDlg, LOWORD(wParam));
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}
void LoadData();

struct PointData
{
	time_t datetime;
	double open;
	double high;
	double low;
	double close;
	int up;
	int down;
};
std::list<PointData> pointList;
void LoadData()
{
	string line;
	ifstream myfile ("COCENY.txt");
	int linepos = 0;
	if (myfile.is_open())
	{
		while ( myfile.good() )
		{
			getline (myfile,line);
			// Parse the line
			if (linepos > 0) // Skip the first header line
			{
				PointData pt;
				struct tm t;
				ZeroMemory(&t, sizeof(tm));
				int fields = sscanf(line.c_str(), "%d/%d/%d,%2d%2d,%le,%le,%le,%le,%d,%d",&t.tm_mon, &t.tm_mday,&t.tm_year,&t.tm_hour,&t.tm_min, &pt.open, &pt.high, &pt.low, &pt.close, &pt.up, &pt.down);
				if (fields == 11)
				{
					t.tm_year -= 1900;
					pt.datetime = mktime ( &t );
					pointList.push_back(pt);
				}
			}
			linepos++;
		}
		myfile.close();
	}
}

Open in new window

0
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
LVL 8

Expert Comment

by:SunnyDark
ID: 35173310
First there is no need to declare LoadData on line 31 AND on line 221,
remove the declaration on line 221
Second move the declaration of PointData struct and the pointList

struct PointData
{
	time_t datetime;
	double open;
	double high;
	double low;
	double close;
	int up;
	int down;
};
std::list<PointData> pointList;

Open in new window


to the top of the file (line 32 for example would be fine)

0
 
LVL 8

Expert Comment

by:SunnyDark
ID: 35173337
The next step :
declare 2 new functions:

void DrawGraph(Graphics& gr, Rect& rect);
void DrawHistogram(Graphics& gr, Rect& rect);
void DrawGrid(Graphics& gr, Rect& rect);

Open in new window


Put the declaration somewhere on the top of the file...
Now create the bodies of those functions somewhere in the file (you can out is at the end of the file , though it doesn't really matter)
By the way the reason to first declare the function at the top of the file and then put it's body somewhere further in the file is this: If you use the function somewhere BEFORE it is declared , it is still undefined, so to prevent it we declare each function at the top of the file so it will alway be already defined further in the file.
So the body of those function look like this:

void DrawGraph(Graphics& gr, Rect& rect)
{
	DrawGrid(gr, rect);
}
void DrawHistogram(Graphics& gr, Rect& rect)
{
	DrawGrid(gr, rect);
}
void DrawGrid(Graphics& gr, Rect& rect)
{

}

Open in new window


As you can guess the fist draws the graph and the second the histogram, since both need to draw the background grid the both call the third function that actually draws the grid.

0
 
LVL 8

Expert Comment

by:SunnyDark
ID: 35173341
Next we will change our paint section like this:

case WM_PAINT:
		{
			hdc = BeginPaint(hWnd, &ps);

			RECT rcClient;
			GetClientRect(hWnd, &rcClient);

			int width = rcClient.right - rcClient.left;
			int height = rcClient.bottom - rcClient.top;

			Bitmap memoryBitmap(width, height);
			Graphics gr(&memoryBitmap);
			gr.Clear(Color::White);		// Clear to white background

			Rect rectGraph(rcClient.left, rcClient.top, width, height / 2);
			Rect rectHistogram(rcClient.left, rcClient.top + height / 2, width, height / 2);

			DrawGraph(gr, rectGraph );
			DrawHistogram(gr, rectHistogram);

			Graphics grScreen(hdc);
			grScreen.DrawImage(&memoryBitmap, 0,0);

				
			EndPaint(hWnd, &ps);
		}
		break;

Open in new window


As you can see we draw the graph in the top half of rectangle and the histogram in the bottom half
0
 

Author Comment

by:pgmerLA
ID: 35173342
Done.
What's next?
:)
0
 
LVL 8

Expert Comment

by:SunnyDark
ID: 35173540
Here is the finished 3 functions:

void DrawGraph(Graphics& gr, Rect& rect)
{
	rect.Inflate(-4,-4);
	DrawGrid(gr, rect);
}

void DrawHistogram(Graphics& gr, Rect& rect)
{
	rect.Inflate(-4,-4);
	DrawGrid(gr, rect);
}

void DrawGrid(Graphics& gr, Rect& rect)
{
	Pen penGridDash(Color::LightGray, 1);
	penGridDash.SetDashStyle(DashStyle::DashStyleDash);
	Pen penGridSolid(Color::LightGray, 1);
	Pen penGridBorder(Color::Gray, 1);
	
	// Draw the border
	gr.DrawRectangle(&penGridBorder, rect);

	// Just draw some grid lines at determined space of 20 pixels...
	for (int i = rect.GetLeft() + 20; i < rect.GetRight(); i+= 20)
	{
		gr.DrawLine(&penGridDash, i, rect.GetTop(), i, rect.GetBottom());
	}
}

Open in new window


And here is what the result should look like :
 gdi3Note that I only drew the vertical lines , I leave the horizontal line to your implementation.
Use the penGridSolid to draw them.
Good luck.
After that 4 step of the tutorial.
Just call the question: "GDI tutorial step 4"

0
 

Author Comment

by:pgmerLA
ID: 35209503
I am having a hard time doing it. i have tried many different combination, but none worked.
could you give a hint or a link I could look at for what/how to use the function?

thanks.
0
 
LVL 8

Accepted Solution

by:
SunnyDark earned 500 total points
ID: 35211271
I am just going to post the complete project , and the after you have looked at it it will be  easier to explain if there are still things you didn't understand.
You may download the project here:
http://www.rdvsystems.com/EE/GDIGraph.zip
0
 

Author Comment

by:pgmerLA
ID: 35243327
Hi, do you want to start over with the full code and make small tutorial going over the complete code. You could break it down by "subject" or part of the code. and we could go from there.

can you give the title and what to write in the body of the question so that other people could  benefit from it as well.

thanks.
*email address removed*
0
 

Author Comment

by:pgmerLA
ID: 35302663
Hi SunnyDark,

are you around?

PS:There must be a better to communicate.
0

Featured Post

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
What does std::atomic give me? 7 124
object modeling - load and save functions 5 61
FMX enumerated colours 2 100
passing data from one form to another form in c++ 27 80
In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question