12. November 2010
Bei dieser Aufgabe haben wir den Umgang mir Buffern gelernt und die Klasse PGraphics verwendet. Die Aufgabe bestand darin ein Zeichnungstool zu erstellen. Das Zeichnungsprogramm sollte die Möglichkeit bieten einen Screenshot zu speichern als JPG oder PNG. Ebenfalls sollte der Abgabe die interessanteste Zeichnung als File beigelegt werden. Das Programm soll auch einige GUI-Elemente enthalten, mit denen man die Zeichnung beeinflussen kann. Ich hatte hier die Idee eine vorhergehende Aufgabe weiterzuführen. Und zwar das Erstellen von Ornamenten. In einem Buffer sollte man mit der Maus zeichnen können und diese "Kachel" dann gleich in einem Displaybereich dupliziert dargestellt bekommen. Hilfslinien beim Mauszeiger sollten helfen die Linien an den Grenzen (oben, unten, links, rechts) nahtlos zu platzieren. Optionen- Werkzeugspitze Kreis
- Werkzeugspitze Linie
- Radiergummi
- Grösse Werkzeugspitzen ändern
- Anzeige Spalten gespiegelt
- Anzeige Reihen gespiegelt
- Screenshot speichern
- Kachelgrösse anpassen
size(1200, 900, OPENGL);Folgende Angabe erlaubt es beim Speichern eines Screenshots der Datei einen Namen zu geben.
save(selectOutput());Lustigerweise gibt es einen Fehler, wenn im System-Popup Cancel gedrückt wird (NullPointerException). 2. Version Bei der zweiten Version sind nun alle Option umgesetzt. Die Kacheln werden neu alle in einen Buffer gezeichnet, somit sind Überlappungen an den Rändern möglich. Wenn die Kachelgrösse geändert wird, dann kann über ein feines "kleinmaschiges" Ornament ein grosses gezeichnet werden. Ebenfalls kann nun die Grösse der Werkzeugspitze verändert werden. Die interessantesten Resultate entstehen, wenn die Reihen und Spalten gespiegelt werden. Download Finaler Code Ornament Generator (ZIP) Checkbox Klasse
class Checkbox { PVector _p1; // starting point PVector _p2; // end point int _h = 20; // height of checkbox int _w = 20; // width of checkbox boolean _checked; // flag checkbox selected // x/y of scheckbox, width/height of bg checkbox Checkbox(int x,int y) { //_dir = dir; _p1 = new PVector(x+_w*.5, y); _p2 = new PVector(x+_w*.5, y+_h); smooth(); // svg loaded for slider styling } boolean isHit(int x,int y) { if (x > _p1.x - 10 && x < _p1.x + 10 && y > _p1.y && y < _p2.y) { return true; } else { return false; } } void draw() { pushStyle(); drawCheckbox(); if (_checked==true) drawKnob(false); // if preselected popStyle(); } void drawCheckbox() { PShape checkboxBg = loadShape("checkbox_bg.svg"); PShape checkboxEnd = loadShape("checkbox_end.svg"); checkboxBg.rotate(radians(-90)); checkboxEnd.rotate(radians(-90)); shape(checkboxEnd,_p1.x-_w/1.5*.5,_p1.y+10/1.5,20/1.5,20/1.5); // end left shape(checkboxEnd,_p1.x-_w/1.5*.5,_p2.y+10/1.5,20/1.5,20/1.5); // end right shape(checkboxBg,_p1.x-_w/1.5*.5,_p2.y,_w/1.5,_h); // strip } void drawKnob(boolean hover) { PShape sliderKnob = null; if (hover==false) { sliderKnob = loadShape("checkbox_knob.svg"); } else { sliderKnob = loadShape("checkbox_knob_hover.svg"); } PVector dir = PVector.sub(_p1,_p2); PVector pos = PVector.add( _p2, PVector.mult(dir,0.5)); shape(sliderKnob,pos.x-_w*.5, pos.y - 10,20,20); } void mousePos(int x,int y,boolean pressed) { if(pressed) { if(isHit(x,y)) { if (_checked==false) { drawKnob(false); // checkbox activated _checked = true; } else { _checked = false; } } } else { // mouse over: highlight knob, only if knob visible if(isHit(x,y) && _checked==true) drawKnob(true); } } }Programm Code
// buttons Checkbox btnSaveScreen = null; Checkbox btnSelectDrawType0 = null; Checkbox btnSelectDrawType1 = null; Checkbox btnFlipXDisplay = null; Checkbox btnFlipYDisplay = null; Checkbox btnEraser = null; Slider sliderBrushSize = null; Slider sliderNumTiles = null; PGraphics pg; // buffer drawing PGraphics pdisp; // buffer display // general margins int marginLeft = 50; int marginTop = 50; // dimensions areas, tile int drawAreaWidth = 200; int drawAreaHeight = drawAreaWidth; int tileDisplayWidth = 50; int tileDisplayHeight = tileDisplayWidth; int displayAreaWidth = 800; int displayAreaHeight = displayAreaWidth; int displayTilesX = displayAreaWidth/tileDisplayWidth; int displayTilesY = displayTilesX; // yet square int indexMousePointerWidth = 20; // circle following mouse pointer int indexMousePointerHeight = indexMousePointerWidth; int eraserWidth = indexMousePointerWidth*2; int eraserHeight = indexMousePointerHeight*2; int offsetTopNav = marginTop+drawAreaHeight+50; // start Y of navigation area int offsetLeftNav = marginLeft+20; // start Y of navigation area int drawType = 0; // 0: ellipse, 1: line boolean mouseDown = false; // mouse pressed boolean mouseDownDrawing = false; // draw only when mouse pressed (true: mouse pressed & within drawing area) float pgScaleDown = 1; // pg scaled gives very thin lines (shadowy) int fontSize = 16; void setup() { size(1200, 900); // , OPENGL) smooth(); // load font and set font size PFont font = loadFont("AvenirLT-Roman-48.vlw"); textFont(font, fontSize); // buffer erstellen pg = createGraphics(drawAreaWidth,drawAreaHeight,JAVA2D); pg.beginDraw(); pg.endDraw(); // avoid nullpointer error (has to be called once, only set on mousepressed) pdisp = createGraphics(displayTilesX*tileDisplayWidth,displayTilesY*tileDisplayHeight,JAVA2D); pdisp.beginDraw(); pdisp.endDraw(); // avoid nullpointer error (has to be called once, only set on mousepressed) // buttons (checkboxes) btnSaveScreen = new Checkbox(offsetLeftNav,offsetTopNav+fontSize*17+4,false); btnSelectDrawType0 = new Checkbox(offsetLeftNav,offsetTopNav+fontSize*0+4,true); btnSelectDrawType1 = new Checkbox(offsetLeftNav,offsetTopNav+fontSize*2+4,false); btnFlipXDisplay = new Checkbox(offsetLeftNav,offsetTopNav+fontSize*10+4,false); btnFlipYDisplay = new Checkbox(offsetLeftNav,offsetTopNav+fontSize*12+4,false); btnEraser = new Checkbox(offsetLeftNav,offsetTopNav+fontSize*4+4,false); // sliders sliderBrushSize = new Slider(offsetLeftNav,offsetTopNav+fontSize*6+4,100,20,.2,true); sliderNumTiles = new Slider(offsetLeftNav,offsetTopNav+fontSize*21+4,100,20,.125,true); frameRate(30); } void draw() { background(212); pushStyle(); fill(0); text("Werkzeugspitze",offsetLeftNav,offsetTopNav-12); // BUTTON draw type LINE btnSelectDrawType0.draw(); btnSelectDrawType0.mousePos(mouseX,mouseY,false); text("Kreis",offsetLeftNav+30,offsetTopNav+fontSize); btnSelectDrawType1.draw(); btnSelectDrawType1.mousePos(mouseX,mouseY,false); text("Linie",offsetLeftNav+30,offsetTopNav+fontSize*3); // BUTTON eraser btnEraser.draw(); btnEraser.mousePos(mouseX,mouseY,false); text("Radiergummi",offsetLeftNav+30,offsetTopNav+fontSize*5); // BUTTON brush size sliderBrushSize.draw(); sliderBrushSize.mousePos(mouseX,mouseY,false); text("Grösse",offsetLeftNav+116,offsetTopNav+fontSize*7); // BUTTON flip display tiles X btnFlipXDisplay.draw(); btnFlipXDisplay.mousePos(mouseX,mouseY,false); text("Spalten spiegeln",offsetLeftNav+30,offsetTopNav+fontSize*11); // BUTTON flip display tiles Y btnFlipYDisplay.draw(); btnFlipYDisplay.mousePos(mouseX,mouseY,false); text("Reihen spiegeln",offsetLeftNav+30,offsetTopNav+fontSize*13); // BUTTON save screenshot btnSaveScreen.draw(); btnSaveScreen.mousePos(mouseX,mouseY,false); text("Screenshot speichern",offsetLeftNav+30,offsetTopNav+fontSize*18); // BUTTON numbner of tiles sliderNumTiles.draw(); sliderNumTiles.mousePos(mouseX,mouseY,false); text("Kachelgrösse",offsetLeftNav+116,offsetTopNav+fontSize*22); popStyle(); tileDisplayWidth = ((int)((sliderNumTiles._pos*400.0))/50)*50; if (tileDisplayWidth<50) tileDisplayWidth=25; if (tileDisplayWidth>200) tileDisplayWidth=400; if (tileDisplayWidth>100 && tileDisplayWidth<200) tileDisplayWidth=100; //println(tileDisplayWidth); tileDisplayHeight = tileDisplayWidth; // DRAWING AREA // GRAPHIC drawing area if (mouseDownDrawing==true) { pg.beginDraw(); drawTile(pg, 1.0, 0, 0, false, false, 0, 0); // TILE pg.endDraw(); } // border drawing area pushStyle(); stroke(0); fill(255); rect(50,50,drawAreaWidth,drawAreaWidth); popStyle(); pushMatrix(); translate(0,0); // show buffer drawing image(pg, marginLeft, marginTop); popMatrix(); pushStyle(); stroke(0); noFill(); rect(50,50,drawAreaWidth,drawAreaWidth); popStyle(); // DISPLAY AREA // GRAPHIC display area (scaled down, multiplied) // border display area pushStyle(); stroke(236); strokeWeight(5); fill(255); rect(300,marginLeft,displayAreaWidth,displayAreaHeight); popStyle(); if (mouseDownDrawing==true) { pdisp.beginDraw(); for(int i=0; i<displayTilesX; i++) { for(int k=0; k<displayTilesY; k++) { drawTile(pdisp, (tileDisplayWidth*1.0/drawAreaWidth*1.0),tileDisplayWidth*i,tileDisplayHeight*k,btnFlipXDisplay._checked,btnFlipYDisplay._checked, i, k); // TILE SMALL } } pdisp.endDraw(); } pushMatrix(); translate(0,0); // show buffer display area image(pdisp, 300, marginTop); popMatrix(); // OPTION save screenshot if (btnSaveScreen._checked==true) { save(selectOutput()); btnSaveScreen._checked = false; // diactivate btn immediately (save screen only once) } // index mouse pointer if (hitTest(mouseX, mouseY)) { // only visible when mouse within drawing area pushStyle(); noFill(); stroke(102); strokeWeight(2); ellipse(mouseX,mouseY,indexMousePointerWidth,indexMousePointerHeight); popStyle(); // help lines pushStyle(); noFill(); stroke(153); strokeWeight(1); int helplineX = mouseX; if (mouseX<marginLeft) helplineX = marginLeft; if (mouseX>marginLeft+drawAreaWidth) helplineX = marginLeft+drawAreaWidth; line(helplineX,marginTop,helplineX,marginTop+drawAreaHeight); int helplineY = mouseY; if (mouseY<marginTop) helplineY = marginTop; if (mouseY>marginTop+drawAreaHeight) helplineY = marginTop+drawAreaHeight; line(marginLeft,helplineY,marginLeft+drawAreaWidth,helplineY); popStyle(); } } boolean hitTest(int x,int y) { if (x > marginLeft && x < marginLeft + drawAreaWidth && y > marginTop && y < marginTop + drawAreaHeight) { return true; } else { return false; } } // mouse events void mousePressed() { mouseDown = true; if (hitTest(mouseX, mouseY)) mouseDownDrawing = true; // draw only when mouse is pressed btnSaveScreen.mousePos(mouseX,mouseY,true); btnSelectDrawType0.mousePos(mouseX,mouseY,true); btnSelectDrawType1.mousePos(mouseX,mouseY,true); btnFlipXDisplay.mousePos(mouseX,mouseY,true); btnFlipYDisplay.mousePos(mouseX,mouseY,true); btnEraser.mousePos(mouseX,mouseY,true); sliderBrushSize.mousePos(mouseX,mouseY,true); sliderNumTiles.mousePos(mouseX,mouseY,true); } void mouseDragged() { sliderBrushSize.mousePos(mouseX,mouseY,true); sliderNumTiles.mousePos(mouseX,mouseY,true); } void mouseReleased() { mouseDown = false; // stop drawing mouseDownDrawing = false; // stop drawing } // FUNCTION: DRAW TILE // scale: 1.0 -> width 200 // flipAlp: kacheln alternierend spiegeln void drawTile(PGraphics pg, float scaling, int offsetLeft, int offsetTop, boolean flipAltX, boolean flipAltY, int numIndexCol, int numIndexRow) { // draws one tile, used for drawing area and display area // tiles in display area are scaled down pg.smooth(); pg.stroke(0); pg.strokeWeight(1.0*scaling); pg.scale(pgScaleDown); // scale down // TODO INCLUDE TYPES if (mouseDownDrawing==true) { // SWITCH draw types if (btnEraser._checked==true) { drawType = 2; } else if (btnSelectDrawType0._checked==true) { drawType = 0; } else if (btnSelectDrawType1._checked==true) { drawType = 1; } else { drawType = 0; } float drawLineWidth = 75*sliderBrushSize._pos; float startX = ((mouseX/pgScaleDown-marginLeft/pgScaleDown)*scaling+offsetLeft); float startY = ((mouseY/pgScaleDown-marginTop/pgScaleDown)*scaling+offsetTop); float endX = (mouseX/pgScaleDown-(marginLeft-drawLineWidth)/pgScaleDown)*scaling+offsetLeft; float endY = (mouseY/pgScaleDown-(marginTop-drawLineWidth)/pgScaleDown)*scaling+offsetTop; int isEvenCol = numIndexCol%2; int isEvenRow = numIndexRow%2; if (flipAltX==true && isEvenCol==1) { // flip horizontally alternated startX = ((offsetLeft+tileDisplayWidth) - (mouseX/pgScaleDown-marginLeft/pgScaleDown)*scaling); endX = (offsetLeft+tileDisplayWidth) - (mouseX/pgScaleDown-(marginLeft-drawLineWidth)/pgScaleDown)*scaling; } if (flipAltY==true && isEvenRow==1) { // flip vertically alternated startY = ((offsetTop+tileDisplayHeight) - (mouseY/pgScaleDown-marginLeft/pgScaleDown)*scaling); endY = (offsetTop+tileDisplayHeight) - (mouseY/pgScaleDown-(marginTop-drawLineWidth)/pgScaleDown)*scaling; } switch(drawType) { case 0: // ellipse pushStyle(); pg.fill(0); pg.noStroke(); pg.ellipse(startX, startY,20*scaling*sliderBrushSize._pos, 20*scaling*sliderBrushSize._pos); popStyle(); break; case 1: // line pg.line(startX, startY, endX, endY); break; case 2: // eraser pushStyle(); pg.fill(255); pg.noStroke(); pg.ellipse(startX, startY, eraserWidth*scaling*sliderBrushSize._pos, eraserHeight*scaling*sliderBrushSize._pos); popStyle(); break; } } }