none
mettre en oeuvre le backgroundWorker de manière enchainée RRS feed

  • Question

  • Mon besoin est de voir le progrès du document pendant qu'il est traité: ça peut prendre plusieurs dizaines de minutes pour un gros document et c'est pourquoi j'ai besoin d'une progress bar.

    Ce problème n'est pas bloquant pour l'instant car je n'ai que des documents qui sont traités en quelques secondes.
    Mais je vais m'attaquer à des plus gros documents à partir de la visite chez un constructeur automobile Lundi prochain.

    je voudrais savoir comment passer les éléments de mesure de mon programme dans la progressBar

    je suppose que je dois passer le nombre dans le backgroundWorker

    J'ai donc mis dans mon code après avoir calculé le pourcentage de progression l'instruction

    J'ai suivi l'exemple donné sur msdn et je ne vois pas ce qui change dans mon exemple.

    je commence à mettre mon code:

    erc CWManager::StartDocAnalysis( System::ComponentModel::BackgroundWorker^  backgroundWorker1, long ulNbWord, bool bNewDoc)
    		{				
    			CBloc* pBloc;
    			size_t iSize;
    			nParagraph = 0;
    			erc ulTotalNbWords = 0;
    			Word::Paragraphs^ objParagraphs = objDocument->Paragraphs;
    			// il faut swapper les fichiers de backup
    			bool bStatus = CopyFile( (LPCTSTR)sLogFile.c_str(), (LPCTSTR)sSavedLogFile.c_str(), false);
    			int iStatus = remove( sLogFile.c_str());
    			for each( Word::Paragraph^ objParagraph in objParagraphs)
    			{
    				System::String^ wsText = objParagraph->default->default;
    				// Récupérer les informations de Layout
    				// Word::Paragraph::Format::ParagraphFormat^ Format = objParagraph->Format->ParagraphFormat;
    				Object^ Style = objParagraph->Style;
    				const wchar_t* chars = (const wchar_t*)(Marshal::StringToHGlobalUni( wsText)).ToPointer();
    				pBloc = new CBloc;
    				pBloc->wsBlocText.append( chars);
    				Marshal::FreeHGlobal(IntPtr((void*)chars));
    
    				//pour chaque mot du paragraph on enregistre le Layout dans la list Elements avec le mot correspondant.
    				// CSchedulerGlobal::AnalyseBlocText(CBloc* pBloc)
    				// appeler SchedulerGlobal pour traiter le paragraph.
    				iSize = pBloc->wsBlocText.size();
    				if( iSize > 2)
    					ulTotalNbWords = objSchedulerGlobal.AnalyseBlocText( pBloc, ulTotalNbWords, bNewDoc);
    				// il faut appeler le backgroundWorker1_ProgressChanged( System::Object^ sender, ProgressChangedEventArgs^ e)
    				// il faut appeler le backgroundWorker1_ProgressChanged( System::Object^ sender, ProgressChangedEventArgs^ e)
    				erc ProgressPercentage = 100 * ulTotalNbWords / ulNbWord;
    				// e->ProgressPercentage = ProgressPercentage;
    				// void MainMenue::backgroundWorker1_ProgressChanged( System::Object^ sender, ProgressChangedEventArgs^ e)
    				// backgroundWorker1->RunWorkerAsync( numberToCompute );
    				// worker->ReportProgress( percentComplete ); 
    				backgroundWorker1->ReportProgress( ProgressPercentage);
    			}
    			CloseDocument();
    			return( 0);
    		}

    Ce qui convient au compilateur mais j'ai régulièrement le message d'erreur le backgroudWordker n'est pas disponible lors de son premier appel:

    Informations supplémentaires : OperationCompleted a déjà été appelé pour cette opération. D'autres tentatives d'appel ne seraient pas conformes.

    je n'ai qu'un backgroundWorker Je vous met ci dessous le code correspondant

    void MainMenue::InitializeProgressBar()
    	{
    		Shown += gcnew EventHandler(  this, &MainMenue::Form1_Shown);
    		// To report progress from the background worker we need to set this property
    		backgroundWorker1->WorkerReportsProgress = true;
    		// This event will be raised when we call ReportProgress
    		backgroundWorker1->RunWorkerCompleted += gcnew RunWorkerCompletedEventHandler( this, &MainMenue::backgroundWorker1_RunWorkerCompleted );
     		backgroundWorker1->ProgressChanged += gcnew ProgressChangedEventHandler( this, &MainMenue::backgroundWorker1_ProgressChanged);
    		backgroundWorker1->DoWork += gcnew DoWorkEventHandler( this, &MainMenue::backgroundWorker1_DoWork );
    	}
    
    	void MainMenue::Form1_Shown( System::Object^ sender, System::EventArgs^ e)
    	{
    		// Start the background worker
    		progressBar1->Visible = false;
    	}
    	
    	// Back on the 'UI' thread so we can update the progress bar
    	void MainMenue::backgroundWorker1_ProgressChanged( System::Object^ sender, ProgressChangedEventArgs^ e)
    	{
    		// The progress percentage is a property of e
    		progressBar1->Value = e->ProgressPercentage;
    	}
    
    	System::Void MainMenue::backgroundWorker1_DoWork(System::Object^  sender, System::ComponentModel::DoWorkEventArgs^  e)
    	{
    		// The progress percentage is a property of e
    		// This event handler is where the actual, 
    		// potentially time-consuming work is done. 
      
    		// Get the BackgroundWorker that raised this event.
    		BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
    		// Assign the result of the computation 
    		// to the Result property of the DoWorkEventArgs 
    		// object. This is will be available to the  
    		// RunWorkerCompleted eventhandler.
    		e->Result = ComputeAdvance( safe_cast<Int32>(e->Argument), worker, e );
       }
    	
    	
    	
    	// This event handler deals with the results of the 
    	// background operation. 
    	void MainMenue::backgroundWorker1_RunWorkerCompleted( Object^ /*sender*/, RunWorkerCompletedEventArgs^ e )
    	{
          /*
    		// First, handle the case where an exception was thrown. 
          if ( e->Error != nullptr )
          {
             MessageBox::Show( e->Error->Message );
          }
          else 
          if ( e->Cancelled )
          {
             // Next, handle the case where the user cancelled  
             // the operation. 
             // Note that due to a race condition in  
             // the DoWork event handler, the Cancelled 
             // flag may not have been set, even though 
             // CancelAsync was called.
             ResultLabel->Text = "Cancelled";
          }
          else
          {
             // Finally, handle the case where the operation  
             // succeeded.
             ResultLabel->Text = e->Result->ToString();
          }
    	  */
       }
    
       // This is the method that does the actual work. For this 
       // example, it computes a Fibonacci number and 
       // reports progress as it does its work. 
       long MainMenue::ComputeAdvance( int n, BackgroundWorker^ worker, DoWorkEventArgs ^ e )
       {
          // The parameter n must be >= 0 and <= 91. 
          // Fib(n), with n > 91, overflows a long. 
          if ( (n < 0) || (n > 91) )
          {
             throw gcnew ArgumentException( "value must be >= 0 and <= 91","n" );
          }
    
          long result = 0;
    
          // Abort the operation if the user has cancelled. 
          // Note that a call to CancelAsync may have set  
          // CancellationPending to true just after the 
          // last invocation of this method exits, so this  
          // code will not have the opportunity to set the  
          // DoWorkEventArgs.Cancel flag to true. This means 
          // that RunWorkerCompletedEventArgs.Cancelled will 
          // not be set to true in your RunWorkerCompleted 
          // event handler. This is a race condition. 
          if ( worker->CancellationPending )
          {
             e->Cancel = true;
          }
          else
          {
             if ( n < 2 )
             {
                result = 1;
             }
             else
             {
                result = ComputeAdvance( n - 1, worker, e ) + ComputeAdvance( n - 2, worker, e );
             }
    
             // Report progress as a percentage of the total task. 
             int percentComplete = (int)((float)n / (float)numberToCompute * 100);
             if ( percentComplete > highestPercentageReached )
             {
                highestPercentageReached = percentComplete;
                worker->ReportProgress( percentComplete );
             }
          }
    
          return result;
       }

    et l'include correspondant

    public ref class MainMenue : public System::Windows::Forms::Form
    	{
    	public:
    		MainMenue::MainMenue(void);
    		System::ComponentModel::BackgroundWorker^  backgroundWorker1;
    		SpecificationLoader::CWManager^ objWordManager;
    
    	protected:
    		/// Nettoyage des ressources utilisées.
    		MainMenue::~MainMenue();
    
    	private:
    		int numberToCompute;
    		int highestPercentageReached;
    		System::Windows::Forms::MenuStrip^  menuStrip1;
    		System::Windows::Forms::ToolStripMenuItem^  filesToolStripMenuItem;
    		System::Windows::Forms::ToolStripMenuItem^  openAFileToolStripMenuItem;
    		System::Windows::Forms::ToolStripMenuItem^  exitToolStripMenuItem;
    		System::Windows::Forms::ToolStripMenuItem^  helpToolStripMenuItem;
    		System::Windows::Forms::Label^  ResultLabel;
    		System::Windows::Forms::ProgressBar^  progressBar1;
    		System::ComponentModel::Container ^components;
    		void MainMenue::InitializeComponent(void);
    		System::Void MainMenue::openAFileToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e);
    		System::Void MainMenue::exitToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e);
    		System::Void MainMenue::helpToolStripMenuItem_Click(System::Object^  sender, System::EventArgs^  e);
    		void MainMenue::InitializeProgressBar();
    		void MainMenue::Form1_Shown( System::Object^ sender, System::EventArgs^ e);
    		void MainMenue::backgroundWorker1_ProgressChanged( System::Object^ sender, ProgressChangedEventArgs^ e);
    		System::Void MainMenue::backgroundWorker1_DoWork(System::Object^  sender, System::ComponentModel::DoWorkEventArgs^  e);
    		void MainMenue::backgroundWorker1_RunWorkerCompleted( Object^ /*sender*/, RunWorkerCompletedEventArgs^ e );
    		long MainMenue::ComputeAdvance( int n, BackgroundWorker^ worker, DoWorkEventArgs ^ e );
    	
    	};

    ainsi que les déclarations d'initialisation

    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Méthode requise pour la prise en charge du concepteur - ne modifiez pas
    		/// le contenu de cette méthode avec l'éditeur de code.
    		/// </summary>
    		void MainMenue::InitializeComponent(void)
    		{
    			this->menuStrip1 = (gcnew System::Windows::Forms::MenuStrip());
    			this->filesToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
    			this->openAFileToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
    			this->exitToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
    			this->helpToolStripMenuItem = (gcnew System::Windows::Forms::ToolStripMenuItem());
    			this->progressBar1 = (gcnew System::Windows::Forms::ProgressBar());
    			this->backgroundWorker1 = (gcnew System::ComponentModel::BackgroundWorker());
    			this->ResultLabel = (gcnew System::Windows::Forms::Label());
    			this->menuStrip1->SuspendLayout();
    			this->SuspendLayout();
    			// 
    			// menuStrip1
    			// 
    			this->menuStrip1->Items->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(2) {this->filesToolStripMenuItem, 
    				this->helpToolStripMenuItem});
    			this->menuStrip1->Location = System::Drawing::Point(0, 0);
    			this->menuStrip1->Name = L"menuStrip1";
    			this->menuStrip1->Size = System::Drawing::Size(1018, 24);
    			this->menuStrip1->TabIndex = 0;
    			this->menuStrip1->Text = L"menuStrip1";
    			// 
    			// filesToolStripMenuItem
    			// 
    			this->filesToolStripMenuItem->DropDownItems->AddRange(gcnew cli::array< System::Windows::Forms::ToolStripItem^  >(2) {this->openAFileToolStripMenuItem, 
    				this->exitToolStripMenuItem});
    			this->filesToolStripMenuItem->Name = L"filesToolStripMenuItem";
    			this->filesToolStripMenuItem->Size = System::Drawing::Size(40, 20);
    			this->filesToolStripMenuItem->Text = L"Files";
    			// 
    			// openAFileToolStripMenuItem
    			// 
    			this->openAFileToolStripMenuItem->Name = L"openAFileToolStripMenuItem";
    			this->openAFileToolStripMenuItem->Size = System::Drawing::Size(137, 22);
    			this->openAFileToolStripMenuItem->Text = L"Open a file";
    			this->openAFileToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainMenue::openAFileToolStripMenuItem_Click);
    			// 
    			// exitToolStripMenuItem
    			// 
    			this->exitToolStripMenuItem->Name = L"exitToolStripMenuItem";
    			this->exitToolStripMenuItem->Size = System::Drawing::Size(137, 22);
    			this->exitToolStripMenuItem->Text = L"Exit";
    			this->exitToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainMenue::exitToolStripMenuItem_Click);
    			// 
    			// helpToolStripMenuItem
    			// 
    			this->helpToolStripMenuItem->Name = L"helpToolStripMenuItem";
    			this->helpToolStripMenuItem->Size = System::Drawing::Size(40, 20);
    			this->helpToolStripMenuItem->Text = L"Help";
    			this->helpToolStripMenuItem->Click += gcnew System::EventHandler(this, &MainMenue::helpToolStripMenuItem_Click);
    			// 
    			// progressBar1
    			// 
    			this->progressBar1->Location = System::Drawing::Point(35, 216);
    			this->progressBar1->Name = L"progressBar1";
    			this->progressBar1->Size = System::Drawing::Size(909, 23);
    			this->progressBar1->TabIndex = 1;
    			// 
    			// ResultLabel
    			// 
    			this->ResultLabel->AutoSize = true;
    			this->ResultLabel->Location = System::Drawing::Point(32, 445);
    			this->ResultLabel->Name = L"ResultLabel";
    			this->ResultLabel->Size = System::Drawing::Size(50, 13);
    			this->ResultLabel->TabIndex = 2;
    			this->ResultLabel->Text = L"Message";
    			// 
    			// MainMenue
    			// 
    			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
    			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    			this->ClientSize = System::Drawing::Size(1018, 479);
    			this->Controls->Add(this->ResultLabel);
    			this->Controls->Add(this->progressBar1);
    			this->Controls->Add(this->menuStrip1);
    			this->MainMenuStrip = this->menuStrip1;
    			this->Name = L"MainMenue";
    			this->Text = L"MainMenue";
    			this->menuStrip1->ResumeLayout(false);
    			this->menuStrip1->PerformLayout();
    			this->ResumeLayout(false);
    			this->PerformLayout();
    
    		}
    #pragma endregion

    J'ai remplacé la fonction récursive par une fonction provisoire et je cherche à comprendre par ou passe le backgroundWorker.

    J'ai regardé l'objet au débugger et je ne trouve pas de ReportProgress et donc je ne sait pas ce qui se passe.

    J'ai mis un point d’arrêt dans mes méthodes

    System::Void MainMenue::backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e)

    long MainMenue::ComputeAdvance( int n, BackgroundWorker^ worker, DoWorkEventArgs ^ e )

    et je n'y passe pas., et donc je ne sais pas ou ça plante. Mais la méthode StartDocAnalyse est une méthode de haut niveau qui active 100 000 LOC. elle ne me parrait pas être un bon candidat pour le boulot.

    il reste à trouver comment enhaîner les appels au backgroundWorker pour qu'il puisse afficher après chaque paragraphe envoyé l'avance mesurée.


    Jean Noël Martin



    • Modifié JeanNoel53 vendredi 14 décembre 2012 15:50
    vendredi 14 décembre 2012 13:02

Toutes les réponses