Frage zum Tutorial aus dem Magazin (Split)
-
Hi,
ich finde den Artikel sehr gut
Ich würde gerne die Möglichkeit bieten etwas zu zeichnen. Wie kann ich das am Besten realisieren. Eignet sich ein wxPanel als Zeichemfläche? Wie kann ich dort einzelne Pixel setzen? Ich möchte gerne das man wie in MS Pain mit der Maus eine Linie zeichnen kann. Wie sollte ich das am Besten umsetzen? Ein kleiner Beispielcode wäre super!
Vielen Dank,
Marina
-
Also ich bin jetzt schon weiter, aber ich habe ein Problem: Wie kann ich es so realisieren, dass so lange gezeichnet wird, wie die Maustatse gedrückt ist?
Zur Zeit nutze ich wxEVT_LEFT_DOWN, aber das reicht für meine Zweck so nicht aus. Ich will schließlich eine Art Paint programmieren.
Kann mir jemand helfen?
Danke,
Marina
-
Hey,
ich habe nun nur noch ein Problem. Wenn ich die Maus schneller bewege, werden nur noch "ab und zu" die Punkte eingezeichnet. Es entsteht also keine Zusammenhängende Kurve
Hier ein Beispielbild. Am Anfang habe ich ganz langsam gezeichnet und zum Schluss schneller:
http://img525.imageshack.us/my.php?image=problemsc0.jpgUnd hier mein Source-Code:
class MyPanel : public wxPanel { private: typedef std::vector<wxPoint> DotVec; DotVec dots; public: MyPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxPanel(parent, id, pos, size, style) { Connect(wxEVT_PAINT,wxPaintEventHandler(MyPanel::OnPaint)); Connect(wxEVT_MOTION,wxMouseEventHandler(MyPanel::OnMotion)); Connect(wxEVT_LEFT_DOWN,wxMouseEventHandler(MyPanel::OnLeftDown)); Connect(wxEVT_LEFT_UP,wxMouseEventHandler(MyPanel::OnLeftUp)); } ~MyPanel() { } void Clear() { dots.clear(); wxClientDC dc(this); dc.SetBackground(*wxWHITE); dc.BeginDrawing(); dc.Clear(); dc.EndDrawing(); } void OnPaint(wxPaintEvent& ev) { wxPaintDC dc(this); dc.SetPen(wxPen(*wxBLACK)); dc.BeginDrawing(); for (DotVec::const_iterator it = dots.begin(); it != dots.end(); ++it) { dc.DrawPoint(*it); } dc.EndDrawing(); dc.SetPen(wxNullPen); } void OnMotion(wxMouseEvent& ev) { if (ev.LeftIsDown() && HasCapture()) { wxClientDC dc(this); dc.SetPen(wxPen(*wxBLACK)); dc.BeginDrawing(); dc.DrawPoint(ev.GetPosition()); dots.push_back(ev.GetPosition()); dc.EndDrawing(); dc.SetPen(wxNullPen); } } void OnLeftDown(wxMouseEvent& ev) { if (!HasCapture()) CaptureMouse(); } void OnLeftUp(wxMouseEvent& ev) { if (HasCapture()) ReleaseMouse(); } };
Wie kann ich das Problem lösen?
Viele liebe Grüße,
Marina
-
Hi Marina,
du zeichnest einfach nicht einzelne Punkte, sondern merkst dir immer den letzten und zeichnest dann eine Linie vom aktuellen zum letzten Punkt. wie das mit wxw geht, kann ich aber leider nicht sagen....
-
zwutz schrieb:
Hi Marina,
du zeichnest einfach nicht einzelne Punkte, sondern merkst dir immer den letzten und zeichnest dann eine Linie vom aktuellen zum letzten Punkt. wie das mit wxw geht, kann ich aber leider nicht sagen....
Gute Idee! Vielen Dank! Klappt super
Hier mein Code für mein "Zeichenflächen-Panel"
#include <wx/wx.h> #include <vector> class DrawPanel : public wxPanel { private: struct Lines { wxPoint w1, w2; }; typedef std::vector<Lines> LineVec; LineVec lines; public: DrawPanel(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) : wxPanel(parent, id, pos, size, style) { Connect(wxEVT_PAINT,wxPaintEventHandler(DrawPanel::OnPaint)); Connect(wxEVT_MOTION,wxMouseEventHandler(DrawPanel::OnMotion)); Connect(wxEVT_LEFT_DOWN,wxMouseEventHandler(DrawPanel::OnLeftDown)); Connect(wxEVT_LEFT_UP,wxMouseEventHandler(DrawPanel::OnLeftUp)); } ~DrawPanel() { } void Clear() { lines.clear(); wxClientDC dc(this); dc.SetBackground(*wxWHITE); dc.BeginDrawing(); dc.Clear(); dc.EndDrawing(); } void OnPaint(wxPaintEvent& ev) { wxPaintDC dc(this); dc.SetPen(wxPen(*wxBLACK)); dc.BeginDrawing(); for (LineVec::size_type i = 0; i < lines.size(); ++i) { dc.DrawPoint(lines[i].w1); dc.DrawPoint(lines[i].w2); dc.DrawLine(lines[i].w1, lines[i].w2); } dc.EndDrawing(); dc.SetPen(wxNullPen); } void OnMotion(wxMouseEvent& ev) { if (ev.Dragging() && HasCapture()) { wxClientDC dc(this); dc.SetPen(wxPen(*wxBLACK)); dc.BeginDrawing(); Lines t; t.w1 = lines.empty() ? ev.GetPosition() : (--lines.end())->w2; t.w2 = ev.GetPosition(); dc.DrawLine(t.w1, t.w2); dc.EndDrawing(); lines.push_back(t); dc.SetPen(wxNullPen); } } void OnLeftDown(wxMouseEvent& ev) { if (!HasCapture()) { CaptureMouse(); wxClientDC dc(this); dc.SetPen(wxPen(*wxBLACK)); dc.BeginDrawing(); dc.DrawPoint(ev.GetPosition()); dc.EndDrawing(); Lines t; t.w1 = t.w2 = ev.GetPosition(); lines.push_back(t); dc.SetPen(wxNullPen); } } void OnLeftUp(wxMouseEvent& ev) { if (HasCapture()) { ReleaseMouse(); } } };
Habt ihr noch Verbesserungsvorschläge???
Vielen Daaaaaank,
Marina
-
Ich hab noch eine Speicher-Funktion hinzugefügt. Die klappt auch, aber wenn in dem Moment gerade ein anderes Programm über der Zeichenfläche ist wird eine Art Screenshot davon erstellt. Das will ich aber so nicht! Wie kann ich das verhinden?
Hier mein Code:
void Save(const wxString& fileName) { wxClientDC dc(this); wxBitmap im; wxImage k; im.Create(GetClientSize().GetWidth(), GetClientSize().GetHeight()); wxMemoryDC *mem = new wxMemoryDC(); mem->SelectObject(im); mem->Blit(wxPoint(0, 0), GetClientSize(), &dc, wxPoint(0, 0)); k = im.ConvertToImage(); k.SaveFile(fileName, wxBITMAP_TYPE_PNG); delete mem; }
Bitte helft mir!
Marina
-
Was passiert denn, wenn du das Fenster minimierst und dann wieder hervorholst?
Speicherst du die Punkte irgendwo im Programm?
-
Hallo,
tut mir wirklich sehr leid. Ich habe diesen Thread erst gerade entdeckt. Ich dachte man hat meine Fragen gelöscht.
Ja, ich speicher die Punkte und könnte das Problem damit umgehen. Ist mir aber auch erst eben eingefallen
Ein Problem hätte ich dann aber noch:
Marina schrieb:
Dann möchte ich gerne noch ein wxImage "ausschneiden". Dazu möchte ich es gerne an allen 4 Seiten verkürzen. Das habe ich hiermit versucht:
k.Size(wxSize(imgX2, imgY2), wxPoint(imgX1, imgY1));
nach unten und rechts wird alles korrekt abgeschnitten. An der linken und oberen Seite wird theoretisch auch alles korrekt abgeschnitten, aber es bleibt ein transparenter Bereich zurück. Ich möchte aber auch keinen transparenten Bereich sondern das Bild richtig geschnitten haben. Ich habe schon die ganze Hilfe danach durchsucht und keine Funktion gefunden.
Nochmals vielen Dank
Liebe Grüße,
MarinaPS: Der Post beim Artikel kann dann gelöscht werden
-
Marina schrieb:
Hallo,
tut mir wirklich sehr leid. Ich habe diesen Thread erst gerade entdeckt. Ich dachte man hat meine Fragen gelöscht.
[...]
PS: Der Post beim Artikel kann dann gelöscht werden
Ist schon weg.
Wärst du registriert und hättest Email erlaubt, dann hätte ich dir auch geschrieben.Ich wollte nur verhindern, dass der Artikelthread so abdriftet. Für Fragen die nicht direkt zum Artikel sind ist ja das Forum da.
-
Also etwas mehr Code für das wxImage Problem wäre schon sehr gut, an einer Zeile lässt sich das schwer ausmachen.
-
phlox81 schrieb:
Also etwas mehr Code für das wxImage Problem wäre schon sehr gut, an einer Zeile lässt sich das schwer ausmachen.
Hi,
ich möchte nur den Teil haben auf dem tatsächlich etwas gezeichnet wurde. Dafür taste ich mich an allen 4 Seiten ran, und suche nach dem Pixel der zum Rand am nächsten ist. Ich wusste aber nicht, wie man mit wxImage auf einzelne Pixel zugreifen kann. Also habe ich das notgedrungen mit SFML gemacht. Wäre aber toll, wenn mir jemand sagt, wie ich das ohne SFML lösen könnte:
sf::Image img; img.LoadFromFile("temp.png"); unsigned int imgX1 = img.GetWidth(); unsigned int imgX2 = 0; unsigned int imgY1 = img.GetHeight(); unsigned int imgY2 = 0; for (unsigned int j = 0; j < img.GetHeight(); ++j) { for (unsigned int i = 0; i < img.GetWidth(); ++i) { if (img.GetPixel(i, j) != sf::Color::White) { if (imgX1 > i) imgX1 = i; if (imgX2 < i) imgX2 = i; if (imgY1 > j) imgY1 = j; if (imgY2 < j) imgY2 = j; } } } imgX1 -= 1; imgX2 += 1; imgY1 -= 1; imgY2 += 1;
An den nun ermittelten Stellen soll das Bild ausgeschnitten werden. Die Funktion Size macht das aber nicht so, wie ich es will, da eine transparenter Bereich erzeugt wird:
Returns a resized version of this image without scaling it by adding either a border with the given colour or cropping as necessary. The image is pasted into a new image with the given size and background colour at the position pos relative to the upper left of the new image. If red = green = blue = -1 then use either the current mask colour if set or find, use, and set a suitable mask colour for any newly exposed areas
Ich habe also ein wxImage und will aus diesem an den Stellen imgX1, imgY1 bis imgX2, imgY2 ausschneiden und das Ergebnis z.B. in ein neues wxImage einlesen.
Ich habe schon gesehen das es so was wie wxRect gibt, aber lässt sich damit mein Problem lösen?
Danke,
Marina
-
Sind denn deine Koordinaten die du da ermittelst korrekt?
Eigentlich müsstest du ja wenn du alle Punkte speicherst, daraus auch das resultierende Rechteck ermitteln können.
-
Ja, ich hab das jetzt mit probieren geschafft
Könntest du mir erklären, wie ich den Teil mit der Koordinatenermittlung ohne SFML umsetzen kann? Dann brauche ich diese Bibliothek endlich nicht mehr. Danke!
-
Marina schrieb:
Ja, ich hab das jetzt mit probieren geschafft
Könntest du mir erklären, wie ich den Teil mit der Koordinatenermittlung ohne SFML umsetzen kann? Dann brauche ich diese Bibliothek endlich nicht mehr. Danke!
Ich würde es ganz anders anpacken. Das Bild danach zu durchsuchen ist zu ineffizient. Wenn du sowieso eine Liste der Punkte die Gezeichnet wurde hast, dann kannst du aus dieser Punktliste auch das Rechteck errechnen.
pseudocode:
std::vector<wxPoint> ptlist; wxRect rect; makeMaxRect(ptlist[0],ptlist[1],rect)//die musst du dann selber implementieren. for(int i = 2; i < ptlist.size();i++) makeMaxRect(ptlist[i-1],ptlist[i],rect)
phlox
-
Du hast natürlich Recht
Warum bin ich da nicht selber drauf gekommen? Ich werde das jetzt mal so umsetzen
V I E L E N D A N K ! ! !
Marina
-
Die Lösung funktioniert leider doch nicht so
Meine Punkte sind wegen SetPen größer. Daher stimmen dann die Koordinaten nicht mehr überein
Am Besten überprüfe ich doch jeden Pixel. Könntest du mir sagen, wie ich an die Pixel ran komme?
Danke,
Marina
-
Marina schrieb:
Die Lösung funktioniert leider doch nicht so
Meine Punkte sind wegen SetPen größer. Daher stimmen dann die Koordinaten nicht mehr überein
Am Besten überprüfe ich doch jeden Pixel. Könntest du mir sagen, wie ich an die Pixel ran komme?
Danke,
MarinaWenn SetPen einheitlich ist, kannst du das ja immer noch berechnen.
Du müsstest aufjedenfall so das korrekte Rechteck erhalten, und musst es dann evtl. noch an solche Dinge anpassen.