JUCE_MODAL_LOOPS_PERMITTEDがデフォルトで0になる(すでになったかも)。これが意味するところは、AlertWindowを下記のように使っていたコードは全部エラーになるということ…。
auto result = AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
"Write a program",
"Are you sure to overwrite?");
if (result)
{
// Okだった場合の処理
}
なぜなら、
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()の返り値を使っての処理ができなくなる。今後は、
AlertWindow::showOkCancelBox (AlertWindow::NoIcon,
"Write a program",
"Are you sure to overwrite?",
String(),
String(),
nullptr,
ModalCallbackFunction::create([](int result){
if (result)
{
// Okだった場合の処理
}
}));
のように書く必要がある。上記はラムダ式を使って書いてるけど、静的メンバ関数を定義しても良い。ただし、いちいち定義がめんどくさいし、メンバ変数を使いたかったりするとめんどくさいのでラムダ式が良いかと。JUCEのDemorunnerでは静的メンバ関数になってるけど。自動変数を使いたい場合は[]の中に書いておけばいい。
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を書いておく。
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()はメンバ関数
}
}));
実際多いのは下記のように両方使う場合かも。
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にある。
class Home
{
// <-- snip -->
private:
std::unique_ptr<FileChooser> fileChooser;
}
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);
});