メインコンテンツまでスキップ

チュートリアル:メインコンポーネント

このチュートリアルでは、メイン・コンテンツ・コンポーネントを作成することによって、アプリケーション・ウィンドウにグラフィカル・コンテンツを追加する方法を説明します。これは、ウィンドウ内でユーザーにコンテンツを表示するために重要です。

レベル:初級

プラットフォーム:Windows, macOS, Linux

クラス: ドキュメントウィンドウ, コンポーネント, グラフィック

はじめる

Launch the Projucer and create a new GUI application project with the name メインコンポーネントチュートリアル. In the 自動生成するファイル: field make sure you select Main.cppファイルのみを作成する.

If you need help with this step, see チュートリアルProjucerパート1:Projucerを始める.

Modify the メインコンポーネントチュートリアルアプリケーション class to include the following メインウィンドウ class as follows:

//==============================================================================
class MainComponentTutorialApplication : public juce::JUCEApplication
{
public:
//...

//==============================================================================
class MainWindow : public juce::DocumentWindow
{
public:
MainWindow (juce::String name) : DocumentWindow (name,
juce::Colours::lightgrey,
DocumentWindow::allButtons)
{
setUsingNativeTitleBar (true);
centreWithSize (300, 200);
setVisible (true);
}

void closeButtonPressed() override
{
JUCEApplication::getInstance()->systemRequestedQuit();
}

private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
};

private:
std::unique_ptrメインウィンドウ
};
DocumentWindow タイトルバーと、最大化、最小化、閉じるボタンを持つ、サイズ変更可能なウィンドウ。
JUCEApplication::getInstancestatic JUCEApplication *JUCE_CALLTYPE getInstance() noexcept実行中のアプリケーションオブジェクトのグローバルインスタンスを返します。
JUCEApplication::systemRequestedQuitvoid systemRequestedQuit() overrideオペレーティングシステムがアプリケーションを閉じようとしているときに呼び出される。
nameint UnityEventModifiers const char * nameDefinition juce_UnityPluginInterface.h:195
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)This is a shorthand way of writing a both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...Definition juce_PlatformDefs.h:245
ColoursContains a set of predefined named colours (mostly standard HTML colours)定義 juce_Colours.h:37
定義 juce_AudioWorkgroup_mac.h:24

Add the following line to the イニシャライズ() function:

void initialise (const juce::String& commandLine) override
{
mainWindow.reset (new MainWindow (getApplicationName()));
}

Finally, add the following line to the シャットダウン function:

void shutdown() override
{
mainWindow = nullptr;
}

Introduction

In the last tutorial (チュートリアルアプリケーション・ウィンドウ), we covered the main window, which serves as the frame in which the application's graphical interface lives. In this tutorial, we will create a メインコンテンツコンポーネント, which is the object that shows the 内容 of the app's interface. The main content component is an essential object for every JUCE app.

If you create a new GUI application with プロジューサー, it will automatically generate a main content component for you. However, a good way to familiarise yourself with the concept and to understand how JUCE apps are structured is to create such a main content component yourself. This is what we will do in this tutorial.

Open the tutorial project in your IDE. We take off at the same point we arrived in the last tutorial: with an empty application window. In the メイン.cpp file, we have a メインウィンドウ class. We already learned how to use it in the last tutorial (チュートリアルアプリケーション・ウィンドウ). Now, we will fill this window with content!

However, before we can do that, let's first explore the concept of a コンポーネント a little bit further.

The Component class

The most important base class for all JUCE graphical interfaces is the コンポーネント class. In JUCE, practically all visible elements of the GUI, be it buttons, sliders, or text fields, are コンポーネント, deriving from this class. The way to write such an app in JUCE is to create a 主成分, which is owned by the main application window and is the window's 内容. All other components will then be 子供たち of this main component (see チュートリアル親子コンポーネント). The ドキュメントウィンドウ class, from which our メインウィンドウ derives, contains the necessary functionality to make sure the main window shows its content correctly (including the main component and its children).

注記

Remember: all graphical elements in JUCE derive from the コンポーネント class. To build a GUI, different components are arranged in a nested hierarchy with and 子供 components. The top-most component is called the メインコンテンツコンポーネント. See チュートリアル親子コンポーネント for more detail.

Adding a main component class

Creating new source files

Now, let's create our main component class. For this, we need to create new files where the source code for this class will go. Go back to プロジューサー and open the tutorial project there. At the left, make sure that the ファイル browser is open. Then, right-click on the ソース group (that's the file group where new C++ source files should always go) and select 新しいコンポーネントクラスを追加(CPPとヘッダーに分割).... プロジューサー will ask you how to name the new コンポーネント subclass. In the dialog, enter メインコンポーネント and click on ファイル作成. You will see that プロジューサー has created two new files: メインコンポーネント.cpp and メインコンポーネント.h. Now, save the project and open it again in your IDE. You should now see the new files there as well. プロジューサー has automatically created some code for the new component class, which we will examine in the next section.

Adding a new component class in The Projucer.
Adding a new component class in The Projucer.
注記

Remember: If you create new classes, they should go into their own files, with the file names matching the class names. Always use プロジューサー to create new files; never do so from your IDE (プロジューサー would overwrite such changes the next time you save your project).

A new component class

As you can see, プロジューサー automatically derived the new class from the コンポーネント class and added the following class declaration:

class MainComponent : public juce::Component
{
public:
MainComponent();
~MainComponent();

void paint (juce::Graphics&) override;
void resized() オーバーライド;

private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent).
};

The コンポーネント base class has two important virtual member functions that should be overridden in any class deriving from it. プロジューサー already created these two overrides for you:

  • Component::paint(): このメンバ関数は、コンポーネントがどのように画面に描画されるかを決定します。
  • Component::resized():このメンバ関数は、コンポーネントがリサイズされたときに何が起こるかを決定する。
注記

Always add the keyword オーバーライド to all functions in a class that should override a function from a base class. This prevents unexpected errors in your app, and is part of the JUCEコーディング標準.

Implementing the paint function

The ペイント function determines how the コンポーネント object is rendered on the screen. This is where we add a custom appearance to our メインコンポーネント class.

プロジューサー has automatically added some demo code. Let's put some code of our own into the ペイント function.

void MainComponent::paint (juce::Graphics& g)
{
g.fillAll (juce::Colours::lightblue);

g.setColour (juce::Colours::darkblue);
g.setFont (20.0f);
g.drawText ("Hello, World!", getLocalBounds(), juce::Justification::centred, true);
}

We don't have to go into the details of this code too much. We will learn more about the functions used here (and more) in the next tutorial: チュートリアルGraphicsクラス. For now, you can probably guess that this demo code fills the component with a light blue background, and then renders the text ハロー、ワールド! in a blue font in the centre of the component. The point here is that all the code that determines how the メインコンポーネント object should look goes right here inside the ペイント function.

Make the main component visible

では、コードをコンパイルして実行してください。青い背景とテキストの代わりに、空のアプリケーション・ウィンドウが表示されるだけです。なぜでしょうか?

Well, we did not tell the メインウィンドウ object that it should now show some content. First of all we need to include the header so that the メインウィンドウ class knows about the メインコンポーネント class. Add the folowing include at the top of the メイン.cpp file, underneath the already existing include:

#include "MainComponent.h"

The next step is to create a メインコンポーネント object and to add it as the 内容 of the main window. We can do that by calling the DocumentWindow::setContentOwned() function.

注記

"Owned" means that the メインウィンドウ object is now responsible for the lifetime of メインコンポーネント object and will destroy it automatically when its own destructor is called.

Add the following line to the constructor of the メインウィンドウ class:

setContentOwned (new MainComponent(), true);

such that the メインウィンドウ constructor looks like this:

MainWindow (juce::String name) : DocumentWindow (name、
juce::Colours::lightgrey、
DocumentWindow::allButtons)
{
setUsingNativeTitleBar (true);
setContentOwned (new MainComponent(), true);
centerWithSize (getWidth(), getHeight());
setVisible (true);
}

Note that we changed one other detail: the arguments to the Component::centreWithSize() function have changed as well. We now don't explicitly set the size of the メインウィンドウ object anymore, but tell it to figure out its size based on its content:

centerWithSize (getWidth(), getHeight());

However, for this to work, the メインコンポーネント object needs to have its size set before the centerWithSize() function call happens. If this isn't done then the main window won't know what window size is appropriate (this will trigger an assertion failure if you run it). The next section explains how to accomplish this.

Setting the component's size

In principle, there are two ways to set the size of a コンポーネント object. Either you set the size in the constructor of the component itself, or you set the size in the constructor of its parent component. For the main component, we usually set the size in the component itself. Add the following line to the constructor of our メインコンポーネント class:

setSize (400, 300);

(もちろん、他のサイズを選ぶこともできる)。

警告

覚えておいてください: コンポーネントのサイズは必ず設定してください。このステップを省略することは、JUCEのバグの非常に一般的な原因です。

This is the reason why the calls to functions Component::getWidth() and Component::getHeight() in the メインウィンドウ class can figure out the size of the window so that the main component is displayed with the correct size. The メインコンポーネント object's size gets set in its own constructor, before the メインウィンドウ object is positioned and sized.

これで必要なパーツはすべて揃った。アプリをコンパイルして実行すると、メイン・コンポーネントがアプリケーション・ウィンドウに正しく描画されているのが見えるはずだ:

The new MainComponent object is rendered on the screen.
The new MainComponent object is rendered on the screen.

Find out what the second argument of the setContentOwned() function means (which we set to 真の here) and how it behaves if you change it. Hint: check out the documentation for the ResizableWindow::setContentOwned() function.

Implement a resize function

Now that we have covered the ペイント function, let's move on and see how we can make the メインコンポーネント class react to being resized.

First of all, we need to tell the main window that it should be resizable. Please refer to チュートリアルアプリケーション・ウィンドウ if you don't remember how to do that.

Now, compile and run the app, and resize the window using the mouse. You will see that the メインコンポーネント object resizes itself to fit the size of the main window — all the necessary code to do that is already implemented for you in the コンポーネント base class.

しかし、コンポーネントのサイズが変更されるたびに、カスタム作業を行いたい場合はどうでしょうか?もしかしたら、子コンポーネントがあり、メインコンポーネントのサイズによってレイアウトを変える必要があるかもしれません。この単純なデモアプリでは、メイン・コンポーネント内のテキストを変更し、コンポーネントの現在のサイズを表示するようにしてみましょう。

Anything that needs to be done or updated when we need to resize our component goes into our component's リサイズ function. Currently, the function is empty. Let's add our functionality here.

警告

Component::resized()関数は、コンポーネントのサイズ変更につながる何かが起こるたびに自動的に呼び出されます。決して自分でこの関数を呼び出してはいけません!

The text that is displayed inside the component is currently given as a literal string — "Hello, World!" — inside the ペイント function. Let's change that by introducing a new member variable to the メインコンポーネント class. It is good practice to always give your variables descriptive, intention-revealing names. This makes the code easier to read and understand, and reduces the amount of additional code comments. We want our new variable to represent the current size of the main component as a string, so let's call it カレントサイズ.

メンバ変数は常にクラスのprivateセクションで宣言される:

class MainComponent : public juce::Component
{
// ...

private:
juce::String currentSizeAsString;
// ...
};

Now let's implement the desired behaviour for the カレントサイズ object. There are two things to do:

  • The contents of the カレントサイズ object should be rendered on screen.
  • The カレントサイズ object should update itself whenever the main component's size changes.

How we achieve the first part should be fairly simple: inside the ペイント function, when the g.drawText() function is called, simply replace the literal string there with the カレントサイズ object:

void MainComponent::paint (juce::Graphics& g)
{
//...
g.drawText (currentSizeAsString, getLocalBounds(), juce::Justification::centred, true);
}

The second part is more interesting. We already know that every time we resize that the リサイズ function is called. So let's update the value of the カレントサイズ object there:

void MainComponent::resized()
{
currentSizeAsString = juce::String (getWidth()) + " x " + juce::String (getHeight());
}

Component::getWidth() and Component::getHeight() are convenient functions that let you query the current size of the component. We also need to convert these integers to ストリング objects. (You can find out more about how to work with the ストリング class in a future tutorial.)

今アプリをコンパイルして実行すると、常に現在のサイズが表示されることがわかるだろう:

The finished demo app.
The finished demo app.

We can make two interesting observations here. First, the display is automatically updated — the ペイント function is called automatically after the リサイズ function is called. Second, the size is already shown correctly when the app starts up, even before you first resize the window yourself. Remember that the リサイズ function is always called whenever 何でも changes the component's size. This includes the first time the component's size is set and the component is painted after the app launched.

Modify the MainComponent::resize() function in such a way that on every resize, the メインコンポーネント object also changes its background colour.

You can download a finished version of the tutorial project here: ピップ | ジップ and compare it to your own.

概要

This tutorial explained the concept of a main component, how to add one to your app, and how to implement the ペイント and リサイズ functions. After reading this tutorial, you should be familiar with the following important things:

  • すべてのJUCEアプリケーション・ウィンドウには、メイン・コンポーネントがあります。これは、アプリのGUIを構成する他のすべてのコンポーネントの親となります。
  • Every component, including the main component, has two important functions that you need to override: ペイント and リサイズ.
  • In the ペイント function, you should add the code that will render the component on the screen.
  • You should implement a リサイズ function if you need special behaviour for your component, in order for it to react to size changes.
  • The ペイント and リサイズ functions are コールバック functions that are called automatically when needed.
  • メイン・コンポーネントのサイズを設定し、メイン・ウィンドウに追加して表示させることを忘れてはならない。

関連項目