?
Solved

Reading the file and drawing the grid in GDI+

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

Thanks.
0
Comment
Question by:pgmerLA
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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 2000 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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
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…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

770 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