Forum: PC-Programmierung C#-Daten in zweitem Fenster parallel anzeigen


von Mark W. (kram) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo,

Ich moechte gerne meine Daten in einem Chart auf einem zweiten Fenster 
zusaetzlich anzeigen. Unten ist der Code, den ich verwende um die Daten 
in den kleinen Charts anzuzeigen, alles in Form 1 und ueber den Timer 
gesteuert. Nun wollte ich mit Klick auf eine Schaltflaeche ein zweites 
Fenster oeffnen, was wieder so einen Chart enthaelt und die gleichen 
Daten in vergroesserter Form anzeigt. Das Fenster kann ich mit einer 
Schaltflaeche oeffnen, jedoch zeigt der Chart dann keinen Daten an. Ich 
bekomme die Verbindung des Charts in Form2 zu den Daten von Form 1 
irgendwie nicht hin. Im Anhang ist noch ein Screenshot vom Code unten.

Ich wuerde mich freuen, wenn jemand mich in die richtige Richtung 
bringen koennte. Momentan will ich es ueber eine Klasse versuchen, 
funktioniert aber bis jetzt noch nicht. Ich weiss nicht, ob das der 
richtige Weg in meinem Fall ist.

1
 private void InputTimer_Tick(object sender, EventArgs e)
2
        {
3
            if (myHidDevice != null)
4
            {
5
              /* Disable timer so we don't get another interrupt until we service this interrupt */
6
                InputTimer.Enabled = false;
7
                /* This CyUSB.DLL method uses the Win32 ReadFile() function to read IN data transferred
8
           to our application from the device */
9
                myHidDevice.ReadInput();
10
        
11
          
12
                /* 5V full scale */
13
                double FS = 5.0;
14
                /* 16 bit resolution */
15
                double Res = 65536;
16
17
                if (CH1CheckBox.Checked)
18
                {
19
                    CH1CheckBox.ForeColor = Color.Green;
20
                    CH1CheckBox.Text = "ON";
21
                
22
                    //Unload the ADC Data for CH1 from the Input Buffer to application variables
23
                    AdcCH1Counts_1 = myHidDevice.Inputs.DataBuf[ADCCH1_Byte1_Position];
24
                    AdcCH1Counts_2 = myHidDevice.Inputs.DataBuf[ADCCH1_Byte2_Position];
25
26
                    //Compose the overall ADC value by shifting and adding the multiple ADC bytes
27
                    double ADCCH1number = ((AdcCH1Counts_1 << 8) + AdcCH1Counts_2);
28
                    /* change ADC values to mV */
29
                    double ADCCH1mvolts = ADCCH1number * FS/Res * 1000;
30
                    
31
                    /* Change ADC mV to String */
32
                    String ADCCH1voltstr = ADCCH1mvolts.ToString("0.0");
33
                    /* Display String in Text Box */
34
                    CH1_mv_Box.Text = ADCCH1voltstr;
35
                    //int ADCCH1numberint = Convert.ToInt32(ADCCH1number);
36
37
                    chart1.Series["CH1"].Points.AddY(ADCCH1mvolts);
38
39
                    chart1.Series["CH1"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
40
41
                    chart1.Series["CH1"].Color = Color.Red;
42
43
                    
44
                }
45
                else
46
                {
47
                    CH1CheckBox.ForeColor = Color.Red;
48
                    CH1CheckBox.Text = "OFF";
49
                }

von nicht"Gast" (Gast)


Lesenswert?

Moin,

irgend wie ist von einer zweiten Form nichts zu sehen in deinem Code.

Du solltest ihn allerding mal überarbeiten, denn du vermischt ziemlich 
wild Darstellung und Daten einsammeln.


Dein Interrupt sollte lediglich die Daten aus dem HID auslesen und eine 
Struktur verpacken. Das Umwandeln und Anzeigen gehört dann in eine 
andere Stelle, die benachrichtigt wird, wenn Daten eintreffen.

Das kann entweder über einen Methodenaufruf direkt erfolgen z.Bsp. als 
letzte Zeile Update(neueDaten) aufrufen oder über ein Event (google 
mal).

Damit löst du prinzipiell erst mal die Abhängigkeit deines "Interrupts" 
von der Darstellung auf.

Dann kannst du einfach die Daten an die Form schieben, die sich dann 
selber darum kümmert, sie anzuzeigen.

Grüße,

von Frank L. (Firma: Flk Consulting UG) (flk)


Lesenswert?

Hallo,

schau mal nach den Themen Datenmodell und PropertyChangeEvent bzw. MVVM.

Beide Formulare auf dem Model registrieren also den PropertyChangeEvent 
abonnieren und gut ist.

Alles andere geht von alleine.

Gruß
Frank

von Mark W. (kram) Benutzerseite


Lesenswert?

Vielen Dank schon mal fuer die Hinweise. Ich habe es noch nicht 
hinbekommen, aber taste mich langsam vorwaerts. Mittlerweile ist auch 
mein ertstes Buch ueber C# eingetroffen.

Hier ist der Code mit dem ich das zweite Fenster erzeuge:
1
private void button1_Click(object sender, EventArgs e)
2
        {
3
            Form2 form2Show = new Form2();
4
            
5
6
            /* 5V full scale */
7
            double FS = 5.0;
8
            /* 16 bit resolution */
9
            double Res = 65536;
10
11
            AdcCH1Counts_1 = myHidDevice.Inputs.DataBuf[ADCCH1_Byte1_Position];
12
            AdcCH1Counts_2 = myHidDevice.Inputs.DataBuf[ADCCH1_Byte2_Position];
13
            double ADCCH1number = ((AdcCH1Counts_1 << 8) + AdcCH1Counts_2);
14
            double ADCCH1mvolts = ADCCH1number * FS / Res * 1000;
15
            String ADCCH1voltstr = ADCCH1mvolts.ToString("0.0");
16
17
            form2Show.setTextBox1(ADCCH1voltstr);
18
            form2Show.setChart1(ADCCH1mvolts);
19
20
            form2Show.Show();
21
        }

In der Textbox kann ich einmalig beim Aufrufen einen Wert vorfinden, das 
wars dann aber.
Ich denke ich muss das Program dahingehen umbauen, dass ich die Werte 
mit einem Timer aus dem Buffer hole, dann die Werte global verfuegbar 
mache und dann mit einem zweiten Timer die Werte in den Diagrammen 
anzeige.

von Peter (Gast)


Lesenswert?

Mark W. schrieb:
> Vielen Dank schon mal fuer die Hinweise. Ich habe es noch nicht
> hinbekommen, aber taste mich langsam vorwaerts. Mittlerweile ist auch
> mein ertstes Buch ueber C# eingetroffen.

Enthält das Buch auch ein Kapitel über SW Architektur und Design 
Pattern?

von Mark W. (kram) Benutzerseite


Lesenswert?

Peter schrieb:
> Mark W. schrieb:
>> Vielen Dank schon mal fuer die Hinweise. Ich habe es noch nicht
>> hinbekommen, aber taste mich langsam vorwaerts. Mittlerweile ist auch
>> mein ertstes Buch ueber C# eingetroffen.
>
> Enthält das Buch auch ein Kapitel über SW Architektur und Design
> Pattern?
Titel ist Visual Studio C# Programming and PC interfacing von John 
Allwork

von Peter (Gast)


Lesenswert?

Du schreibst, dass du in Form2.ChartX die selben Daten anzeigen 
möchtest, wie in Form1.ChartX.
Was mir als Info fehlt ist, ob die Daten in Form2.ChartX live, also 
während einer Messung, angezeigt werden sollen oder nur diejenigen, die 
zum Zeitpunkt der Anzeige von Form2.ChartX vorhanden sind?

Im ersten Fall reicht es, eine Kopie der Daten an Form2 mitzugebeben.
Stuzig macht mich aber die button1_Click(object sender, EventArgs e) 
Methode:

form2Show.setChart1(ADCCH1mvolts);
...
form2Show.Show();

Hier setzt du einen double Wert, den das Chart anzeigen soll, richtig?
Der Code wird genau einmal durchlaufen. Und zwar dann, wenn das 
entsprechende Event ausgelöst wird ('Button wurde gedrückt'). Also wird 
auch das Chart nur diesen einen Wert anzeigen. Dto. gilt für die 
Textbox.

Im zweiten Fall (live Daten) müßte sich deine Form2.ChartX-Klassse als 
Listener bei deiner Datendevice-Klasse anmelden.

Eins noch am Rande:

Mir ist aufgefallen, dass du in der InputTimer_Tick(object sender, 
EventArgs e) Methode weder auf sender, noch auf die EventArgs zugreifst. 
Statt dessen greifst du auf eine Instanz von myHidDevice zu.
Gibt es einen Grund dafür?

Das ist in soweit ungewöhnlich, als dass ich hier erwartet hätte, dass 
die neuen Messdaten entweder in den EventArgs enthalten sind, ober aber 
das sender eine Referenz auf den Erzeuger der Daten ist.
Wer ist hier der sender und was steht in den EventArgs?

von Wolfgang H. (drahtverhau)


Lesenswert?

Hi. Füge deinem Programm ein Dataset hinzu. Im Designer kannst Du die 
gewünschten Tabellen für Daten erstellen. Per timer oder event oder wie 
auch immer befüllst du das dataset. Per databinding zeigst du die 
gewünschten daten im gewünschten Fenster an.
Vorteil: Die daten lassen sich mit einer Zeile code als datei speichern 
und laden. Durch den designer werden alle erfordelichen Funktionen im 
Programm erstellt.

Alle erfordelichen infos gibt es hier: 
http://www.vb-paradise.de/index.php/Thread/94955-die-vier-Views-auf-Video/

(ja.. Das forum heißt so.. Aber alles dort gilt auch für c#).
Gruss

von Mark W. (kram) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ich habe jetzt probiert, eine Klasse als globale Variable zu verwenden, 
funktioniert aber nicht. Kompiliert zwar ohne Fehler, aber im Fenster 2 
werden keine Daten angezeigt.

Den code von Fenster 1 habe ich dahingehend geaendert, dass ich jetzt 
die Daten in eine angelegte Klasse zusaetzlich schreibe, von der ich 
hoffte, dass Fenster 2 davon lesen kann:
1
AdcCH1Counts_1 = myHidDevice.Inputs.DataBuf[ADCCH1_Byte1_Position];
2
                    AdcCH1Counts_2 = myHidDevice.Inputs.DataBuf[ADCCH1_Byte2_Position];
3
4
                    //Compose the overall ADC value by shifting and adding the multiple ADC bytes
5
                    double ADCCH1number = ((AdcCH1Counts_1 << 8) + AdcCH1Counts_2);
6
                    /* change ADC values to mV */
7
                    double ADCCH1mvolts = ADCCH1number * FS/Res * 1000;
8
                    GlobalVar.GlobalValue = ADCCH1mvolts;
9
10
                    /* Change ADC mV to String */
11
                    String ADCCH1voltstr = ADCCH1mvolts.ToString("0.0");
12
                    /* Display String in Text Box */
13
                    CH1_mv_Box.Text = ADCCH1voltstr;
14
                    //int ADCCH1numberint = Convert.ToInt32(ADCCH1number);
15
16
                    chart1.Series["CH1"].Points.AddY(GlobalVar.GlobalValue);
17
18
                    chart1.Series["CH1"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
19
20
                    chart1.Series["CH1"].Color = Color.Red;

Der Code fuer die Klasse sieht so aus:
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Text;
5
using System.Threading.Tasks;
6
7
namespace Voltagelogger
8
{
9
    public static class GlobalVar
10
    {
11
        static double _globalValue;
12
13
        public static double GlobalValue
14
        {
15
            get
16
            {
17
                return _globalValue;
18
            }
19
            set
20
            {
21
                _globalValue = value;
22
            }
23
        }
24
    }
25
}

Und der Code fuer Fenster 2 sieht so aus. Wird auch aufgemacht, chart 
bleibt aber leer. Siehe Anhang. Im Fenster 1 dagegen werden die Daten 
richtig angezeigt, wie weiter oben zu sehen.
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Data;
5
using System.Drawing;
6
using System.Linq;
7
using System.Text;
8
using System.Threading.Tasks;
9
using System.Windows.Forms;
10
11
namespace Voltagelogger
12
{
13
    public partial class Form2 : Form
14
    {
15
        public Form2()
16
        {
17
            InitializeComponent();
18
        }
19
20
        private void timer1_Tick(object sender, EventArgs e)
21
        {
22
            timer1.Enabled = false;
23
24
            chart1.Series["Series1"].Points.AddY(GlobalVar.GlobalValue);
25
26
            chart1.Series["Series1"].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine;
27
28
            chart1.Series["Series1"].Color = Color.Red;
29
30
            timer1.Enabled = true;
31
32
33
        }
34
    }
35
}

Ja, die Daten kommen live von der USB Schnittstelle, Haeufigkeit je nach 
Einstellung des InputTimers in Fenster1, maximal jedoch jede 1ms. 
Spaeter wollte ich das noch aendern, so dass man das im Programm 
einstellen kann.

von ccpphh (Gast)


Lesenswert?

Ich denke du willst auf die Daten deiner Form1 zugreifen. Ist ja in dem 
Fall eine Klasse. Um aus der Form2 heraus auf deine Form1 zugreifen zu 
können, musst du eine "Verbindung" zwischen den Forms aufbauen.

D.h. public Form2() wird zu -> public Form2(Form1 MainForm)...
über dieser Zeile platzierst du nochmal ein Form1 myNewForm.... diesen 
initiierst du wiederum unter deiner Zeile InitializeComponent()...



namespace Voltagelogger
{
    Form1 myNewForm;
    public partial class Form2 : Form
    {
        public Form2(Form1 MainForm)
        {
           myNewForm = this.MainForm;
           InitializeComponent();

        }


in deiner Funktion button1_Click musst du noch deine Form1 mitübergeben 
also so:
   form2Show.Show(this);

dann sollte es funktionieren aminakoyim

von Paul (Gast)


Lesenswert?

Lieber Mark, liest du nur oder verstehst du auch?
Leider hast du bisher keinen der Vorschläge berücksichtigt oder bist auf 
Vorschläge eingegangen.
Dein Code zeugt eher von einem Mangel an Grundverständnis bezüglich 
bestimmter Programmierparadigmen. Und nun kannst du entweder 
verwurschteln und es irgendwie hinbekommen und hoffentlich das Ergebnis 
nie an einen Kunden verkaufen oder aber du gehst mal einen Schritt 
zurück, liest ein paar der Vorschläge hier und fragst ggf. nach.
Natürlich könntest du dir auch jemanden suchen, der sich mit dem 
Handwerk des Programmierens auskennt und dir gegen Bares was Wahres 
liefert.

von Mark W. (kram) Benutzerseite


Lesenswert?

Ich programmiere mit C# gerade erstmal 2 Wochen und es ist nur Hobby. 
Bei dem Programm hab ich mich Schritt fuer Schritt von einem bestehendem 
Programm vorgetastet. Nun bin ich an die Grenzen gestossen und werde 
mich erstmal mit den Grundlagen auseinandersetzen. Einiges im 
Programmaufbau von C# ist mir noch nicht so klar. Derzeit habe ich das 
Programm ertmal umgebaut und alles in ein Fenster gelegt, nun sind alle 
8 Kanaele in einem Chart sichtbar, das geht auch erstmal so.

Die Problematik jeden Kanal, der Uebersicht halber, in einem extra 
Fenster anzeigen zu lassen, zusaetzlich zu den kleinen Vorschaufenstern, 
habe ich erstmal ausgegliedert. Wenn ich mein Ziel erreiche, will ich es 
auch verstanden haben. Ich habe mir dazu ein Minimal Programm 
geschrieben und will damit erstmal nur die Sache mit dem zweiten Fenster 
machen. Wenn ich Erfolge oder Fragen diesbezueglich habe, dann lass ich 
es Euch wissen.

von Wolfgang H. (drahtverhau)


Lesenswert?

Moin... Hab dir den link auf die videos gepostet... Wenn du sowas machst 
dann mach es doch gleich richtig... Ohne gewuschtel per 
handgeschriebener Klassen sondern gleich objektorientiert...

von Mark W. (kram) Benutzerseite


Lesenswert?

Hallo Wolfgang,

habe mir den link angesehen und abgespeichert. Ich galube nicht, dass 
ich jetzt schon so eine komplexe Loesung mit Datenbanken machen will. 
Ich schaue mir die Videos mal bei Gelegenheit an, scheint mir aber 
Overkill zu sein fuer meine Anwendung.

von Wolfgang H. (drahtverhau)


Lesenswert?

Hallo Mark!

In den Videos geht es eben genau nicht um Datenbanken. Es geht um 
LocalDB. Darum dass Du deine Gesammelten Werte vernünftig in eine Liste 
eintragen, filtern usw. kannst. Dass das ganze per Designer gemacht 
werden kann nur durch erstellung entsprechender Tabellen und vor allem 
dass alles Objektorientiert gehandhabt wird.

So wie dort erklärt wird ist es z. b. schlecht mit Strings als 
Übergabeparameter zu arbeiten, da diese erstens geparst werden müssen 
und zweiten Fehler passieren können. Per LocalDB wird der 
objektorientierte Ansatz inklusive Intelisense ermöglicht. Es ist dann 
nur mehr notwendig das Databinding zu setzen und die gwünschten Daten 
anzeigen zu lassen.

Und nicht vom Namen des Forums abschrecken lassen. Alles was dort gesagt 
wird lässt sich genauso auch in C# machen. Es werden auch genauso C# 
Fragen beantwortet sollten welche auftreten.

Kanns Dir nur empfehlen es gleich richtig zu machen und alle Vorteile 
des Studios zu nutzen.

Soll natürlich nicht heissen dass meine Vorredner keine Ahnung hätten...

Gruß

von Mark W. (kram) Benutzerseite


Lesenswert?

Nachtrag:
hier ist zu sehen, wie ich es haben moechte. Nur eben so einfach wie ich 
es im ersten Fenster habe, Daten anzeigen mit nur 3 Zeilen Code und 
einfach verstaendlich.
Ich habe mir das Projekt angesehen, scheint mir etwas zu umstaendlich 
fuer den Moment zu sein.

https://www.youtube.com/watch?v=g_C-L97l_XI

von John (Gast)


Lesenswert?

Wolfgang H. schrieb:
> ... Wenn du sowas machst
> dann mach es doch gleich richtig... Ohne gewuschtel per
> handgeschriebener Klassen sondern gleich objektorientiert...

Wut?

von Wolfgang H. (drahtverhau)


Lesenswert?

nein!!! Aufgrund von Erfahrung wollte ich nur drauf hinweisen es gleich 
so zu machen. Spart eine menge arbeit.

Hab ja geschrieben dass trotzdem alles andere wahrscheinlich nicht 
verkehrt ist.

von Herr Flitzpiep (Gast)


Lesenswert?

>>> Ohne gewuschtel per handgeschriebener Klassen sondern gleich
>>> objektorientiert...
>> Wut?
> nein!!!

Meine lieben Forenfreude, vielleicht vermag ich die entstandene 
Konfusion zumindest in Teilen ein wenig abzumildern. Ich will mich 
kurzfassen: Der Herr John wollte sicher nur - vorausgesetzt, das in 
Deutsch fürwahr unglückliche "Wut" lässt sich in diesem Kontext 
tatsächlich geradeweg und ohne Umscheife mit "What" übersetzen, wie es 
ein sogenanntes "urbanes Wörterbuch" vorschlägt, welches ich kürzlich im 
Internetz unter einigem Einsatz aufzustöbern in der Lage war - seiner 
Verwunderung ob der augenscheinlichen Diskrepanz Ausdruck verleihen, 
dass Ihr, Herr Wolfgang, einerseits unumwunden als aufrechter 
Fürsprecher objektorientierter Programmierung, ja, als ihr Held und 
Verteidiger auftretet, was ich als Anhänger derselbigen durchaus zu 
goutieren weiß, andererseits jedoch personaliter konzipierten und 
niedergeschriebenen Klassen - deren Vorhandensein ja gemeinhin gerade 
als eines der innigsten und leidenschaftlichsten Symbole für ebendieses 
Vorgehen gilt - grob ablehnend gegenüberzustehen scheint.

von Wolfgang H. (drahtverhau)


Lesenswert?

Ok...

Es gibt viele wege nach rom... Mein vorschlag war einer unter vielen. 
Denke mal dass das der sinn von einem forum is. Und wie geschrieben mag 
die klassenlösung mit Sicherheit auch ihre vorteile haben... Je nachdem 
was als ziel definiert is vermute ich mal...

von seho85 (Gast)


Lesenswert?

Hey,

was die Vorposter mit richtiger Objektorientierung meinten ist meiner 
Meinung nach folgendes - eine objektorientierte Abstraktion zur Lösung 
deines Problems zu nutzen.

Folgende Idee:

Erstelle eine Klasse LogEntry. Die Klasse beinhaltet einen LogEintrag.
Idee: Konstruktor mit zwei Bytes. Float  Repräsentation werden von den 
beiden Bytes abgeleitet. String Repräsentation von Float.

Erstelle eine Klasse DataLogger (kein Form!), diese beinhaltet eine 
Liste mit LogEntry. In dieser Liste werden die Log Einträge gespeichert.
Idee: Konstruktor bekommt "myHidDevice" übergeben.

DataLogger startet seinen eigenen BackgroundTimer, in dessen Tick er den 
Wert aus "myHidDevice" liest und in seiner Liste ablegt.

In deinem "MainForm" erstellt du dann eine Instanz des DataLogger.

Diese Instanz von DataLogger enthält nun alle deine gemessenen Werte, 
diese Instanz kannst du nun in deinem "HauptWindow" nutzen, oder einfach 
jedem Unterfenster das die Daten verarbeiten soll mitgeben.

Wenn du nun noch DataLogger einen eigenen Event spendierst, den du 
feuerst wenn du im "Tick" einen neuen Messwert gelesen hast, können alle 
Konsumenten des DataLogger darüber benachrichtigt werden das ein neuer 
Wert vorhanden ist. (Hollywood Prinzip)


Gruß,
Sebastian

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.