Hallo zusammen. Ich studiere Eletronik und habe u.A. das Fach
Windowsprogrammierung, welches auf C# beruht und inklusive
Übungsaufgaben ist.
Im Laufe der Übungen hat sich das Folgende (vereinfacht) Ergeben:
Datei main.cs:
1
classHauptklasse{
2
publicstaticvoidMain(){
3
Unterklasseu=newUnterklasse();
4
u.Lauf();
5
}
6
}
Datei unter.cs:
1
classUnterklasse{
2
publicvoidLauf(){
3
stringstr="";
4
Console.WriteLine("Eingabe:");
5
while(str!="beenden"){
6
str=Console.ReadLine();
7
Console.Clear();
8
Console.WriteLine("Eingabe war: "+str);
9
Console.WriteLine("Neue Eingabe:");
10
}
11
}
12
}
Die Aufgabe in der neuen Übung ist nun, die Ausgabe parallel in einer
Windows Forms zu machen. Doch ich bekomme es nicht hin, dass es
ausgegeben wird. Selbst das neue Fenster, was von der Form erstellt
wird, spackt rum. Es wird nichts angezeigt und wenn ich ein anderes
Fenster dort rüberziehe, kommen diese Schlieren, die typisch für
abgestürzte Programme sind. Ich weiß nicht wie ich das machen soll. In
der Aufgabe stand etwas wie: "Ersetzen sie die Methode Lauf durch die
überschriebene OnPaint-Methode der Klasse Form.
Mein Versuch war:
Datei main.cs:
Das ging aber nicht, da er wohl erst die Änderung anzeigt, wenn die
OnPaint-Methode Verlassen wird. Ebenso aus dem gleichen Grund ging
folgendes auch nicht:
Datei unter.cs:
Sofort wenn er in die Methode OnPaint rein geht, wird das Fenster
geleert.
Dann dachte ich mir, ich kann es anders lösen:
Datei main.cs:
1
classHauptklasse{
2
publicstaticvoidMain(){
3
Unterklasseu=newUnterklasse();
4
u.Show();
5
u.Lauf();
6
u.Hide();
7
}
8
}
Datei unter.cs:
1
classUnterklasse:Form{
2
stringstr;
3
publicUnterklasse(){
4
str="";
5
}
6
7
protectedoverridevoidOnPaint(PaintEventArgspea){
8
base.OnPaint(pea);
9
Graphicsgrfx=pea.Graphics;
10
grfx.DrawString(str,Font,Brushes.Black,0,0);
11
}
12
13
publicvoidLauf(){
14
stringstr="";
15
Console.WriteLine("Eingabe:");
16
while(str!="beenden"){
17
str=Console.ReadLine();
18
Console.Clear();
19
Console.WriteLine("Eingabe war: "+str);
20
Console.WriteLine("Neue Eingabe:");
21
str="Eingabe war: "+str+"\nNeue Eingabe:");
22
Invalidate();
23
}
24
}
25
}
Dort dachte ich, dass durch das Invalidate die OnPaint-Methode
aufgerufen wird, doch dies war nicht der Fall.
Kann mir jemand vielleicht einen Tipp geben, wie ich das hinbekommen
kann??
Ich bin langsam am Verzweifeln.
Danke schonmal
Michael
1. In Lauf wird str neu definiert, onpaint kriegt gar nix
2. Du rufst nach invalidate sofort hide auf
3. Du kannst nicht ganz so einfach aus ner konsolen applikation eine
winformsanwendung machen, umgekehrt schneller(aus dem projekt template)
4. Lass mal den konsolenteil aus der form raus und übergeb den string
als property
5. Euer proff verlangt wirres zeug ohne grundlagen
Gl hf
Man sollte in OnPaint() eigentlich nichts anderes tun als Zeichnen.
Und erst recht keine blockierenden Funktionen wie ReadLine() verwenden,
die dafür sorgen das Windows meinen könnte dass das Fenster tot wäre
("Reagiert nicht mehr") weil OnPaint() verdächtig lange braucht.
Invalidate() in OnPaint() ist auch nicht sinnvoll, du erzeugst damit
praktisch eine Endlosschleife.
Bei der zweiten Varianten fehlt außerdem Application.Run()
erst ab .Run() wird die Message-Loop gestartet. Die Message-Loop
verarbeitet Nachrichten die Windows an Fenster der Anwendung sendet und
löst oftmals Ereignisse wie OnPaint() überhaupt erst aus.
Weiterhin merkwürdig ist Konsole und Windows.Forms zu mischen.
Insgesamt riecht das praktisch nach übelster Pfuscherei (also schon die
Aufgabenstellung, wenn die so gemeint ist) ;D
-----
Bei Windows.Forms (wenn man davon absieht dass man dort einfach ne
Textbox nehmen könnte und kein Console.ReadLine() nimmt), würde ich das
persönlich grob eher so machen:
1) KeyPress-Ereignis abfangen und getipptes Zeichen an einen String
anhängen und Invalidate() aufrufen*
2) In OnPaint() einfach nur den String zeichnen
*Newline-Behandlung:
- Zusätzlich in einer bool-Variable merken falls ein Newline eingegeben
wurde
- Beim nächsten KeyPress: Ist die bool-Variable gesetzt, dann erstmal
den String leeren bevor das getippte Zeichen angehangen wird
Sebasrian L. schrieb:> 1. In Lauf wird str neu definiert, onpaint kriegt gar nix> 2. Du rufst nach invalidate sofort hide auf> 3. Du kannst nicht ganz so einfach aus ner konsolen applikation eine> winformsanwendung machen, umgekehrt schneller(aus dem projekt template)> 4. Lass mal den konsolenteil aus der form raus und übergeb den string> als property> 5. Euer proff verlangt wirres zeug ohne grundlagen
Zu 1.: In Lauf wird str (die in der gesamten Klasse Unterklasse bekannt
ist) überschrieben. Wenn OnPaint aufgerufen würde, würde er doch also
auch die Variable str verwenden können!?
Zu 2.: Invalidate rufe ich am Ende der While-Schleife auf. Gedacht hatte
ich mir, dass ich die Eingabe mache, gib den Text in der Konsole auf,
schreibe den anzuzeigenen Text in die str Variable und veranlasse mit
Invalidate das Neuschreiben der Form, was somit die OnPaint-Methode
aufruft, die dann den Text in str ausgibt.
Zu 5.: Denk ich mir auch manchmal. Es soll ein Programm langsam von
Konsolenbetrieb in komplett Windows Forms betrieb geändert werden. Und
diese Übung ist quasi ein Zwischenschritt, wo nur etwas angezeigt werden
kann.
@ bluppdidupp: Deshalb kann ich auch nich so einfach mit Textfeldern die
Eingabe machen. Damit wäre das sicherlich weniger das Problem. Die
Bedienfelder lösen ja auch die Ereignisse aus. OnClick, OnKeyDown usw
usf. Es soll quasi nichts geändert werden, nur dass das, was in der
Konsole steht, auch in der Windows Forms steht.
bluppdidupp schrieb:> Invalidate() in OnPaint() ist auch nicht sinnvoll, du erzeugst damit> praktisch eine Endlosschleife.
Das war auch mein Ziel, nur dachte ich, dass der Text die ganze Zeit da
steht. Dann auf str = "beenden" geprüft und ein Close(); gemacht und ich
hätte dadurch quasi die While-Schleife ersetzt.
bluppdidupp schrieb:> Bei der zweiten Varianten fehlt außerdem Application.Run()> erst ab .Run() wird die Message-Loop gestartet. Die Message-Loop> verarbeitet Nachrichten die Windows an Fenster der Anwendung sendet und> löst oftmals Ereignisse wie OnPaint() überhaupt erst aus.
Das hab ich mir auch schon überlegt, doch wenn ich Application.Run habe,
wo kommt dann mein Console.ReadLine() hin? In die OnPaint-Methode ja
nicht, da dann nicht gezeichnet wird. Unter das Application.Run auch
nicht, da man dort ja erst hinkommt, wenn man die Form per X oder
Close(); beendet hat.
bluppdidupp schrieb:> Bei Windows.Forms (wenn man davon absieht dass man dort einfach ne> Textbox nehmen könnte und kein Console.ReadLine() nimmt), würde ich das> persönlich grob eher so machen:> 1) KeyPress-Ereignis abfangen und getipptes Zeichen an einen String> anhängen und Invalidate() aufrufen*> 2) In OnPaint() einfach nur den String zeichnen>> *Newline-Behandlung:> - Zusätzlich in einer bool-Variable merken falls ein Newline eingegeben> wurde> - Beim nächsten KeyPress: Ist die bool-Variable gesetzt, dann erstmal> den String leeren bevor das getippte Zeichen angehangen wird
Wie gesagt, mit Textfeld oder OnKeyPress-Methode ginge das ganze
warscheinlich deutlich einfacher.
Ich hab die Aufgabenstellung einfach mal kopiert:
"Aufgabe 5.1 Fenster mit OnPaint-Methode
5.1 Im nächsten Schritt soll die Ausgabe des Programms nun parallel in
der Konsole und in einer selbst erstellten Form stattfinden.
Das ist die zugrundeliegende Idee: In der reinen Konsolenversion war der
„Motor“ in der while-Schleife der Methode Lauf() innerhalb der Klasse
Unterklasse eingebaut. Diesen Motor verlagern wir nun in die
überschriebene OnPaint-Methode einer Form. Gleichzeitig bemühen wir uns,
von dem bisher geschriebenen Code so viel wie möglich beizubehalten, da
dieser Teil ja bereits getestet ist. Leiten Sie daher die Klasse
Unterklasse von der Klasse Form ab. Vergessen Sie nicht, die Verweise
System.Windows.Forms und System.Drawing und die entsprechenden
using-Direktiven in unter.cs unserem Programm hinzuzufügen.
...
Um Ausgaben im Formular zu realisieren, wird ein PaintHandler benötigt,
welcher dafür sorgt, Text- und Grafik-Ausgaben im Formular darzustellen.
Hierfür soll die Methode
protected override void OnPaint(PaintEventArgs pea)
verwendet werden. Sie ersetzt die Methode Lauf() unserer bisherigen
Klasse Unterklasse. Achten Sie darauf, dass die Lauffähigkeit des
Programms durch Ihre Änderungen nicht beeinträchtigt wird, der Bediener
also immer noch über die Konsole Befehle an das Programm übermitteln
kann. Der einzige Unterschied ist nun, dass zusätzlich zu den Ausgaben
in der Konsole diese auch im Formular dargestellt werden sollen. Es ist
klar, dass das Programm in dieser Zwischenstufe zwischen
Konsolenanwendung und reiner grafischer Benutzereingabe etwas „ruckelig“
funktioniert, aber das werden wir im weiteren Verlauf abstellen. Um die
Form dazu zu bringen, dass sie sich beendet, muss die Methode Close ()
aufgerufen werden."
Vielleicht hab ich auch etwas nur nich gerafft.
Ok. Ich hab es nun doch hinbekommen. Nach vielen Versuchen und
umstellen.
Letztendlich ist es wie hier, nur dass das DrawString vor dem ReadLine
kommt:
Michael Skropski schrieb:> Datei main.cs:class Hauptklasse{> public static void Main(){> Unterklasse u = new Unterklasse();> Application.Run(u);> }> }>> Datei unter.cs:class Unterklasse : Form {> protected override void OnPaint(PaintEventArgs pea){> base.OnPaint(pea);> Graphics grfx = pea.Graphics;>> string str = "";> Console.WriteLine("Eingabe:");> while(str != "beenden"){> str = Console.ReadLine();> Console.Clear();> Console.WriteLine("Eingabe war: " + str);> Console.WriteLine("Neue Eingabe:");> grfx.DrawString("Eingabe war: " + str + "\nNeue Eingabe:", Font,
Brushes.Black, 0, 0);
> }> }> }
Dennoch vielen Dank.
Hi Michael,
mannomann, Du kannst ja nichts dafür, aber die Aufgabe ist meiner
Meinung nach wirklich absoluter Schwachsinn!
OnPaint dient einzig und allein zum Zeichnen von eigenen grafischen
Erweiterungen. Normalerweise braucht niemand diese Funktion zu
überschreiben. Der Zeitpunkt, wann dieser Event ausgelöst wird, bestimmt
ganz alleine Windows und sonst niemand (außer erzwungen mit
Invalidate()). Jegliche Applikationslogik hat hier überhaupt gar nichts
zu suchen.
Auch wenn es nur ein Zwischenschritt war: Eine Übung dient ja dazu, dass
irgendetwas Sinnvolles hängenbleibt. Diesen Kram sollte man allerdings
GANZ GANZ SCHNELL wieder vergessen!
Gruß, Oliver
Ich dachte mir auch schon, dass das nicht im Sinne des Erfinders sein
kann. Ich mein, was passiert denn, wenn durch irgendwas (z.B. das
Fenster über den Bildschirmrand rausschieben und wieder zurück) noch ein
OnPaint ausgelöst wird, er aber noch in der while-Schleife steckt. In
der Vorlesung sind jetzt Events dran gekommen und es geht jetzt weiter
mit Buttons, Textfeldern usw. Ich glaube nicht, das da noch soo viel
kommt bezüglich der Forms bzw. OnPaint.
Ich hoffe das Wahlpflichtfach "Microcontrollerprogrammierung in C" wird
besser. Immerhin gibts da keine Forms oder ähnliches und C hatten wir
schon im ersten Semester.
Naja, ich bin gespannt, was er sich für die nächste Übung ausgedacht
hat.