C# Anfänger-Fragen zu C#

psybak

Cadet 3rd Year
Dabei seit
Jan. 2008
Beiträge
50
Hallo Leute,

ich mache zur Zeit eine Studienarbeit in C# für die FH und habe da als Anfänger noch einige kleinere Stolpersteine.

Erstellt werden soll eine Art simpler Bildeditor, in dem man z.B. Bilder, Text, Linien und Rechtecke einfügen kann. Hier ein Link zum Screenshot, wie es momentan aussieht:



Die Grafik-Elemente sollen zu erst nur in dem Rechteck als Vorschau angezeigt werden, erst durch das Drücken des "Einfügen"-Buttons fest auf die Picture-Box gezeichnet werden.

Vielleicht kann mir ja jemand von euch bei folgenden Problemstellungen helfen:


  • Wie kann ich den "Einfügen"-Vorgang realisieren? Wichtig dabei ist, dass der Zustand (Bild, Text, Linie, Rechteck) ausgelesen wird.

  • Wie kann ich den Rahmen eines Rechtsecks mit einem Timer-Event farblich von schwarz nach weiß ändern (blinken lassen)?

Bin für jede Unterstützung dankbar!

Danke + Gruß

psybak
 

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
Einfügen: Den Zustand sich intern merken/abspeichern. Sollte nicht schwer sein, wird ja in den entsprechenden Feldern gespeichert.
Rahmen: Im Timer bei jedem Aufruf ein Rahmen zeichnen, in einer Variable abspeichern, was beim letzten Aufruf für eine Farbe war und die andere zeichnen.
 

psybak

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Jan. 2008
Beiträge
50
hui - das ging ja schnell!

Ja von der Theorie her hab ich mir das auch schon so überlegt. Momentan scheitert es noch an der Umsetzung.

Einfügen: Den Zustand sich intern merken/abspeichern. Sollte nicht schwer sein, wird ja in den entsprechenden Feldern gespeichert.
Wie kann ich den Zustand am besten abspeichern? Muss ich einen Umweg über die Zwischenablage machen?
 

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
Zustand:
Code:
struct
{
int x,y,breite,hoehe;
TYP typ;
COLOR farbe;
String^text;
FONT schrift;
IMAGE bild;
};
Das kannst du alles aus den Steuerelementen deiner Dialogbox auslesen, so wie du ins Vorschaubild zeichnest, musst du dann nur noch in dein "echtes" Bild zeichnen. (Am besten in eine Funktion auslagern, die als Parameter die Zeichnefläche nimmt)
 

psybak

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Jan. 2008
Beiträge
50
Also ich hab momentan im Paint-Event der picturebox u. a. folgenden Code stehen:

if (Zustand == Zustaende.Text)
{
e.Graphics.DrawString(txtText.Text, dialogFont.Font, new SolidBrush(txtColor.BackColor), (float)nudX.Value, (float)nudY.Value);
}


Damit wird, wenn in der Listbox "Text" ausgewählt ist auf die PicBox gezeichnet.

Frage nun, wie kann ich mit der Click-Event-Methode des Einfügenbuttons den Text fest auf die picbox zeichnen und anschließen einen neuen Text an einer anderen Stelle einfügen?
 
Zuletzt bearbeitet:

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
Ja und jetzt machst du statt e.Graphics halt MyPictureBox.Graphics rein und schwupps haste es richtig gezeichnet.

Ahh, jetzt versteh ich dein Problem, es wird direkt auf die Zeichenfläche die Vorschau gezeichnet.
Du hast ja irgendwo dein Bild abgespeichert, das zeichnest du ja bei OnPaint zuerst.
Wenn du jetzt auf Einfügen drückst, musst du nur auf das gespeicherte Bild statt auf den Bildschirm zeichnen.
 

toeffi

Lt. Junior Grade
Dabei seit
Feb. 2010
Beiträge
474
Für dein Timer event, schau dir mal den System.Threading.Timer an. Um nicht ins gehege mit dem GUI Thread zu kommen, müsstest du dir dazu die Methode BeginInvoke mal anschauen.
@Blitzmerker: was hatten dein struct mit C# zu tuen? :D
 

psybak

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Jan. 2008
Beiträge
50
Vielleicht sollte ich noch dazu sagen, dass ich als Entwicklungsumgebung Visual Studio 2005 nutze. Das mit dem "Struct" sagt mir ehrlich gesagt gar nichts.

Es geht momentan darum, dass ich den "Einfügen"-Vorgang in folgenden Code einfüge:

private void butPaste_Paint(object sender, PaintEventArgs e)
{

}


Ich komme aber einfach nicht drauf, wie ich den Wert des jeweils ausgewählten Grafik-Elements auslesen und fest auf die PictureBox bekomme....
 
Dabei seit
Dez. 2009
Beiträge
213
Ich nehme mal an, du meinst es so, dass der Benutzer das Rechteck mit Maus oder Cursor-Tasten erst mal positionieren soll, also so wie in Paint.

Tue immer erst das Bild aus irgendeiner Bilddatei zeichnen lassen. Dannach das Rechteck. Wenn sich dann zB. das Rechteck verschiebt, musst du wieder erst das original-Bild zeichnen und dann das Rechteck darüber, jetzt aber mit anderen Koordinaten. Wenn du es dann richtig fest einfügen möchtest, dann lass das Rechteck direkt in das Bild zeichnen und abspeichern.

Mit dem Timer könntest du es so regeln:
Bei jedem Timer-Tick wird eine bool-Variable gelesen, die angibt, ob das Rechteck weiß oder schwarz sein soll. Dann wird das Rechteck neu gezeichnet (siehe oben) und ganz am Schluss noch die bool-Variable fürs nächste mal geändert.

Ich habe dir jetzt hier kein Code für c# gepostet, das war mir zu aufwendig, aber mit dieser Strukturanleitung wirst du in der Lage sein, nach entsprechenden .NET Klassen zu recherchieren. Oder hier zu posten, ich weiß ja nicht, wieviel du schon in c# weißt...
 

psybak

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Jan. 2008
Beiträge
50
Ok, ich kann euren Tipps leider nur schwer folgen...hiermal der Code, in dem ich die verschiedenen Zustände der Bild-Element-Auswahl realisiert habe:

private void picScreen_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;

Pen pen = new Pen(Color.Black);
pen.DashStyle = DashStyle.Dash;
pen.Color = dialogColor.Color;

if (Zustand == Zustaende.Bild)
{
if (File.Exists(txtPicture.Text))
{
Bitmap bmp = new Bitmap(Image.FromFile(txtPicture.Text));
Graphics bmpGr = Graphics.FromImage(bmp);

bmpGr.Dispose();

e.Graphics.DrawImage(bmp, (int)nudX.Value, (int)nudY.Value, (int)nudB.Value, (int)nudH.Value);
}
}

if (Zustand == Zustaende.Linie)
{
e.Graphics.DrawLine(pen, (int)nudX.Value, (int)nudY.Value, ((int)nudX.Value + (int)nudB.Value), ((int)nudY.Value + (int)nudH.Value));
}

if (Zustand == Zustaende.Rechteck)
{
e.Graphics.DrawRectangle(pen, (int)nudX.Value, (int)nudY.Value, (int)nudB.Value, (int)nudH.Value);
}

if (Zustand == Zustaende.Text)
{
e.Graphics.DrawString(txtText.Text, dialogFont.Font, new SolidBrush(txtColor.BackColor), (float)nudX.Value, (float)nudY.Value);

}

g.DrawRectangle(pen, (int)nudX.Value, (int)nudY.Value, (int)nudB.Value, (int)nudH.Value); // ----> hier wird das Auswahl-Rechteck gezeichnet


.
.
.
.
.
.
.
private void butPaste_Paint(object sender, PaintEventArgs e)
{

}


An dieser Stelle hapert es halt momentan: Ich weiß einfach nicht, wie ich programmieren kann, dass z.B. der Text, den ich eingetippt habe, dauerhaft auf meiner PictureBox bleibt - durch drücken des "Einfügen"-Buttons. Zur Zeit seh ich den Text nur solange, wie ich in der Auswahl-Liste der Bild-Elemente den Eintrag "Text" ausgewählt habe. Wenn ich aber einen Text eingegeben habe, aber dann auf z.B. "Rechteck" in der Auswahlliste gehe, ist der Text halt weg.
 

Syssneck

Lieutenant
Dabei seit
Sep. 2007
Beiträge
792
Ist das Dispose nicht so eine Löschfunktion? (bin mir da nicht sicher)
Weill dann wäre es ja logisch, nachdem du "text" nicht mehr ausgewählt hast läuft er wieder von oben durch löscht den Text aus dem Feld und die Bedinung, dass der Zustand Text ist, ist ja auch nciht mehr erfüllt, so wird der Text nicht mehr neu gezeichnet, bau vielleicht nochmal ein Knopf ein mit dem du sowas extra machst.
 

kalleberlin

Lieutenant
Dabei seit
Feb. 2005
Beiträge
851
Zur Zeit seh ich den Text nur solange, wie ich in der Auswahl-Liste der Bild-Elemente den Eintrag "Text" ausgewählt habe. Wenn ich aber einen Text eingegeben habe, aber dann auf z.B. "Rechteck" in der Auswahlliste gehe, ist der Text halt weg.
Das liegt daran, das deine Picturebox jedesmal neu gezeichnet wird. Wenn Du also Text + Rechteck haben möchtest, musst Du auch beides *gleichzeitig* zeichnen, was Du aber nicht tust .

Desweiteren, ist es sehr performancehungrig, wenn Du bei jedem neu zeichnen dein Bild von der Festplatte liest. Wenn ich das richtig sehe, willst Du das ganze einfach nur anzeigen. Lade das Bild nur *einmal*.


Eine letzte Frage stellt sich mir noch:

Code:
Graphics bmpGr = Graphics.FromImage(bmp);

bmpGr.Dispose();
Warum erstellst Du hier ein Graphics object, nur um es dann gleich wieder zu löschen? :)

//Kalleberlin
 

psybak

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Jan. 2008
Beiträge
50
Das liegt daran, das deine Picturebox jedesmal neu gezeichnet wird. Wenn Du also Text + Rechteck haben möchtest, musst Du auch beides *gleichzeitig* zeichnen, was Du aber nicht tust .
Hmm...ok....wie zeichne ich beides gleichzeitig? ;)

Desweiteren, ist es sehr performancehungrig, wenn Du bei jedem neu zeichnen dein Bild von der Festplatte liest. Wenn ich das richtig sehe, willst Du das ganze einfach nur anzeigen. Lade das Bild nur *einmal*.
Joa, du kannst dir die Frage denken: Wie mach ich das? :freak:

Die Dispose MEthode habe ich mal rausgelassen, aber es ändert momentan nichts. Für später halte ich das aber mal im Hinterkopf...

Gruß
psybak
 

kalleberlin

Lieutenant
Dabei seit
Feb. 2005
Beiträge
851
Hallo psybak,

du zeichnest beides indem Du dein Zeichenvorgang (e.Graphics...) nicht durch eine IF-Bedingung ausschliesst.

Dein "Zustand" kann ja nur* "Linie", "Rechteck" oder eben "Text" sein. Das heisst also, wenn dein Zustand == Text ist, wird natürlich auch *nur* dein Text gezeichnet, weil bei deinen weiteren IF-Abfrage die Bedingung ja false ist, und somit nicht gezeichnet wird.

Wie bereits oben erwähnt, jedes mal wenn deine OnPaint-Methode aufgerufen wird, musst Du dir ein weisses Blatt vorstellen. Du Zeichnest jedesmal alles neu.

*Man kann enums zwar auch kombinieren, aber das lassen wir erstmal um dich nicht zu verwirren :p

//Kalleberlin
 

psybak

Cadet 3rd Year
Ersteller dieses Themas
Dabei seit
Jan. 2008
Beiträge
50
Hi Kalle,

ich hab jetzt diverse Versuche gemacht und meinen Quelltext umgeschrieben in Bezug auf die IF-Schleife. Es will einfach nicht klappen! :(

Wie kann ich es realisieren, dass sich die LEinwand nicht jedesmal neu zeichnet?

Dazu müsste ich ja schon gezeichnetes abspeichern und wieder neu-mitzeichnen, wenn ich das Paint-Event erneut aufrufe...oder?!
 

cx01

Ensign
Dabei seit
Mai 2010
Beiträge
241
Du hast 2 Möglichkeiten:
- du speichert in einem Array alle Zeichenoperationen in abstrakter Form, so wie es Blitzmerker mit der struct oben vorgeschlagen hat. Dann musst du in dieser Paint-Methode einfach dein Array durchgehen und alle Operationen nacheinander anwenden
- du zeichnest alles in einen unsichtbaren Buffer (also z.B. ein Bitmap Element). Den kopierst du dann in der Paint-Methode einfach in die PictureBox
 
Top