Saeven Posted March 2, 2004 Posted March 2, 2004 Hello, I am very new to GDI and Windows .net Forms - please forgive me for any sacrilegeous use of its components! :) Fiddling with tutorials, I have devised the class whose code is detailed below. All the methods work fine, the custom 'drawFittest' function draws what it is required to draw. However, it is being called frequently from inside a while loop in the main program and the form becomes irresponsive while displaying its contents. This GUIDE class is meant to be a viewscreen that shows data as it is being processed. Right now, it displays ok - but I cannot resize or move etc. If I drag the mouse over the form the windows hourglass shows, and if I attempt to drag it - there is a slight delay before it does drag, and after this it does not display contents properly anymore. Any help appreciated, it is being called like this: main program: int main( void ){ GUIDE *screen = new GUIDE(); screen->Show(); screen->Refresh(); run_GA( screen ); // this calls the loop that calls the drawFittest method if( csv ) fout.close(); return 0; } #using <mscorlib.dll> #using <System.dll> #using <System.Drawing.dll> #using <System.Windows.Forms.dll> using namespace System; using namespace System::Drawing; using namespace System::Windows::Forms; __gc class GUIDE : public Form { private: PictureBox *PictBox; Point p1, p2; Graphics *g; Pen *red, *black; CITY *c, *d; double lastFitness; unsigned int from, to; public: void GUIDE::drawFittest( GASTRING * fittest ){ if( fittest->fitness != 1000000000 && fittest->fitness != lastFitness ){ Refresh(); std::vector<CITY*>::iterator i; for( i = cities.begin() ; i != cities.end() ; ++i ){ c = *i; p1 = Point( (int)c->x, (int)c->y ); p2 = Point( (int)c->x, (int)c->y + 5 ); g->DrawLine( black, scale( p1 ), scale( p2 ) ); } unsigned int size = fittest->genome.size(); for( unsigned int i = 0 ; i < size ; i++ ){ from = fittest->genome[i] - 1; to = fittest->genome[(i+1)%size] - 1; c = cities[from]; d = cities[to]; p1 = Point( (int)c->x, (int)c->y ); p2 = Point( (int)d->x, (int)d->y ); g->DrawLine( red, scale( p1 ), scale( p2 ) ); } lastFitness = fittest->fitness; } } Point scale( Point p ){ int width = 540; int height = 480; int max_width = 1800; int max_height = 1800; return Point( p.X * width / max_width , p.Y * height / max_height ); } GUIDE(){ Text = S"Map box"; Size = Drawing::Size(580, 545); PictBox = new PictureBox; PictBox->BorderStyle = BorderStyle::FixedSingle; PictBox->BackColor = Drawing::Color::White; PictBox->Location = Point(16, 16); PictBox->Size = Drawing::Size(540, 480); Controls->Add(PictBox); g = Graphics::FromHwnd( PictBox->Handle ); red = new Pen( Color::Red, 1 ); black = new Pen( Color::Black, 1 ); lastFitness = 0; } }; Thanks for any help! Regards. Alex Quote
AlexCode Posted March 3, 2004 Posted March 3, 2004 If you're so very new to .net like you told... why did you start with the hardest language?? :P Not only most of us wouldn't be able to help you but you'll have a lot of troubles on your path... A friend advise woulb be for you to consider start with C# (I say C# cause it's the most C++ alike language) and when you feel confortable with the .net plattform and feel the need to take the leap to C++.net it wuold be a lot easyer... Just to note that you'll never feel the need to use C++.net unless you need to code something very very very specific like a driver or something like that... Alex :p (friend advisor) :D:D Quote Software bugs are impossible to detect by anybody except the end user.
Saeven Posted March 3, 2004 Author Posted March 3, 2004 Hi, I've been doing c++ on linux for a long time now - my challenge isn't with the language - but instead with the GDI+ which is windows based (new world for me). Sometimes it's just easier on linux ;) Unfortunately, this is to be presented on a windows platform. I'm not very fond of platform specific languages, and as such I will likely stay away from C#. This is a genetic algorithm and I'd like to keep things as bitwise as possible :) Cheers. Alex Quote
*Experts* mutant Posted March 3, 2004 *Experts* Posted March 3, 2004 How does the loop that calls the drawing routine look? Quote
Saeven Posted March 3, 2004 Author Posted March 3, 2004 Hi. I've since changed my guide class to look like this: #using <mscorlib.dll> #using <System.dll> #using <System.Drawing.dll> #using <System.Windows.Forms.dll> using namespace System; using namespace System::Drawing; using namespace System::Windows::Forms; __gc class GUIDE : public Form { private: PictureBox *PictBox; Point p1, p2, fpoint; Graphics *g; Pen *red, *black; CITY *c, *d; double lastFitness; unsigned int from, to; Drawing::Font *arial; Drawing::SolidBrush *brush; public: void GUIDE::drawFittest( GASTRING * fittest, int generation ){ stringstream s; if( fittest->fitness != 1000000000 && ( fittest->fitness != lastFitness || generation % 100 == 0 ) ){ Refresh(); std::vector<CITY*>::iterator i; for( i = cities.begin() ; i != cities.end() ; ++i ){ c = *i; p1 = Point( (int)c->x, (int)c->y ); p2 = Point( (int)c->x, (int)c->y + 5 ); g->DrawLine( black, scale( p1 ), scale( p2 ) ); } unsigned int size = fittest->genome.size(); for( unsigned int i = 0 ; i < size ; i++ ){ from = fittest->genome[i] - 1; to = fittest->genome[(i+1)%size] - 1; c = cities[from]; d = cities[to]; p1 = Point( (int)c->x, (int)c->y ); p2 = Point( (int)d->x, (int)d->y ); g->DrawLine( red, scale( p1 ), scale( p2 ) ); } s << "Distance [" << fittest->fitness << "]"; System::String *fitstr = new System::String( s.str().c_str() ); g->DrawString( fitstr, arial, brush, fpoint ); lastFitness = fittest->fitness; } } Point scale( Point p ){ int width = 540; int height = 480; int max_width = 1800; int max_height = 1800; return Point( p.X * width / max_width , p.Y * height / max_height ); } GUIDE(){ Text = S"Map box"; Size = Drawing::Size(580, 545); PictBox = new PictureBox; PictBox->BorderStyle = BorderStyle::FixedSingle; PictBox->BackColor = Drawing::Color::White; PictBox->Location = Point(16, 16); PictBox->Size = Drawing::Size(540, 480); Controls->Add(PictBox); g = Graphics::FromHwnd( PictBox->Handle ); red = new Pen( Color::Red, 1 ); black = new Pen( Color::Black, 1 ); lastFitness = 0; arial = new System::Drawing::Font( "Arial", 10 ); brush = new System::Drawing::SolidBrush( Color::Black ); fpoint = Point( 410, 460 ); } }; And the function that gets this going looks like this: int main( void ){ GUIDE *screen = new GUIDE(); screen->Show(); screen->Refresh(); fittest = new GASTRING(); fittest->fitness = 1000000000; srand( (unsigned)time(NULL) ); if( csv ) fout.open( "output.txt" ); load_cities(); build_travel_matrix(); generate_population(); run_GA( screen ); if( csv ) fout.close(); return 0; } void run_GA( GUIDE * screen ){ bool match = false; double last_distance = 0; int last_count = 0; while( !match && ++generation ){ screen->drawFittest( fittest, generation ); reproduction_cycle(); // mate + xover + mutation if( fittest->fitness == last_distance ){ last_count++; } else{ last_count = 0; last_distance = fittest->fitness; } if( last_count == 1000 ){ cout << "Fitness has not changed in past 1000 generations. Exiting." << endl; match = true; } } return; } Thanks! Alex Quote
*Experts* mutant Posted March 3, 2004 *Experts* Posted March 3, 2004 You don't seem to give your application enough time to process messages. Its stuck in the loop only doing what you specified in the loop. To allow your application to process messages use this: System::Windows::Forms::Application::DoEvents(); Now your application will be able to process the messages including resize, move etc. Stick that line of code at the bottom of your loop or anywhere in your loop. Quote
Saeven Posted March 3, 2004 Author Posted March 3, 2004 This call is threaded or should be called at each iteration? Cheers! Alex Quote
Saeven Posted March 3, 2004 Author Posted March 3, 2004 Looks like I've answered my own question by simply trying it out :) I have another for you though.. When I close the screen now (moving and everything works wonderfully. I get this error: Unhandled Exception: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+. at System.Drawing.Graphics.DrawLine(Pen pen, Int32 x1, Int32 y1, Int32 x2, In t32 y2) at System.Drawing.Graphics.DrawLine(Pen pen, Point pt1, Point pt2) at GUIDE.drawFittest(GASTRING* fittest, Int32 generation) in guide.h:line 33 I've tried perhaps considering that the screen once closed would become null and wrapping the calls inside an: if( screen ){ screen->drawFittest( fittest, generation ); System::Windows::Forms::Application::DoEvents(); } However this doesn't seem to be the ticket. What happens to the screen object once closed? How can I prevent from any writing once the screen gets disposed of? Thanks! Alex Quote
*Experts* mutant Posted March 4, 2004 *Experts* Posted March 4, 2004 You can prevent drawing to the form by checking the Created property of the Form object. If its false then the form is closed and you can exit the loop. Quote
Saeven Posted March 4, 2004 Author Posted March 4, 2004 Thank you very much - works like a charm. A+ for all your help. Is there a good book on these types of things anywhere? Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.