Windows Forms C++ Questions

Tried to create a Windows Forms App in C++ and just have a few questions.

1. Is there another way to run a loop besides using timer_tick?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct SimConnectRequest {
	int def_ID;
	const char* SimVar;
	const char* SimUnit;
	int req_ID;
	double Value;

};

private: System::Void timer1_Tick_1(System::Object^ sender, System::EventArgs^ e) {


		SimConnect_CallDispatch(hSimConnect, MyDispatchProcRD, NULL);
		
		dataTable1->Rows->Clear();
		for (int i = 2; i < 10; i++) {
			dataTable1->NewRow();
			String^ clistr = gcnew String(SimRec[i].SimVar);
			dataTable1->Rows->Add(i, clistr, (bool)SimRec[i].Value);
			//dataTable1->Rows->Add(i, "LIGHT", (bool)SimRec[i].Value);
		}
}


2. Is there a way to just update a table row without deleting and recreating like I did in the above code?

3. Is there any cleanup code that I need to do for the String^ pointer in the code. Is the coding correct? Don't want any pointer issues.

4. Is the timer tick method also the way to update a Datagridview? I am changing the values of variables and I need to display the updated values in datagridview. My solution was to bind a datasource to datagridview and then modify the datasource in the timer tick. It seems to be working. However as I said, I am clearing all the rows and rewriting them. There must be a better way.

Thanks,
Chris
Last edited on
This is a lonely post. There must not be a lot of Windows Forms Coders here. Anyway I have figured out some of the answers for anybody going down this road.

1. If you need to override the Windows Message handler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected: virtual void WndProc(Message% m) override {
				// Listen for operating system messages 
				switch (m.Msg)
				{
				case WM_ACTIVATEAPP:
				{
					// Notify the form that this message was received. 
					// Application is activated or deactivated, 
					// based upon the WParam parameter.
					appActive = (((int)m.WParam != 0));

					// Invalidate to get new text painted.
					this->Invalidate();
					

					break;
				}
				case WM_USER_SIMCONNECT:
				{   
					SimConnect_CallDispatch(hSimConnect, MyDispatchProcRD, NULL);
					break;
				}
				}
				
				__super::WndProc(m); // this is the WndProc you are looking for
			


2. To update a datagridview without deleting the contents and writing them over:

1
2
3
4
5
6
7
8
9
10
11
12
DataGridViewRow^ row;
		DataGridViewTextBoxCell^ cell;
		//update values for dataGridView1 - Lights vars
		for (int i = 0; i < dataGridView1->Rows->Count; i++)//Loop all grid rows
		{
			row = dataGridView1->Rows[i];
			cell = (DataGridViewTextBoxCell^)row->Cells["Value"];
			
			cell->Value = 
				SimRec[Convert::ToInt16(row->Cells["column1DataGridViewTextBoxColumn"]->Value)].getdouble(); //Update  displayed value from an array where the first column of the datagridview is the index of the array element.
			
		}


3. Update an array object when the user clicks a boolean checkbox in the datagridview:

1
2
3
4
5
6
7
8
9
10
private: System::Void dataGridView1_CellContentClick(System::Object^ sender, System::Windows::Forms::DataGridViewCellEventArgs^ e) {
	//Find the clicked cell
	DataGridViewCheckBoxCell^ cell =  (DataGridViewCheckBoxCell^)dataGridView1->CurrentCell;
	//Flip the bool
	cell->Value = cell->Value == nullptr || !((bool)cell->Value);
	//Update the array
	SimRec[Convert::ToInt16(dataGridView1->CurrentRow->Cells["column1DataGridViewTextBoxColumn"]->Value)].active =
		Convert::ToBoolean(dataGridView1->CurrentRow->Cells["column3DataGridViewCheckBoxColumn"]->Value);
	    dataGridView1->RefreshEdit();
}


4. Process button clicks on a datagridview button column:

1
2
3
4
5
6
7
8
9
   //Process button clicks on Lights Events tab
private: System::Void dataGridView8_CellContentClick(System::Object^ sender, System::Windows::Forms::DataGridViewCellEventArgs^ e) {
	//Find the clicked cell
	DataGridViewButtonCell^ cell = (DataGridViewButtonCell^)dataGridView8->CurrentCell;
	                     
	SimEvent[Convert::ToInt16(dataGridView8->CurrentRow->Cells["dataGridViewTextBoxColumn6"]->Value)].fire(); // Calls an array object's internal procedure
	
    dataGridView8->RefreshEdit();
}


5. Read from the Serial port ( this runs on a separate thread automatically ) and then use Invoke to send the data to the main GUI for writing.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
private: System::Void serialPort1_DataReceived(System::Object^ sender, System::IO::Ports::SerialDataReceivedEventArgs^ e) {
	System::IO::Ports::SerialPort^ sp = (System::IO::Ports::SerialPort^)sender;
	
	
	System::String^ data = serialPort1->ReadExisting();
	
	UpdateTextBox(data);

}

private:  delegate void SafeCallDelegate(System::String^ text);

public: void UpdateTextBox(System::String ^text) {
		   if (this->InvokeRequired)
		   {
			  
			   SafeCallDelegate^ d = gcnew SafeCallDelegate(this, &Form1::UpdateTextBox);
			   Object^ Args = { text };

			   this->Invoke(d,Args);
			   return;
			   
			   
			   
		   } 
			   textBox3->Text = text;
		     
		  

}


6. Having trouble building a byte buffer the Serialport.Write will accept as an argument. That is because std::array is conflicting with cli:array and cli:array is the argument type that is required by Serialport.Write.

1
2
3
4
uint16_t data=25;

cli::array<Byte>^ mybytes = { data & 0xff, data >> 8 };
serialPort1->Write(mybytes, 0, 2);


Chris
Last edited on
Registered users can post here. Sign in or register to post.