チュートリアル:Graphicsクラス
This tutorial shows how to use a グラフィック object to draw text, lines, and geometric shapes. This is fundamental to performing drawing in JUCE.
レベル:初級
プラットフォーム:Windows, macOS, Linux, iOS, Android
クラス: コンポーネント, グラフィック, フォント, カラー, パス
はじめる
Download the demo project for this tutorial here: ピップ | ジップ
The demo project
The demo project for this tutorial contains a main application window and a main component. You should be familiar with these from the last tutorials: チュートリアルアプリケーション・ウィンドウ and チュートリアルメイン・コンポーネント.
You already know that the appearance of the main component (or, as a matter of fact, any other Component!) is determined by the implementation of its ペイント
function. The demo project here takes off where the last tutorial (チュートリアルメイン・コンポーネント) concluded. The implementation of the ペイント
function initially looks as follows:
void paint (juce::Graphics& g)
{
g.fillAll (juce::Colours::lightblue);
g.setColour (juce::Colours::darkblue);
g.setFont (14.0f);
g.drawText ("Hello, World!", getLocalBounds(), juce::Justification::centred, true);
}
If you compile and run the app now, you should see that the window now has a light blue background colour, and the text ハロー、ワールド! is drawn on top of it, in the centre of the window.
In the following, we will add some code that draws some more graphics into the メインコンポーネント
object, using the グラフィック class. This is a very powerful class, and we will be using it a lot in future tutorials to implement the custom visual appearance of different JUCE components.
The Graphics class
Let's have another look at the paint function. Remember that the ペイント
function is a callback called by the operating system when it is time to render your コンポーネント on screen — you should never call this function yourself.
Notice that as the argument to this callback, a reference to a グラフィック instance is passed in. This グラフィック object is provided by the underlying framework. It is the graphics context that you can use to render any graphical elements: text, lines, shapes, colours, gradients and much more. We will explore some of these in this tutorial.
The グラフィック class is usually only used in the ペイント
callback. Normally, you should never use it anywhere else unless when drawing onto an image.
Rendering text
Setting the font
まずはテキストの続きから。行
g.setFont(20.0f);
sets the font size to 20 pixels for the subsequent line (which draws the text ハロー、ワールド! using that font). But what if we want to not only change the size of the font, but also use another typeface and bold or italic letters? And how do we change the position of the text?
There is actually another version of the Graphics::setFont() function that takes a フォント object instead of just a フロート
that determines the size. You can create a new フォント object like this:
juce::Font mainComponentFont ("Times New Roman", 20.0f, juce::Font::italic);
Because we are using this font for our main component, we choose the descriptive variable name メインコンポーネントフォント
.
The first argument of the フォント constructor determines the typeface, the second is the font size, and the third is the font style. Here, we chose italic for the style. The font styles are actually flags that can be used as a bitmask (see チュートリアルアプリケーション・ウィンドウ), so you can combine them for example like this:
juce::Font mainComponentFont ("Times New Roman", 20.0f, juce::Font::bold | juce::Font::italic);
アプリを再度コンパイルして実行すると、フォントが変更されていることが確認できるはずだ。
コンピュータに実際にインストールされていない書体を使用することは、JUCEアプリでフォントが正しく動作しない非常に一般的な原因です。
Instead of creating a named フォント object and then setting it with the Graphics::setFont() function on the next line, you could also do both in one statement:
g.setFont (juce::Font ("Times New Roman", 20.0f, juce::Font::italic));
とはいえ、通常はステートメントを分離して名前付き変数を使った方が、コードの可読性と保守性は向上する。(最近のコンパイラーでは、このような追加変数を導入してもパフォーマンスには影響しません)。
Setting the position
ここで、テキストの位置を変更します。その過程で、JUCEで位置決めがどのように処理されるかを学びます。
The easy way would be to simply change the alignment of the text with respect to the whole component, for example by changing the ジャスティフィケーション::中央揃え value to another one of the possible values, for example the ジャスティフィケーション::左上 value. (You can also check out the other possible ジャスティフィケーション::フラグ values.) However, another very powerful approach is to explicitly define the size and position. There is another version of the Graphics::drawText() function using this approach. Change the line starting with the g.drawText()
call to the following:
g.drawText ("Hello, World!", 20, 40, 200, 40, juce::Justification::centred, true);
This tells the グラフィック object to render the text into an area that is 200 pixels wide, 40 pixels high, and located 20 pixels to the right and 40 pixels to the bottom from the top-left corner of the main component.
アプリはこのようになるはずだ:
Remember: coordinates in JUCE are always measured from the top-left corner of the current component, which is the point (0, 0). They can be given as イント
or フロート
numbers. When used to specify the position of a graphical element or child component, it will be positioned such that its top left corner will appear at the given position.
Finally, the last argument of the Graphics::drawText() function is a ブール
flag which determines whether an ellipsis (...) should be shown if the text does not fit within the given width, or whether the text should be simply chopped off.
テキスト・フィールドの幅を200から小さい値に変更し、省略フラグがどのように機能するかに注目してください。
The Graphics::drawText() function is good for rendering single-line text. For multi-line text, it offers other functions such as Graphics::drawMultiLineText() and Graphics::drawFittedText().
Rendering geometrical shapes
In this section, we continue with drawing some geometrical shapes using the グラフィック class.
Drawing lines
Add the following lines to the bottom of the ペイント
function:
g.setColour (juce::Colours::green);
g.drawLine (10, 300, 590, 300, 5);
This will draw a green horizontal line 5 pixels wide across the window, starting from (10, 300) and ending at (590, 300). Note that every time you want to draw a geometric shape in another colour than the one used last time, you have to call the Graphics::setColour() function before you draw.
You can of course also draw diagonal lines by specifying other coordinates. In fact, JUCE also supports subpixel coordinates (you can use フロート
values for the positions). If the position falls between physical screen pixels, JUCE will apply anti-aliasing for the drawing.
Explore other types of lines. Can you figure out how to draw dashed lines, or arrows? Hint: have a look at the グラフィック class documentation.
Drawing rectangles
Drawing rectangles using the グラフィック object is quite straightforward. Add the following line to the ペイント
function body:
g.setColour (juce::Colours::sandybrown);
g.drawRect (300, 120, 200, 170);
This will render a brown rectangle, 200 pixels wide, 170 pixels high, positioned with its top-left corner at the position (300, 120).
オプションの第5引数で線の太さを指定できる:
g.setColour (juce::Colours::sandybrown);
g.drawRect (300, 120, 200, 170, 3);
If you want a filled rectangle, use the function Graphics::fillRect() instead:
g.setColour (juce::Colours::sandybrown);
g.fillRect (300, 120, 200, 170);
Instead of giving the position, width, and height separately, there is a more convenient class to represent a rectangle: the 長方形 class. There is also a version of the Graphics::drawRect() function that takes such a 長方形 instance to specify the position of the rectangle:
juce::Rectangle家 (300, 120, 200, 170);
g.setColour (juce::Colours::sandybrown);
g.fillRect (house);
This very convenient 長方形 class will be explored in a future tutorial.
Find out how to draw a どっしり rectangle. Next, also try to draw a 充填 rounded rectangle.
矩形を無地で塗りつぶす必要はありません。色のグラデーションや他のいくつかのパターンのいずれかを使用することもできます。茶色の長方形が家を表しているとしましょう。市松模様で塗りつぶすことで、レンガのような質感を加えることができます。次のコードで長方形を描画します:
juce::Rectanglehouse (300, 120, 200, 170);
g.fillCheckerBoard (house, 30, 10, juce::Colours::sandybrown, juce::Colours::saddlebrown);
今、アプリケーションをコンパイルして実行すると、以下のようになるはずだ:
Drawing circles
Let's see how the グラフィック class draws circles and ellipses. Have a look at the functions Graphics::drawEllipse() and Graphics::fillEllipse(). They work just like the Graphics::drawRect() and Graphics::fillRect() functions.
小さな風景に太陽を加えてみよう。次のコードは、ウィンドウの右上に60ピクセルの円を描く:
g.setColour (juce::Colours::yellow);
g.drawEllipse (530, 10, 60, 60, 3);
Note that the position given (530, 10) does ない place the centre of the circle at that position. Instead, as with all other graphical elements, the object will be placed such that the top-left corner of its enclosing rectangle will be located at the given position.
例えば、コンポーネントの境界を明示的に使って位置を計算することもできる:
g.setColour (juce::Colours::yellow);
g.drawEllipse (getWidth() - 70, 10, 60, 60, 3);
Write a wrapper function around the Graphics::drawEllipse() function for drawing circles more conveniently. The function should take the coordinates of a point and a radius, and then draw a circle with the centre at this point and the given radius.
Drawing other polygons
最後に、家に屋根をつけよう。これは赤い三角形になる。
You will find out that there is no function called drawTriangle()
or drawPolygon()
in the グラフィック class. For this, we have to take a more generic approach.
Check out the パス class. It essentially handles any sets of connected points. In this case, we need a triangle that comprises three points. For example, we could use the three points (300, 110), (500, 110), (400, 70) so that the roof triangle sits on top of the house rectangle.
これがJUCEコードで私たちの赤い屋根がどのように見えるかだ:
g.setColour (juce::Colours::red);
パス屋根;
roof.addTriangle (300, 110, 500, 110, 400, 70);
g.fillPath (roof);
定義 juce_Path.h:68
Path::addTrianglelevoid addTriangle(float x1, float y1, float x2, float y2, float x3, float y3)パスに三角形を追加します。