Редактирование: Java Gnome FAQ Drawing with cairo
Материал из Wiki.crossplatform.ru
Внимание: Вы не представились системе. Ваш IP-адрес будет записан в историю изменений этой страницы.
Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.
Текущая версия | Ваш текст | ||
Строка 1: | Строка 1: | ||
+ | In this part of the Java programming tutorial, we will do some drawing with the Cairo library. | ||
+ | <b>Cairo</b> is a library for creating 2D vector graphics. | ||
+ | We can use it to draw our own widgets, charts or various effects or animations. | ||
+ | |||
+ | == Simple drawing == | ||
+ | |||
+ | The stroke operation draws the outlines of shapes and the fill operation fills the insides of shapes. Next we will demonstrate these two operations. | ||
+ | |||
+ | <source lang="java"> | ||
+ | package com.zetcode; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.Allocation; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | /** | ||
+ | * Java Gnome tutorial | ||
+ | * | ||
+ | * This program draws a simple | ||
+ | * drawing with the Cairo library. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GSimpleDrawing extends Window implements Widget.ExposeEvent { | ||
+ | |||
+ | public GSimpleDrawing() { | ||
+ | |||
+ | setTitle("Simple drawing"); | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | setDefaultSize(250, 200); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | darea.connect(this); | ||
+ | add(darea); | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | final Context cr; | ||
+ | |||
+ | cr = new Context(widget.getWindow()); | ||
+ | drawShape(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public void drawShape(Context cr) { | ||
+ | |||
+ | cr.setLineWidth(9); | ||
+ | cr.setSource(0.7, 0.2, 0.0); | ||
+ | |||
+ | int width, height; | ||
+ | width = getAllocation().getWidth(); | ||
+ | height = getAllocation().getHeight(); | ||
+ | |||
+ | cr.translate(width/2, height/2); | ||
+ | cr.arc(0, 0, (width < height ? width : height) / 2 - 10, 0, 2*Math.PI); | ||
+ | cr.strokePreserve(); | ||
+ | |||
+ | cr.setSource(0.3, 0.4, 0.6); | ||
+ | cr.fill(); | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GSimpleDrawing(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | In our example, we will draw a circle and fill it with a solid color. | ||
+ | |||
+ | <source lang="java"> | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | </source> | ||
+ | |||
+ | We will be doing our drawing operations on the <b>DrawingArea</b> widget. | ||
+ | |||
+ | <source lang="java"> | ||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | final Context cr; | ||
+ | |||
+ | cr = new Context(widget.getWindow()); | ||
+ | drawShape(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | When the window needs to be redrawn, the <b>ExposeEvent</b> is created. | ||
+ | The actual drawing is delegated to the <b>drawShape()</b> method. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr = new Context(widget.getWindow()); | ||
+ | </source> | ||
+ | |||
+ | We create the <b>Context</b> object from the gdk window of the drawing area. The context is an object onto which we do all our drawings. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.setLineWidth(9); | ||
+ | </source> | ||
+ | |||
+ | We set the width of the line to 9 pixels. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.setSource(0.7, 0.2, 0.0); | ||
+ | |||
+ | </source> | ||
+ | |||
+ | We set the color to dark red. | ||
+ | |||
+ | <source lang="java"> | ||
+ | int width, height; | ||
+ | width = getAllocation().getWidth(); | ||
+ | height = getAllocation().getHeight(); | ||
+ | |||
+ | cr.translate(width/2, height/2); | ||
+ | </source> | ||
+ | |||
+ | We get the width and height of the drawing area. | ||
+ | We move the origin into the middle of the window. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.arc(0, 0, (width < height ? width : height) / 2 - 10, 0, 2*Math.PI); | ||
+ | cr.strokePreserve(); | ||
+ | |||
+ | </source> | ||
+ | |||
+ | We draw the outside shape of a circle. The <b>strokePreserve()</b> strokes the current path according to the current line width, line join, line cap, and dash settings. Unlike the <b>stroke()</b>, it preserves the path within the cairo context. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.setSource(0.3, 0.4, 0.6); | ||
+ | cr.fill(); | ||
+ | </source> | ||
+ | |||
+ | This fills the interior of the circle with some blue color. | ||
+ | |||
+ | [[image: Java_Gnome_faq_simpledrawing.png| center]] | ||
+ | |||
+ | == Basic shapes == | ||
+ | |||
+ | The next example draws some basic shapes onto the window. | ||
+ | |||
+ | <source lang="java"> | ||
+ | |||
+ | package com.zetcode; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | import org.freedesktop.cairo.Matrix; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program draws basic shapes | ||
+ | * with the cairo library. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GBasicShapes extends Window implements Window.ExposeEvent { | ||
+ | |||
+ | public GBasicShapes() { | ||
+ | |||
+ | setTitle("Basic Shapes"); | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | setDefaultSize(390, 240); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | darea.connect(this); | ||
+ | add(darea); | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | final Context cr; | ||
+ | |||
+ | cr = new Context(widget.getWindow()); | ||
+ | drawShapes(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public void drawShapes(Context cr) { | ||
+ | |||
+ | cr.setSource(0.6, 0.6, 0.6); | ||
+ | |||
+ | cr.rectangle(20, 20, 120, 80); | ||
+ | cr.rectangle(180, 20, 80, 80); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.arc(330, 60, 40, 0, 2*Math.PI); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.arc(90, 160, 40, Math.PI/4, Math.PI); | ||
+ | cr.fill(); | ||
+ | |||
+ | Matrix mat = new Matrix(); | ||
+ | mat.translate(220, 180); | ||
+ | mat.scale(1, 0.7); | ||
+ | cr.transform(mat); | ||
+ | |||
+ | cr.arc(0, 0, 50, 0, 2*Math.PI); | ||
+ | cr.fill(); | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GBasicShapes(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | In this example, we will create a rectangle, a square, a circle, an arc and an ellipse. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.rectangle(20, 20, 120, 80); | ||
+ | cr.rectangle(180, 20, 80, 80); | ||
+ | cr.fill(); | ||
+ | </source> | ||
+ | |||
+ | These lines draw a rectangle and a square. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.arc(330, 60, 40, 0, 2*Math.PI); | ||
+ | cr.fill(); | ||
+ | </source> | ||
+ | |||
+ | Here the <b>arc()</b> method draws a full circle. | ||
+ | |||
+ | <source lang="java"> | ||
+ | Matrix mat = new Matrix(); | ||
+ | mat.translate(220, 180); | ||
+ | mat.scale(1, 0.7); | ||
+ | cr.transform(mat); | ||
+ | |||
+ | cr.arc(0, 0, 50, 0, 2*Math.PI); | ||
+ | cr.fill(); | ||
+ | |||
+ | </source> | ||
+ | |||
+ | If we want to draw an oval, we do some scaling first. | ||
+ | The <b>scale()</b> method shrinks the y axis. | ||
+ | |||
+ | [[image: Java_Gnome_faq_basicshapes.png| center]] | ||
+ | |||
+ | == Colors == | ||
+ | |||
+ | A color is an object representing a combination of Red, Green, and Blue (RGB) intensity values. | ||
+ | Cairo valid RGB values are in the range 0 to 1. | ||
+ | |||
+ | <source lang="java"> | ||
+ | |||
+ | package com.zetcode; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program draws nine rectangles | ||
+ | * on the drawing area. Each of them | ||
+ | * has different color. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GColors extends Window | ||
+ | implements Widget.ExposeEvent { | ||
+ | |||
+ | public GColors() { | ||
+ | |||
+ | setTitle("Colors"); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | setDefaultSize(350, 280); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | darea.connect(this); | ||
+ | add(darea); | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | final Context cr; | ||
+ | |||
+ | cr = new Context(widget.getWindow()); | ||
+ | drawRectangles(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | |||
+ | public void drawRectangles(Context cr) { | ||
+ | cr.setSource(0.5, 0.65, 0.45); | ||
+ | cr.rectangle(10, 15, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.16, 0.7, 0.9); | ||
+ | cr.rectangle(130, 15, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.274, 0.262, 0.48); | ||
+ | cr.rectangle(250, 15, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.5, 0.39, 0.33); | ||
+ | cr.rectangle(10, 105, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.99, 0.83, 0.24); | ||
+ | cr.rectangle(130, 105, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.95, 0.38, 0.27); | ||
+ | cr.rectangle(250, 105, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.85, 0.57, 0.21); | ||
+ | cr.rectangle(10, 195, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.25, 0.04, 0.73); | ||
+ | cr.rectangle(130, 195, 90, 60); | ||
+ | cr.fill(); | ||
+ | |||
+ | cr.setSource(0.12, 0.08, 0.03); | ||
+ | cr.rectangle(250, 195, 90, 60); | ||
+ | cr.fill(); | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GColors(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | We draw nine rectangles in nine different colors. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.setSource(0.5, 0.65, 0.45); | ||
+ | |||
+ | </source> | ||
+ | |||
+ | The <b>setSource()</b> method sets a color for the cairo context. The three parameters of the method are the color intensity values. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.rectangle(10, 15, 90, 60); | ||
+ | cr.fill(); | ||
+ | </source> | ||
+ | |||
+ | We create a rectangle shape and fill it with the previously specified color. | ||
+ | |||
+ | [[image: Java_Gnome_faq_colors.png| center]] | ||
+ | |||
+ | == Transparent rectangles == | ||
+ | |||
+ | Transparency is the quality of being able to see through a material. | ||
+ | The easiest way to understand transparency is to imagine a piece of glass or water. Technically, the rays of light can go through the glass and this way we can see objects behind the glass. | ||
+ | |||
+ | In computer graphics, we can achieve transparency effects using alpha compositing. Alpha compositing is the process of combining an image with a background to create the appearance of partial transparency. | ||
+ | The composition process uses an alpha channel. (wikipedia.org, answers.com) | ||
+ | |||
+ | <source lang="java"> | ||
+ | package com.zetcode; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program draws ten rectangles | ||
+ | * with different levels of transparency. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GTransparentRectangles extends Window | ||
+ | implements Widget.ExposeEvent { | ||
+ | |||
+ | public GTransparentRectangles() { | ||
+ | setTitle("Transparent Rectangles"); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | setSizeRequest(590, 90); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | add(darea); | ||
+ | darea.connect(this); | ||
+ | } | ||
+ | |||
+ | |||
+ | public void doDrawing(Context cr) { | ||
+ | |||
+ | for (int i = 1; i<=10; i++) { | ||
+ | cr.setSource(0, 0, 1, 0.1*i); | ||
+ | cr.rectangle(50*i, 20, 40, 40); | ||
+ | cr.fill(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | |||
+ | Context cr = new Context(widget.getWindow()); | ||
+ | doDrawing(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GTransparentRectangles(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | In the example we will draw ten rectangles with different levels of transparency. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.setSource(0, 0, 1, 0.1*i); | ||
+ | </source> | ||
+ | |||
+ | The last parameter of the <b>setSource()</b> method is the alpha transparency. | ||
+ | |||
+ | [[image: Java_Gnome_faq_transparency.png| center]] | ||
+ | |||
+ | == Donut == | ||
+ | |||
+ | In the following example we create an complex shape by rotating a bunch of ellipses. | ||
+ | |||
+ | <source lang="java"> | ||
+ | package com.zetcode; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | import org.freedesktop.cairo.Matrix; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program draws a Donut | ||
+ | * shape on the drawing area. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GDonut extends Window | ||
+ | implements Widget.ExposeEvent { | ||
+ | |||
+ | |||
+ | public GDonut() { | ||
+ | |||
+ | setTitle("Donut"); | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | setDefaultSize(300, 260); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | darea.connect(this); | ||
+ | add(darea); | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | final Context cr; | ||
+ | |||
+ | cr = new Context(widget.getWindow()); | ||
+ | drawDonut(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public void drawDonut(Context cr) { | ||
+ | int width = this.getWindow().getWidth(); | ||
+ | int height = this.getWindow().getHeight(); | ||
+ | |||
+ | cr.setLineWidth(0.5); | ||
+ | cr.translate(width/2, height/2); | ||
+ | cr.arc( 0, 0, 120, 0, 2 * Math.PI); | ||
+ | cr.stroke(); | ||
+ | cr.save(); | ||
+ | |||
+ | for ( int i = 0; i < 36; i++) { | ||
+ | Matrix mat = new Matrix(); | ||
+ | mat.rotate(i*Math.PI/36); | ||
+ | mat.scale(0.3, 1); | ||
+ | cr.transform(mat); | ||
+ | cr.arc(0, 0, 120, 0, 2 * Math.PI); | ||
+ | cr.restore(); | ||
+ | cr.stroke(); | ||
+ | cr.save(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GDonut(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | In this example, we create a donut. The shape resembles a cookie, hence the name donut. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.translate(width/2, height/2); | ||
+ | cr.arc( 0, 0, 120, 0, 2 * Math.PI); | ||
+ | cr.stroke(); | ||
+ | </source> | ||
+ | |||
+ | In the beginning there is an ellipse. | ||
+ | |||
+ | <source lang="java"> | ||
+ | Matrix mat = new Matrix(); | ||
+ | mat.rotate(i*Math.PI/36); | ||
+ | mat.scale(0.3, 1); | ||
+ | cr.transform(mat); | ||
+ | cr.arc(0, 0, 120, 0, 2 * Math.PI); | ||
+ | cr.restore(); | ||
+ | cr.stroke(); | ||
+ | cr.save(); | ||
+ | </source> | ||
+ | |||
+ | After several rotations, there is a donut. | ||
+ | |||
+ | [[image: Java_Gnome_faq_donut.jpg| center]] | ||
+ | |||
+ | == Gradients == | ||
+ | |||
+ | In computer graphics, gradient is a smooth blending of shades from light to dark or from one color to another. | ||
+ | In 2D drawing programs and paint programs, gradients are used to create colorful backgrounds and special effects as well as to simulate lights and shadows. (answers.com) | ||
+ | |||
+ | <source lang="java"> | ||
+ | package com.zetcode; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | |||
+ | import org.freedesktop.cairo.LinearPattern; | ||
+ | |||
+ | import org.gnome.gdk.Color; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program draws gradients. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | |||
+ | public class GGradients extends Window implements Widget.ExposeEvent { | ||
+ | |||
+ | public GGradients() { | ||
+ | |||
+ | setTitle("Gradients"); | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | setDefaultSize(340, 390); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | darea.connect(this); | ||
+ | add(darea); | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | final Context cr; | ||
+ | |||
+ | cr = new Context(widget.getWindow()); | ||
+ | drawGradients(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public void drawGradients(Context cr) { | ||
+ | |||
+ | LinearPattern lg1 = new LinearPattern(0.0, 0.0, 350.0, 350.0); | ||
+ | |||
+ | int count = 1; | ||
+ | |||
+ | for (double j=0.1; j<1.0; j+= 0.1) { | ||
+ | if (count % 2 != 0) { | ||
+ | lg1.addColorStopRGB(j, 0, 0, 0); | ||
+ | } else { | ||
+ | lg1.addColorStopRGB(j, 1, 0, 0); | ||
+ | } | ||
+ | count++; | ||
+ | } | ||
+ | |||
+ | cr.rectangle(20, 20, 300, 100); | ||
+ | cr.setSource(lg1); | ||
+ | cr.fill(); | ||
+ | |||
+ | LinearPattern lg2 = new LinearPattern(0.0, 0.0, 350.0, 0); | ||
+ | |||
+ | count = 1; | ||
+ | |||
+ | for (double i=0.05; i<0.95; i+= 0.025) { | ||
+ | if (count % 2 != 0) { | ||
+ | lg2.addColorStopRGB(i, 0, 0, 0); | ||
+ | } else { | ||
+ | lg2.addColorStopRGB(i, 0, 0, 1); | ||
+ | } | ||
+ | count++; | ||
+ | } | ||
+ | |||
+ | cr.rectangle(20, 140, 300, 100); | ||
+ | cr.setSource(lg2); | ||
+ | cr.fill(); | ||
+ | |||
+ | LinearPattern lg3 = new LinearPattern(20.0, 260.0, 20.0, 360.0); | ||
+ | |||
+ | lg3.addColorStopRGB(0.1, 0, 0, 0 ); | ||
+ | lg3.addColorStopRGB(0.5, 1, 1, 0); | ||
+ | lg3.addColorStopRGB(0.9, 0, 0, 0 ); | ||
+ | |||
+ | cr.rectangle(20, 260, 300, 100); | ||
+ | cr.setSource(lg3); | ||
+ | cr.fill(); | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GGradients(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </source> | ||
+ | |||
+ | In our example, we draw three rectangles with three different gradients. | ||
+ | |||
+ | <source lang="java"> | ||
+ | LinearPattern lg1 = new LinearPattern(0.0, 0.0, 350.0, 350.0); | ||
+ | </source> | ||
+ | |||
+ | Here we create a linear gradient pattern. The parameters specify the line, along which we draw the gradient. In our case it is a diagonal line. | ||
+ | |||
+ | <source lang="java"> | ||
+ | LinearPattern lg3 = new LinearPattern(20.0, 260.0, 20.0, 360.0); | ||
+ | lg3.addColorStopRGB(0.1, 0, 0, 0 ); | ||
+ | lg3.addColorStopRGB(0.5, 1, 1, 0); | ||
+ | lg3.addColorStopRGB(0.9, 0, 0, 0 ); | ||
+ | |||
+ | </source> | ||
+ | |||
+ | We define color stops to produce our gradient pattern. In this case, the gradient is a blending of black and yellow colors. By adding two black and one yellow stops, we create a horizontal gradient pattern. What do these stops actually mean? | ||
+ | In our case, we begin with black color, which will stop at 1/10 of the size. | ||
+ | Then we begin to gradually paint in yellow, which will culminate at the centre of the shape. | ||
+ | The yellow color stops at 9/10 of the size, where we begin painting in black again, until the end. | ||
+ | |||
+ | [[image: Java_Gnome_faq_gradients.png| center]] | ||
+ | |||
+ | == Star == | ||
+ | |||
+ | In the following example, we create a moving star. The star moves, rotates and grows/shrinks. | ||
+ | |||
+ | <source lang="java"> | ||
+ | package com.zetcode; | ||
+ | |||
+ | import java.util.Timer; | ||
+ | import java.util.TimerTask; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | import org.freedesktop.cairo.Matrix; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program shows an animated star. Rotate, | ||
+ | * translate and scale operations are | ||
+ | * applied on the star. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GStar extends Window | ||
+ | implements Widget.ExposeEvent { | ||
+ | |||
+ | private static Timer timer; | ||
+ | private int count; | ||
+ | |||
+ | private double angle = 0; | ||
+ | private double scale = 1; | ||
+ | private double delta = 0.01; | ||
+ | |||
+ | double points[][] = { | ||
+ | { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, | ||
+ | { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, | ||
+ | { 40, 190 }, { 50, 125 }, { 0, 85 } | ||
+ | }; | ||
+ | |||
+ | public GStar() { | ||
+ | |||
+ | setTitle("Star"); | ||
+ | |||
+ | timer = new Timer(); | ||
+ | timer.scheduleAtFixedRate(new ScheduleTask(), 100, 20); | ||
+ | count = 0; | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | timer.cancel(); | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | setSizeRequest(350, 250); | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | darea.connect(this); | ||
+ | add(darea); | ||
+ | } | ||
+ | |||
+ | public void drawStar(Context cr) { | ||
+ | |||
+ | int width = this.getWindow().getWidth(); | ||
+ | int height = this.getWindow().getHeight(); | ||
+ | |||
+ | cr.setSource(0, 0.44, 0.7); | ||
+ | cr.setLineWidth(1); | ||
+ | |||
+ | Matrix mat = new Matrix(); | ||
+ | |||
+ | mat.translate(width/2, height/2); | ||
+ | mat.rotate(angle); | ||
+ | mat.scale(scale, scale); | ||
+ | cr.transform(mat); | ||
+ | |||
+ | for ( int i = 0; i < 10; i++ ) { | ||
+ | cr.lineTo(points[i][0], points[i][1]); | ||
+ | } | ||
+ | |||
+ | cr.fill(); | ||
+ | cr.stroke(); | ||
+ | |||
+ | if ( scale < 0.01 ) { | ||
+ | delta = -delta; | ||
+ | } else if (scale > 0.99) { | ||
+ | delta = -delta; | ||
+ | } | ||
+ | |||
+ | scale += delta; | ||
+ | angle += 0.01; | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | |||
+ | Context cr = new Context(widget.getWindow()); | ||
+ | drawStar(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | class ScheduleTask extends TimerTask { | ||
+ | |||
+ | public void run() { | ||
+ | count++; | ||
+ | queueDraw(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GStar(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | We apply translate, scale and rotate operations on a star shape. | ||
+ | |||
+ | <source lang="java"> | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | timer.cancel(); | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | </source> | ||
+ | |||
+ | For a clean exit, we must not forget to stop the timer. Timer is and object of the java util library and is not stopped by the <b> Gtk.mainQuit()</b> method. | ||
+ | |||
+ | <source lang="java"> | ||
+ | double points[][] = { | ||
+ | { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, | ||
+ | { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, | ||
+ | { 40, 190 }, { 50, 125 }, { 0, 85 } | ||
+ | }; | ||
+ | </source> | ||
+ | |||
+ | These points are used to build the star shape. | ||
+ | |||
+ | <source lang="java"> | ||
+ | Matrix mat = new Matrix(); | ||
+ | |||
+ | mat.translate(width/2, height/2); | ||
+ | mat.rotate(angle); | ||
+ | mat.scale(scale, scale); | ||
+ | cr.transform(mat); | ||
+ | </source> | ||
+ | |||
+ | Here we apply the translate, rotate and scale operations on the star shape. | ||
+ | |||
+ | <source lang="java"> | ||
+ | for ( int i = 0; i < 10; i++ ) { | ||
+ | cr.lineTo(points[i][0], points[i][1]); | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | Here we draw the star. | ||
+ | |||
+ | == Waiting == | ||
+ | |||
+ | In this examle, we use transparency effect to create a waiting demo. | ||
+ | We will draw 8 lines that will gradually fade out creating an illusion, that a line is moving. Such effects are often used to inform users, that a lengthy task is going on behind the scenes. | ||
+ | An example is streaming video over the internet. | ||
+ | |||
+ | <source lang="java"> | ||
+ | package com.zetcode; | ||
+ | |||
+ | |||
+ | import java.util.Timer; | ||
+ | import java.util.TimerTask; | ||
+ | |||
+ | import org.freedesktop.cairo.Context; | ||
+ | |||
+ | import org.gnome.gdk.Event; | ||
+ | import org.gnome.gdk.EventExpose; | ||
+ | import org.gnome.gtk.DrawingArea; | ||
+ | import org.gnome.gtk.Gtk; | ||
+ | import org.gnome.gtk.Widget; | ||
+ | import org.gnome.gtk.Window; | ||
+ | import org.gnome.gtk.WindowPosition; | ||
+ | |||
+ | /** | ||
+ | * ZetCode Java Gnome tutorial | ||
+ | * | ||
+ | * This program creates a waiting | ||
+ | * effect. | ||
+ | * | ||
+ | * @author jan bodnar | ||
+ | * website zetcode.com | ||
+ | * last modified March 2009 | ||
+ | */ | ||
+ | |||
+ | public class GWaiting extends Window | ||
+ | implements Widget.ExposeEvent { | ||
+ | |||
+ | private static Timer timer; | ||
+ | private int count; | ||
+ | |||
+ | private final double[][] trs = { | ||
+ | { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 }, | ||
+ | { 1.0, 0.0, 0.15, 0.30, 0.5, 0.65, 0.8, 0.9 }, | ||
+ | { 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65, 0.8 }, | ||
+ | { 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5, 0.65 }, | ||
+ | { 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3, 0.5 }, | ||
+ | { 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15, 0.3 }, | ||
+ | { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, 0.15 }, | ||
+ | { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0, 0.0, } | ||
+ | }; | ||
+ | |||
+ | |||
+ | |||
+ | public GWaiting() { | ||
+ | setPosition(WindowPosition.CENTER); | ||
+ | |||
+ | timer = new Timer(); | ||
+ | timer.scheduleAtFixedRate(new ScheduleTask(), 100, 80); | ||
+ | count = 0; | ||
+ | |||
+ | initUI(); | ||
+ | |||
+ | connect(new Window.DeleteEvent() { | ||
+ | public boolean onDeleteEvent(Widget source, Event event) { | ||
+ | timer.cancel(); | ||
+ | Gtk.mainQuit(); | ||
+ | return false; | ||
+ | } | ||
+ | }); | ||
+ | |||
+ | resize(250, 150); | ||
+ | setTitle("Waiting"); | ||
+ | showAll(); | ||
+ | } | ||
+ | |||
+ | public void initUI() { | ||
+ | DrawingArea darea = new DrawingArea(); | ||
+ | add(darea); | ||
+ | darea.connect(this); | ||
+ | } | ||
+ | |||
+ | public boolean onExposeEvent(Widget widget, EventExpose eventExpose) { | ||
+ | |||
+ | Context cr = new Context(widget.getWindow()); | ||
+ | drawWaiting(cr); | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | private void drawWaiting(Context cr) { | ||
+ | int w = this.getWidth(); | ||
+ | int h = this.getHeight(); | ||
+ | |||
+ | cr.translate(w/2, h/2); | ||
+ | |||
+ | for (int i = 0; i < 8; i++) { | ||
+ | |||
+ | cr.setLineWidth(3); | ||
+ | cr.setSource(0, 0, 0, trs[count%8][i]); | ||
+ | |||
+ | cr.moveTo(0, -10); | ||
+ | cr.lineTo(0, -40); | ||
+ | cr.rotate(Math.PI/4f); | ||
+ | cr.stroke(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class ScheduleTask extends TimerTask { | ||
+ | |||
+ | public void run() { | ||
+ | count++; | ||
+ | queueDraw(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public static void main(String[] args) { | ||
+ | Gtk.init(args); | ||
+ | new GWaiting(); | ||
+ | Gtk.main(); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | </source> | ||
+ | |||
+ | We draw eight lines with eight different alpha values. | ||
+ | |||
+ | <source lang="java"> | ||
+ | private final double[][] trs = { | ||
+ | { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 }, | ||
+ | .... | ||
+ | }; | ||
+ | </source> | ||
+ | |||
+ | This is a two dimensional array of transparency values used in this demo. | ||
+ | There are 8 rows, each for one state. Each of the 8 lines will continuosly use these values. | ||
+ | |||
+ | <source lang="java"> | ||
+ | |||
+ | cr.setLineWidth(3); | ||
+ | </source> | ||
+ | |||
+ | We make the lines a bit thicker, so that they are better visible. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.setSource(0, 0, 0, trs[count%8][i]); | ||
+ | </source> | ||
+ | |||
+ | Here we define the transparency value for a line. | ||
+ | |||
+ | <source lang="java"> | ||
+ | cr.moveTo(0, -10); | ||
+ | cr.lineTo(0, -40); | ||
+ | cr.rotate(Math.PI/4f); | ||
+ | cr.stroke(); | ||
+ | </source> | ||
+ | |||
+ | These code lines will draw each of the eight lines. | ||
+ | |||
+ | [[image: Java_Gnome_faq_waiting.png| center]] | ||
+ | |||
+ | [[Категория:GTK+]] | ||
+ | [[Категория:Java]] |