Solved

Reading the file and drawing the grid in GDI+

Posted on 2011-03-19
13
589 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
 
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

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

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
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 be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

746 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now