2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

JUCEのAlertWindowをAsyncで使う

Last updated at Posted at 2021-08-10

JUCE_MODAL_LOOPS_PERMITTEDがデフォルトで0になる(すでになったかも)。これが意味するところは、AlertWindowを下記のように使っていたコードは全部エラーになるということ…。

hoge.cpp
    auto result = AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
                                               "Write a program",
                                               "Are you sure to overwrite?");
    if (result)
    {
        // Okだった場合の処理
    }

なぜなら、

juce_AlertWindow.h
    static bool JUCE_CALLTYPE showOkCancelBox (MessageBoxIconType iconType,
                                               const String& title,
                                               const String& message,
                                              #if JUCE_MODAL_LOOPS_PERMITTED
                                               const String& button1Text = String(),
                                               const String& button2Text = String(),
                                               Component* associatedComponent = nullptr,
                                               ModalComponentManager::Callback* callback = nullptr);
                                              #else
                                               const String& button1Text,
                                               const String& button2Text,
                                               Component* associatedComponent,
                                               ModalComponentManager::Callback* callback);
                                              #endif

というように第3引数以降もデフォルト値が定義されていないから。かつ、Async実行になるのでshowOkCancelBox()の返り値を使っての処理ができなくなる。今後は、

hoge.cpp
    AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
                                  "Write a program",
                                  "Are you sure to overwrite?",
                                  String(),
                                  String(),
                                  nullptr,
                                  ModalCallbackFunction::create([](int result){
        if (result)
        {
            // Okだった場合の処理
        }
    }));

のように書く必要がある。上記はラムダ式を使って書いてるけど、静的メンバ関数を定義しても良い。ただし、いちいち定義がめんどくさいし、メンバ変数を使いたかったりするとめんどくさいのでラムダ式が良いかと。JUCEのDemorunnerでは静的メンバ関数になってるけど。自動変数を使いたい場合は[]の中に書いておけばいい。

hoge.cpp
    int a = 10;
    AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
                                  "Write a program",
                                  "Are you sure to overwrite?",
                                  String(),
                                  String(),
                                  nullptr,
                                  ModalCallbackFunction::create([a](int result){
        if (result)
        {
            // Okだった場合の処理
            printf ("%d\n", a);
        }
    }));

メンバ関数を呼び出したい場合は[]の中にthisを書いておく。

hoge.cpp
    AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
                                  "Write a program",
                                  "Are you sure to overwrite?",
                                  String(),
                                  String(),
                                  nullptr,
                                  ModalCallbackFunction::create([this](int result){
        if (result)
        {
            // Okだった場合の処理
            foo(); // foo()はメンバ関数
        }
    }));

実際多いのは下記のように両方使う場合かも。

hoge.cpp
    int a = 10;
    AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
                                  "Write a program",
                                  "Are you sure to overwrite?",
                                  String(),
                                  String(),
                                  nullptr,
                                  ModalCallbackFunction::create([this, a](int result){
        if (result)
        {
            // Okだった場合の処理
            foo(a); // foo()はメンバ関数
        }
    }));

JUCE_MODAL_LOOPS_PERMITTEDのデフォルトが変わった背景は、Androidではモーダル処理が許可されていないことにあるらしい。なので、Androidでも動くコードを書くにはこの対応が必須らしい。

AlertWindowだけでなくFileChooserもほぼ同様。ただし、ModalCallbackFunction::create()を使わずにラムダ式を書けば良い様子。AlertWindowのうちMessageBoxは特に何も処理しないのであればコールバック指定なしに使えるが、メンバ関数がAsync専用のAlertWindow::showMessageBoxAsync()になる。FileChooserのインスタンスはクラスのメンバ変数として保持しておくなどの必要あり(めんどくさい…)。場合によっては(?)、thisもSafePointerを使って安全に使えるようにするべきっぽい。もっと良い例は
DemoRunnerにある。

hoge.h
class Home
{
//  <-- snip -->
private:
    std::unique_ptr<FileChooser> fileChooser;
}

hoge.cpp
    SafePointer<Hoge> safeThis (this);
    static const char* fileExt = ".txt";
    auto fileToSave = File::createTempFile ("temp");

    fileChooser.reset (new FileChooser ("Choose a location to save...",
                                        File::getCurrentWorkingDirectory().getChildFile (fileToSave.getFileName()),
                                        String("*") + fileExt, true));
    fileChooser->launchAsync(FileBrowserComponent::saveMode | FileBrowserComponent::canSelectFiles,
                             [safeThis, fileToSave] (const FileChooser& fc)
    {
        auto result = fc.getURLResult();
        if (! result.isEmpty())
        {
            std::unique_ptr<InputStream>  wi (fileToSave.createInputStream());
            std::unique_ptr<OutputStream> wo (result.createOutputStream());
            
            if (wi.get() != nullptr && wo.get() != nullptr)
            {
                auto numWritten = wo->writeFromInputStream (*wi, -1);
                if (numWritten == 0)
                {
                    AlertWindow::showMessageBoxAsync (AlertWindow::InfoIcon,
                                                      "Failed to save file",
                                                      "Failed to create presets backup.");
                }
                ignoreUnused (numWritten);
                wo->flush();
            }
        }
        bool removed = fileToSave.deleteFile();
        jassert(removed);
        ignoreUnused(removed);
    });
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?