Zugriff auf Objekte einer Klasse von aussen



  • zur Veranschaulichung habe ich ein kleines Bsp.-Programm erstellt.
    ich habe eine Klasse für ein Messgerät die einen Konstruktor hat und als Parameter den Port als AnsiString erwartet. Nennen wir die Klasse "CMessgeraet1":

    class CMessgeraet1 {
    private:
    	bool connect;
    public:
    	CMessgeraet1(AnsiString rs232);
    	~CMessgeraet1();
    	String Messwert1Ausgeben();
    };
    

    Nun habe ich eine Form "F_HO", die ein Label (L_AnzeigeMesswert1) beinhaltet, dass später den Messwert anzeigen soll. Bei Klick auf das Label öffnet sich ein weiteres Fenster (F_Messgeraet1) mit einer ComboBox (CB_Ports) und einem Button (B_PortOeffnen). In der ComboBox werden alle verfügbaren Ports angezeigt (kommt aus der Registry).

    Da später mehrere Messgeräte betrieben werden habe ich einen Thread erstellt. Über "UpdateCaption()" soll dann der Messwert aktualisiert werden:

    LONGLONG frequenz, alt, neu;
    void __fastcall ThreadMesswerteAusgeben::Execute() 
    {
       QueryPerformanceCounter((LARGE_INTEGER*)&alt);
       while(!Terminated) {
          QueryPerformanceCounter((LARGE_INTEGER*)&neu);
          if ((neu-alt)/(double)frequenz >= 0.1) Synchronize(UpdateCaption);
          Sleep(1);
       }
    }
    
    void __fastcall ThreadMesswerteAusgeben::UpdateCaption() 
    {
       //F_HO->L_AnzeigeMesswert1->Caption = .... ;
    }
    

    Nun zu meinem Problem. Jetzt muss ich das Objekt der Klasse erzeugen. Das habe ich in das KlickEreignis des Buttons B_PortOeffnen implementiert:

    void __fastcall TF_Messgeraet1::B_PortOeffnenClick(TObject *Sender){
       CMessgeraet1* M1 = new CMessgeraet1(CB_Ports->Text);
    }
    

    Wie komme ich nun aus den anderen Forms auf das Objekt M1? Ich möchte ja in der UpdateCaption Methode der Threadklasse auf die Methoden der Klasse CMesswert1 über das Objekt M1 zugreifen, damit ich den Messwert auf der Form F_HO anzeigen lassen kann.

    Ich hoffe das war einigermaßen verständlich. Wäre für Hilfe sehr dankbar.



  • Hallo,

    Speichere doch deine neue CMessgeraet1 Instanz als Membervariable in TF_Messgeraet1.



  • Braunstein schrieb:

    Speichere doch deine neue CMessgeraet1 Instanz als Membervariable in TF_Messgeraet1.

    also direkt als public? also:

    class TF_Messgeraet1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
    	TComboBox *CB_Ports;
    	TButton *B_PortOeffnen;
    private:
    
    public:		// Anwender-Deklarationen
    	__fastcall TF_Messgeraet1(TComponent* Owner);
       CMessgeraet1* M1;
    };
    

    und das Objekt dann in dem Button CB_Ports oder wo am besten erzeugen?
    void __fastcall TF_Messgeraet1::B_PortOeffnenClick(TObject *Sender)

    void __fastcall TF_Messgeraet1::B_PortOeffnenClick(TObject *Sender)
    {
       M1 = new CMessgeraet1(CB_Ports->Text);
    }
    

    nur wie kann ich jetzt auf das Objekt M1 in dem Thread zugreifen?



  • ich nehme mal an, dass ich das Objekt als extern definieren muss. Habe gerade in einem Buch gelesen, dass man Variablen, die in anderen Units verwendet werden sollen, als extern definieren muss. Wie das jetzt bei Objekten einer Klasse funktioniert steht leider nicht dabei.



  • Übergib doch deiner Threadklasse einfach den Zeiger auf deine Messgeräteklasse.

    class ThreadMesswerteAusgeben : public TThread
    {
    .....
    private:
      CMessgeraet1* M1; 
    
    public:
      void SetMessgeraet(CMessgeraet1 *pmg){M1 = pmg;}
    };
    ....
    
    void __fastcall ThreadMesswerteAusgeben::UpdateCaption()
    {
       M1->Irgendwasmachen();
    }
    


  • und das Objekt erzeug ich wo? Der Konstruktor hat ja einen Parameter:

    CMessgeraet1(AnsiString rs232);
    

    Ich würd das
    beim Klick auf B_Port machen, also

    void __fastcall TF_Messgeraet1::B_PortOeffnenClick(TObject *Sender)
    {
       M1 = new CMessgeraet1(CB_Ports->Text);
    }
    

    Wo steht jetzt CMessgeraet1* M1 ? doch eigentlich als Private Member in TF_Messgeraet1 oder? Dann bekomm ich aber immer wieder Fehler:
    [C++ Fehler] ThreadMesswerteAusgeben.h(11): E2303 Typname erwartet



  • Du musst noch die CMessgeraet-Headerdatei in deiner ThreadMesswerteAusgeben -Header Datei includen.

    Ich weiss leider nicht, wo du dein Threadobjekt erzeugst, in deinen Portöffnenklick kannst das erzeugte CMessgeraet Objekt so übegeben:

    void __fastcall TF_Messgeraet1::B_PortOeffnenClick(TObject *Sender){
       CMessgeraet1* M1 = new CMessgeraet1(CB_Ports->Text);
       Thread->SetMessgeraet(M1);
    }
    


  • mein Threadobjekt erzeuge ich in der Hauptoberfläche, da noch andere Geräte dazukommen. Den Spezifizierer extern kann ich nicht verwenden?
    Hab schon alles mögliche ausprobiert, irgendwie will es nicht klappen.



  • Hab das Testprojekt nocheinmal neu angelegt und ein paar Veränderungen vorgenommen:
    Hier meine Messgeräteklasse. Den Messwert bekommt man über eine serielle Schnittstelle:

    //c_Messgeraet.h:
    #include "comclass.h"
    class c_Messgeraet {
    private:
    	bool m_connect;
       comclass m_port;
    public:
    	c_Messgeraet(AnsiString p_port);
    	~c_Messgeraet();
    	AnsiString ErfasseVolumen();
    	bool GetConnect();
    };
    
    //c_Messgeraet.cpp:
    c_Messgeraet::c_Messgeraet(AnsiString p_port) : m_connect(false) {
       m_connect = m_port.OpenComm(p_port.c_str());
       if(m_connect)
       {
          m_port.SetDCB(9600);
          m_port.SetReadTimeouts(100, 10, 10);
       }
       //else ShowMessage("Messgerät nicht verbunden!");
    }
    //---------------------------------------------------------------------------
    c_Messgeraet::~c_Messgeraet() {if(m_connect) m_port.CloseComm();}
    //---------------------------------------------------------------------------
    AnsiString c_Messgeraet::ErfasseVolumen() {
    	char rec[50] = {0};
       unsigned char send[] = {0x16};
       while(m_port.ReceiveData(rec,1)>0); // Buffer leeren
       m_port.SendData(send,1);
       m_port.ReceiveData(rec,50);
       return AnsiString(rec).SubString(4,9).Trim();
    }
    //---------------------------------------------------------------------------
    bool c_Messgeraet::GetConnect(){
    	return m_connect;
    }
    

    hier meine meine Hauptoberfläche mit 2 Buttons (B_ThreadResume, B_ThreadSuspend) und ein Label (L_AnzeigeVolumen), dass den Messwert anzeigen soll:

    //HO.cpp:
    TF_HO *F_HO;
    //---------------------------------------------------------------------------
    __fastcall TF_HO::TF_HO(TComponent* Owner)
    	: TForm(Owner), o_Messwertthread(new c_Messwertthread(true)) {} // hier erzeug ich mein Threadobjekt
    //---------------------------------------------------------------------------
    void __fastcall TF_HO::L_AnzeigeVolumenClick(TObject *Sender) {
       F_Messgeraet->ShowModal();
    }
    //---------------------------------------------------------------------------
    void __fastcall TF_HO::B_ThreadResumeClick(TObject *Sender) {
       o_Messwertthread->Resume();
    }
    //---------------------------------------------------------------------------
    void __fastcall TF_HO::B_ThreadSuspendClick(TObject *Sender) {
    	o_Messwertthread->Suspend();
    }
    
    //HO.h:
    include "c_Messwertthread.h"
    //---------------------------------------------------------------------------
    class TF_HO : public TForm {
    __published:	// Von der IDE verwaltete Komponenten
    	TLabel *L_AnzeigeVolumen;
    	TButton *B_ThreadResume;
    	TButton *B_ThreadSuspend;
    	void __fastcall L_AnzeigeVolumenClick(TObject *Sender);
    	void __fastcall B_ThreadResumeClick(TObject *Sender);
    	void __fastcall B_ThreadSuspendClick(TObject *Sender);
    private:	// Anwender-Deklarationen
    	c_Messwertthread* o_Messwertthread; // Deklaration des Threadobjekts
    public:		// Anwender-Deklarationen
    	__fastcall TF_HO(TComponent* Owner);
    };
    

    Beim Klick auf das Label auf der HO öffnet sich ein 2. Fenster, das 1 Editfeld enthält zur Eingabe des COM-Ports (zB.: COM5) sowie einen Button (B_OpenPort):

    //Messgeraet.h:
    class TF_Messgeraet : public TForm {
    __published:	// Von der IDE verwaltete Komponenten
    	TEdit *E_SerialPort;
    	TButton *B_OpenPort;
    	void __fastcall B_OpenPortClick(TObject *Sender);
    private:
    	c_Messgeraet* o_Messgeraet;
    public:		// Anwender-Deklarationen
    	__fastcall TF_Messgeraet(TComponent* Owner);
    };
    
    //Messgeraet.cpp:
    TF_Messgeraet *F_Messgeraet;
    //---------------------------------------------------------------------------
    __fastcall TF_Messgeraet::TF_Messgeraet(TComponent* Owner)
    	: TForm(Owner), o_Messgeraet(new c_Messgeraet("")) { }
    //---------------------------------------------------------------------------
    void __fastcall TF_Messgeraet::B_OpenPortClick(TObject *Sender) {
       o_Messgeraet = new c_Messgeraet(E_SerialPort->Text);
    }
    

    und schliesslich die Threadklasse die den Messwert aktualisieren soll:

    //c_Messwertthread.h: 
    class c_Messwertthread : public TThread {
    private:
    	LONGLONG frequenz;
       LONGLONG alt;
       LONGLONG neu;
       unsigned int i;
    protected:
    	void __fastcall Execute();
    public:
    	__fastcall c_Messwertthread(bool CreateSuspended);
    	void __fastcall UpdateVCL(void);
    };
    
    //c_Messwertthread.cpp:
    #include "Messgeraet.h"
    //---------------------------------------------------------------------------
    
    __fastcall c_Messwertthread::c_Messwertthread(bool CreateSuspended)
    	: TThread(CreateSuspended), frequenz(0), alt(0), neu(0), i(0) {
       QueryPerformanceFrequency((LARGE_INTEGER*)&frequenz);
       Priority = tpHighest;
    }
    //---------------------------------------------------------------------------
    void __fastcall c_Messwertthread::Execute() {
    	QueryPerformanceCounter((LARGE_INTEGER*)&alt);
       while(!Terminated)
       {
       	if ((neu-alt)/(double)frequenz >= 0.1*i) Synchronize(UpdateVCL);
          Sleep(0);
       }
    }
    //---------------------------------------------------------------------------
    void __fastcall c_Messwertthread::UpdateVCL(void) {}
    

    Genau hier brauch in den Zugriff auf das Objekt o_Messgeraet damit ich auf die Methode ErfasseVolumen() zugreifen kann. Ich hoffe das war nicht zu viel. Ich brauch wie ich denke eine Methode in Messgeraet.cpp (da hab ich ja das Objekt o_Messgeraet erzeugt) die den Zugriff auf das Objekt erlaubt. Wie müsste die aussehen?
    Andere Sache noch: Kann man das so machen das man die Objekte in der Konstruktorliste der Form initialisiert/erzeugt?



  • normal müsst es ja so gehen:

    //in Messgeraet.h / Messgeraet.cpp:
    class TF_Messgeraet : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
    	TEdit *E_SerialPort;
    	TButton *B_OpenPort;
    	void __fastcall B_OpenPortClick(TObject *Sender);
    private:
    	c_Messgeraet* o_Messgeraet;
    public:		// Anwender-Deklarationen
    	__fastcall TF_Messgeraet(TComponent* Owner);
       c_Messgeraet* GetMessgeraet();
    };
    c_Messgeraet* TF_Messgeraet::GetMessgeraet()
    {
    	return o_Messgeraet;
    }
    
    //in c_ThreadMesswerte.cpp:
    void __fastcall c_Messwertthread::UpdateVCL(void)
    {
       F_HO->L_StatusThread->Caption = i++;
       F_HO->L_AnzeigeVolumen->Caption = F_Messgeraet->GetMessgeraet()->ErfasseVolumen();
    }
    

    oder liege ich falsch? so macht man es jedenfalls bei normalen Variablen.



  • und das funktioniert sogar.
    Leider ist das Programm, wenn der Thread läuft etwas hakerich wenn ich die Maus bewege, das Fenster verschiebe oder einen Button drücke. Kann ich das irgendwie beschleunigen?


Anmelden zum Antworten