Autor |
Beitrag |
Lepheus
Hält's aus hier
Beiträge: 11
|
Verfasst: So 21.12.14 23:14
Hallo Zusammen,
ich bin gerade an einem kleinen Programm dran, dass sich um Messreihen etc kümmert und diese in Diagrammen darstellt. Habe eine MainForm, in dem die Steuerung, Einlesen etc abläuft und ein 2.Form in dem die Diagramme gezeichnet werden und mit Hilfe der ScreenCapture-Technik ausgedruckt werden kann.
Nun möchte ich im MainForm einen Druck Button implantieren, der automatisch das 2.Form aufruft, die Diagramme erzeugt und den Druckauftrag startet und dann das 2.Form wieder schließt, ohne jegliche Interaktion vom Benutzer.
Habe schon verschiedene Wege probiert über OpenEvent, ShowEvent etc.
Auch habe ich versucht die Form mittels Show Befehl zu öffnen und anschließend aus dem MainForm die Funktion im 2.Form aufzurufen, die die Befehle nach und nach abarbeitet. Das klappt auch soweit, nur ist auf dem Ausdruck z.B. nur die Rahmen der Textboxen und Panels zusehen ohne Inhalt. Sieht aus als ob die Initialisierung des Forms noch nicht fertig sei. Habe versucht an verschiedenen Stellen eine Verzögerung einzubauen, ohne Erfolg...
Hat vllt jemand eine Idee wie man das umsetzen könnte?
Im Anhang eine PDF Datei die zur Zeit erzeugt wird, wie oben beschrieben.
Danke.
Grüße Lepheus
Einloggen, um Attachments anzusehen!
|
|
C#
      
Beiträge: 561
Erhaltene Danke: 65
Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
|
Verfasst: Mo 22.12.14 00:04
Hallo und
wie werden denn die Daten in Form2 gleaden? Könntest du vll die Form2 persistent machen? Also statt sie immer wieder zu schließen und neu zu öffnen, könnte man sie auch verstecken und sichtbar machen. Dann kannst du beim Drucken einfach die Form2 sichtbar machen, einen Screenshot machen und anschließend die Form2 wieder verstecken. Dann würden die Daten ja nach wie vor in den TextBoxen stehen und du hättest keine Ladezeiten.
_________________ Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 00:20
Hallo,
danke für deine Antwort
Vllt. zum Verständnis ein bisschen Hintergrundwissen zur Anwendung an sich. Dort gibt es eine Liste mit Messwerten, die durch das Einlesen einer CSV Datei erstellt wird im Hautprogramm. Nun wird mit einem Button Klick in Form1 (MainForm) das Form 2 aufgerufen, in dem dann 3 Graphen gezeichnet werden und mit Daten aus der Liste gefüllt werden. Das kann aber natürlich erst gemacht werden wenn die Daten eingelesen wurden aus der CSV Datei.
Das heißt ich soll einfach mal versuchen beim Laden der CSV Datei das Diagramm zu erzeugen bzw. die 2.Form und diese dann aber zu verstecken?
Problem daran könnte sein, das auch mehrere Messreihen eingelesen werden können, und für jede Messreihe gibt es unterschiedliche Diagramme dann. Diese sollen eigentlich generiert werden sobald die Messreihe markiert wird im MainForm.
Habe auch schon versucht im MainForm bei einem Button Klick die 2.Form zu erzeugen und direkt dahinter den Druck Befehl zu senden:
C#-Quelltext 1: 2: 3:
| Form2 diagrammforumlar = new Form2(); diagrammforumlar.Show(); diagrammforumlar.Drucken(); |
EDIT: Habe es gerade versucht das Formular bereits zu Beginn der MainForm zu erzeugen und zu verstecken.
Durch einen Button Klick wollte ich es sichtbar machen und anschließend "Drucken", leider wieder nur die Boxen ohne Inhalt, der Inhalt erscheint erst dann wenn der PrintDialog erscheint.
Folgenden Code habe ich im Button hinterlegt:
C#-Quelltext 1: 2:
| diagrammforumlar.Visible = true; diagrammforumlar.Drucken(); |
Moderiert von Th69: C#-Tags hinzugefügt
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Mo 22.12.14 00:46
Meiner Meinung nach verdient das Darstellen der Daten eine eigene Methode neben dem Laden der Form selber, die dann auch gesondert aufgerufen wird.
Wenn du also eine Methode dafür schreibst, welche die benötigten Daten entgegen nimmt, dann kannst du die entweder vor oder nach dem Show aufrufen.
In dieser Methode regelst du dann die ganze Darstellung der Daten und wenn du sie aufrufst, dann kannst du dir sicher sein, das nach dem Ausführen auch alles richtig dargestellt wird. Wenn nicht, dann weißt du, wo der Fehler liegt. ^^
Warum die Daten nicht angezeigt werden, das können wir so nicht genau sagen, sondern nur vermuten.
Entweder die Daten werden asynchron geladen und da erst das Drucken tatsächlichen Zugriff auf die fertig geladenen Daten in der Form benötigt, wird da dann auch auf die Visualisierung gerwartet.
Oder du nutzt irgendwo IEnumerable und iterierst nicht durch das fertige IEnumerable-Objekt. Ich habe mal den Fehler gemacht, irgendwo in einer LINQ-Funktion eine Methode unter zu bringen, die dann tatsächlich eine Funktion ausführt, allerdings ohne am Ende ein ToList, ToArray, oder etwas vergleichbares aufzurufen. Das Ergebnis war ein IEnumerable-Objekt, das noch nicht einmal das erste Element geladen und damit auch keine Funktion ausgeführt hatte. Geholfen hat dann ein ToList, was ja alle Elemente einzeln lädt und in eine Liste ablegt.
Wenn das nicht passt, dann hilft nur noch der genaue Code, wie die Daten dargestellt werden.
PS:
Das Verstecken und wieder anzeigen kannst du gerne machen, das bringt etwas, wenn das Rendern und Laden der Form selber viel Zeit benötigt. Wenn aber das Darstellen der Daten (was keine Aufgabe des Konstruktors ist) viel Zeit benötigt, dann bringt das nicht viel, da das ka immer wieder mit neuen Daten geschehen soll.
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 01:04
Vielen Dank für deine Antwort.
Anbei mal der Code der Form2. Wie würdest du diese denn umschreiben und anschließend aufrufen?
Ist es vllt. möglich mit einem "Trick" die Visualisierung vorher schon zu erzwingen? z.B. durch eine Pseudo Druck Aktion oder ähnliches?
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: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167:
| public partial class Form2: Form { ScreenCapture capScreen = new ScreenCapture();
public Form2() { InitializeComponent(); Diagramm_Fuellen(); Daten_Fuellen(); }
public void Start() {
PDF_erstellen(); Close(); }
public void Daten_Fuellen() { Text1.Text = "Demo"; Text2.Text = "Demo"; }
public void Diagramm_Fuellen() { Chart1.Series.Clear(); Chart2.Series.Clear(); Chart3.Series.Clear();
Series eins = new Series("1"); Series zwei = new Series("2"); Series drei = new Series("3");
eins.ChartType = SeriesChartType.Line; zwei.ChartType = SeriesChartType.Line; drei.ChartType = SeriesChartType.Line;
for (int a = 0; a < 10; a++) { double speed = a; double weg = a; eins.Points.AddXY(weg, speed); }
for (int a = 0; a < 10; a++) { double force = a; double weg = a; zwei.Points.AddXY(weg, force); }
for (int a = 0; a < 10; a++) { double temp = a; double weg = a; drei.Points.AddXY(weg, temp); }
Chart1.ChartAreas[0].AxisX.RoundAxisValues(); Chart2.ChartAreas[0].AxisX.RoundAxisValues(); Chart3.ChartAreas[0].AxisX.RoundAxisValues();
Chart1.ChartAreas[0].AxisX.Minimum = 0; Chart2.ChartAreas[0].AxisX.Minimum = 0; Chart3.ChartAreas[0].AxisX.Minimum = 0;
eins.Color = Color.Blue; zwei.Color = Color.DarkGreen; drei.Color = Color.Red;
Chart1.Series.Add(eins); Chart2.Series.Add(zwei); Chart3.Series.Add(drei); }
private void captureScreen() { try { capScreen.CaptureAndSave(@MainForm.pfaddatei, CaptureMode.Window, ImageFormat.Png); } catch (Exception e) { MessageBox.Show(e.Message.ToString()); } }
private void PDF_erstellen() { captureScreen();
PdfDocument doc = new PdfDocument(); PdfPage oPage = new PdfPage();
doc.Pages.Add(oPage); XGraphics xgr = XGraphics.FromPdfPage(oPage); XImage img = XImage.FromFile(@MainForm.pfaddatei); xgr.DrawImage(img, 0, 0);
saveFileDialog.Filter = ("PDF File|*.pdf"); DialogResult btnSave = saveFileDialog.ShowDialog(); if (btnSave.Equals(DialogResult.OK)) { doc.Save(saveFileDialog.FileName); doc.Close(); } img.Dispose();
if (System.IO.File.Exists(@MainForm.pfaddatei)) { System.IO.File.Delete(@MainForm.pfaddatei); } }
public void BildDrucken(string filename, ImageFormat format, Image image) { format = format ?? ImageFormat.Png; image.Save(MainForm.filenameneu, format);
PrintDocument doc = new PrintDocument(); doc.PrintPage += this.Doc_PrintPage;
PrintDialog dlgSettings = new PrintDialog(); dlgSettings.Document = doc;
if (dlgSettings.ShowDialog() == DialogResult.OK) { doc.Print(); } doc.Dispose(); image.Dispose();
}
private void Doc_PrintPage(object sender, PrintPageEventArgs e) { e.Graphics.DrawImageUnscaled(Image.FromFile(@MainForm.filenameneu), 4, 4); }
public Bitmap BildZuschneiden(Bitmap bitmap, int cropX, int cropY, int cropWidth, int cropHeight) { Rectangle rect = new Rectangle(cropX, cropY, cropWidth, cropHeight); Bitmap cropped = bitmap.Clone(rect, bitmap.PixelFormat); return cropped; }
}
} |
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Mo 22.12.14 01:15
Ich kann jetzt so auf die Schnelle nicht sagen, woran es liegt, dass nichts angezeigt wird, aber auf jeden Fall würde ich die Methoden Diagramm_Fuellen und Daten_Fuellen in eine eigene Methode auslagern und die gesondert aufrufen.
|
|
C#
      
Beiträge: 561
Erhaltene Danke: 65
Windows 10, Kubuntu, Android
Visual Studio 2017, C#, C++/CLI, C++/CX, C++, F#, R, Python
|
Verfasst: Mo 22.12.14 02:05
Das mit dem Verstecken der Form war eigentlich auch nur zum Testen gedacht, ob vielleicht doch lange (asynchrone) Ladezeiten entstehen. Du könntest auch mal die TextBoxen der Form2 mit Standardwerten füllen und diese dann drucken. Versuche einfach mal keine CSV-Datei zu laden und die ganzen TextBoxen im Konstruktor mit Werten zu füllen (aber erst nach dem Aufruf von InitializeComponent()). Anschließend druckst du es. Mal sehen, ob dann auch noch alle Felder leer sind.
PS:
Da dein Bild (der Screenshot) nur temporär genutzt wird, solltest du es im RAM halten, und nicht auf der Festplatte zwischenspeichern. Erstelle einfach eine Variable, die dein Screenshot beinhaltet.
PPS:
Bei public void BildDrucken(string filename, ImageFormat format, Image image) solltest du am Ende das Bild NICHT freigeben, also kein image.Dispose();. Da das Bild image als Argument an die Methode weitergereicht wird, könnte man es nach dem Aufrufen von BildDrucken(..) nicht mehr verwenden. Auch außerhalb der Form2 nicht.
_________________ Der längste Typ-Name im .NET-Framework ist: ListViewVirtualItemsSelectionRangeChangedEventHandler
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 10:13
@C#: Danke für deine Antwort.
Habe bereits versucht mit "Demo" Daten das Formular zufüllen, leider kommt es zum selben Ergebnis:
C#-Quelltext 1: 2:
| InitializeComponent(); DemoDaten(); |
zu PS: Welchen Typ muss die Variable haben? Einfach Image? Danke für den Tip, werde es testen.
zu PPS: Das Bild sollte Form2 auch nicht verwenden, das dient nur zum Ausdrucken.
Moderiert von Th69: C#-Tags hinzugefügt
|
|
Th69
      

Beiträge: 4795
Erhaltene Danke: 1059
Win10
C#, C++ (VS 2017/19/22)
|
Verfasst: Mo 22.12.14 10:57
Hallo Lepheus
einen Screenshot kann man nur erstellen, wenn das Formular auch schon dargestellt wird. Beim Aufruf des Konstruktors ist dies jedoch noch nicht der Fall, sondern erst wenn die Methode Show bzw. ShowDialog aufgerufen wurde.
Um darauf zu reagieren, gibt es das Form.Shown-Ereignis.
Abonniere also dieses Ereignis und probiere es dann mal.
Es kann jedoch auch hier sein, daß noch nichts zu sehen ist, da das Fenster ja ersteinmal dargestellt werden muß (per Paint-Ereignis).
Dann wäre eine weitere Möglichkeit, einen Timer zu benutzen, der im Shown-Ereignis gestartet wird und z.B. nach 1 oder 2 Sekunden den Screenshot durchführt.
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 11:47
@Th69: Danke für deine Antwort
Wo würdest du das Ereignis abonnieren?
Direkt in der Funktion in dem die Form aufgerufen wurde oder in der Form selbst (im Konstruktor)?
EDIT: Habe gerade beide Varianten versucht, abgesehen davon das eine Meldung "zu wenig Arbeitsspeicher"  kommt, sieht man das Formular mit den leeren Textboxen, also ohne Inhalt, genau so lange wie der Timer eingestellt ist, und danach baut es sich erst komplett auf, das heißt nach dem der Screenshot gemacht wurde :-/
EDIT2: Auch mittels Paint-Event habe ich es versucht, nur diese Event wird nicht aufgerufen, egal was ich mache.
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Mo 22.12.14 12:36
Der Konstruktor ist nur zu initialisieren des Objektes da.
Daher schrieb ich, dass die Methode gesondert aufgerufen werden kann.
C#-Quelltext 1: 2: 3: 4: 5:
| var myForm = new MyForm(); myForm.Show(); myForm.DisplayData(GetMyData()); myForm.Print(); myForm.Close(); |
oder
C#-Quelltext 1: 2: 3: 4: 5:
| var myForm = new MyForm(); myForm.Show(); myForm.Shown += (sender, e) => myForm.DisplayData(GetMyData()); myForm.Print(); myForm.Close(); |
Wenn auch Warten nichts nutzt, dann liegt es vielleicht daran, dass die GUI so lange blockiert?
Ein Event wird immer im selben Thread ausgeführt, wie der Aufrufer, das heißt, es könnte sein, dass aus irgendeinem Grund das Darstellen blockiert wird.
Ist nur eine Idee, aber probiere mal das:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| var myForm = new MyForm(); myForm.Show(); myForm.Shown += async (sender, e) => { await Task.Delay(1000); myForm.DisplayData(GetMyData()); }; myForm.Print(); myForm.Close(); |
Damit würde diese Methode vom Event asynchron aufgerufen werden, also so lange "beiseite" gelegt werden, bis die Sekunde vergangen ist.
Danach holt sich der EventHandler die Methode zurück und macht da weiter, wo er aufgehört hat.
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 12:45
Vielen Dank für deine ausführliche Antwort.
Was genau ist bei dir die Funktion DisplayData und GetMyData? Wären dies meine Funktionen Diagramm_Fuellen und Daten_Fuellen?
Des Weiteren meckert der Compiler bei mir über "sender, e", diese kennt er nicht. Habe bereits mit object und EventArgs probiert, ohne Erfolg.
|
|
Palladin007
      
Beiträge: 1282
Erhaltene Danke: 182
Windows 11 x64 Pro
C# (Visual Studio Preview)
|
Verfasst: Mo 22.12.14 13:50
Das sind die Methoden, die die Daten in jedes einzelne Feld schreiben (DisplayData) und die Daten von irgendwo auslesen (GetMyData).
Wegen dem Fehler:
Kann es sein, dass du irgendetwas unter .NET 4.5 nutzt?
Da gibt es diese Technik mit der asynchronen Programmierung noch nicht.
Dann kannst du das natürlich nicht nutzen.
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 13:53
Ok danke.
Ich nutze ausschließlich .NET 4.5
Den async Befehl erkennt er auch, nach dem ich "using System.Threading.Tasks;" eingebunden hatte.
Nur die Bezeichner "sender" und "e" erkennt er nicht, für was stehen die?
Den EventHandler für das Shown Ereignis fügt man doch so hinzu, oder liege ich da falsch?
C#-Quelltext 1:
| form2.Shown += new EventHandler(form2.DemoDaten); |
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 22.12.14 13:59
Shown ist ein Event mit 2 Parametern und sender und e sind einfach die beliebigen Namen für die beiden Parameter in diesem Lambda Ausdruck. Hier ist egal wie die heißen da die nicht benutzt werden.
Bist du mit diesem Code zufällig bereits in einem Event der seine Parameter sender und e nennt? Dann nimm einfach 2 andere Namen.
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 14:03
VIELEN DANK an euch ALLE, und vor allem an Palladin007.
Dein Tip hat geklappt.
Für alle die es interessiert, hier die Lösung:
Hiermit rufe ich die form2 auf:
C#-Quelltext 1: 2: 3: 4:
| myForm from2 = new myForm(); form2.Show(); form2.DemoDaten(); form2.Shown += new EventHandler(prodruck.Drucken); |
Und hier die Funktionen in Form 2:
C#-Quelltext 1: 2: 3: 4: 5: 6:
| public async void Drucken(object sender, EventArgs e) { await Task.Delay(500); PDFDrucken(); Close(); } |
|
|
Ralf Jansen
      
Beiträge: 4708
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mo 22.12.14 14:11
Gefühlt ist deine gezeigte Reihenfolge eher ungünstig. Shown wird von Show gefeuert und sollte vorher verdrahten werden sonst besteht die Möglichkeit das Shown gefeiert wird bevor dein Shown Handler überhaupt verdrahtet ist. Genauso sollten das Befüllen der Form mit Daten vor dem Aufruf von Show erfolgen. Jetzt sieht es für mich aus als würdest du die ungünstige Reihenfolge dadurch reparieren das du vor dem Drucken mal kurz ein Pause einlegst.
|
|
Lepheus 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 22.12.14 14:14
Nochmals danke für den Tip.
Meinst du es so?
C#-Quelltext 1: 2: 3: 4:
| myForm from2 = new myForm(); form2.DemoDaten(); form2.Shown += new EventHandler(prodruck.Drucken); form2.Show(); |
|
|
|