💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# Cario 绘图 II > 原文: [http://zetcode.com/gui/javagnome/drawingII/](http://zetcode.com/gui/javagnome/drawingII/) 在 Java Gnome 编程教程的这一部分中,我们将继续使用 Cairo 库进行绘制。 ## 甜甜圈 在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。 `donut.java` ```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(); } } ``` 在此示例中,我们创建一个甜甜圈。 形状类似于曲奇,因此得名“甜甜圈”。 ```java cr.translate(width/2, height/2); cr.arc( 0, 0, 120, 0, 2 * Math.PI); cr.stroke(); ``` 刚开始时有一个椭圆。 ```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(); ``` 旋转几圈后,有一个甜甜圈。 ![Donut](https://img.kancloud.cn/b4/e2/b4e2dbe591fdac454c899474feb7eebe_306x285.jpg) 图:多纳圈 ## 渐变 在计算机图形学中,渐变是从浅到深或从一种颜色到另一种颜色的阴影的平滑混合。 在 2D 绘图程序和绘图程序中,渐变用于创建彩色背景和特殊效果以及模拟灯光和阴影。 (answers.com) `gradients.java` ```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(); } } ``` 在我们的示例中,我们绘制了三个具有三个不同渐变的矩形。 ```java LinearPattern lg1 = new LinearPattern(0.0, 0.0, 350.0, 350.0); ``` 在这里,我们创建一个线性渐变图案。 参数指定直线,沿着该直线绘制渐变。 在我们的情况下,它是一条对角线。 ```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 ); ``` 我们定义色标以产生渐变图案。 在这种情况下,渐变是黑色和黄色的混合。 通过添加两个黑色和一个黄色色标,我们创建了一个水平渐变图案。 这些停止实际上是什么意思? 在我们的情况下,我们从黑色开始,该颜色将以大小的 1/10 停止。 然后,我们开始逐渐涂成黄色,最终达到形状的中心。 黄色停在大小的 9/10,我们再次开始用黑色绘图,直到结束。 ![Gradients](https://img.kancloud.cn/bc/b4/bcb4998b07e2a6b418840cb909affead_346x415.jpg) 图:渐变 ## 星形 在下面的示例中,我们创建了一颗移动的星星。星星移动,旋转并成长/收缩。 `star.java` ```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(); } } ``` 我们对星形应用平移,缩放和旋转操作。 ```java public boolean onDeleteEvent(Widget source, Event event) { timer.cancel(); Gtk.mainQuit(); return false; } ``` 为了干净出口,我们一定不要忘记停止计时器。 `Timer`是 Java `util`库的对象,并且不被`Gtk.mainQuit()`方法停止。 ```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 } }; ``` 这些点用于构建星形。 ```java Matrix mat = new Matrix(); mat.translate(width/2, height/2); mat.rotate(angle); mat.scale(scale, scale); cr.transform(mat); ``` 在这里,我们对星形应用平移,旋转和缩放操作。 ```java for ( int i = 0; i < 10; i++ ) { cr.lineTo(points[i][0], points[i][1]); } ``` 在这里,我们画星星。 ## 等待 在此示例中,我们使用透明效果创建一个等待演示。 我们将绘制 8 条线,这些线将逐渐消失,从而产生一条线在移动的错觉。 这种效果通常用于通知用户,一项艰巨的任务正在幕后进行。 一个示例是通过互联网流式传输视频。 `waiting.java` ```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(); } } ``` 我们用八个不同的 alpha 值绘制八条线。 ```java private final double[][] trs = { { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 }, .... }; ``` 这是此演示中使用的透明度值的二维数组。 有 8 行,每行一种状态。 8 行中的每行将连续使用这些值。 ```java cr.setLineWidth(3); ``` 我们使线条更粗一些,以便更好地显示它们。 ```java cr.setSource(0, 0, 0, trs[count%8][i]); ``` 在这里,我们定义了一条线的透明度值。 ```java cr.moveTo(0, -10); cr.lineTo(0, -40); cr.rotate(Math.PI/4f); cr.stroke(); ``` 这些代码行将绘制八行中的每行。 ![Waiting](https://img.kancloud.cn/72/bd/72bda4dbfe7083101206c2c767785bd3_256x175.jpg) 图:等待 在 Java Gnome 编程库的这一章中,我们使用 Cairo 库进行了一些更高级的绘制。