Update BStringView text from a thread or an alarm

Hello,

I face a big problem in my program to update the text in a BStringView inside a function executed from a thread or a signal alarm.

This function is to display a countdown for a timeout while the application can be accessed to write text or click on the buttons. So this countdown is not a sleep() that freezes the application.
It’s like an exam to continue to the next question if the student does not reply to the current question fast enough.

Here is the structure I use:


const uint32 kAnswer=‘btc1’;

class MyClass : public BWindow {

private:
	BStringView *Countdown;

public:
MyClass(BRect frame)
	: BWindow(frame,"",B_TITLED_WINDOW,B_BORDERED_WINDOW_LOOK) {
	Archive(new BMessage(kAnswer),true);
	Countdown = new BStringView("","");
	//…
}

public:
void MyFunction() {
    std::string txt=Countdown->Text();
	std::cout<<"Hello world!";
	Countdown->SetText("000"); // => The application crashes here!!!
}

void MessageReceived(BMessage *message) {
	switch (message->what) {
		case B_KEY_DOWN:
			std::thread t = std::thread(&MyClass::MyFunction,this);
			t.detach();
			break;
	}
}

};


The function “MyFunction” is started successfully and displays “Hello world!”, but as soon as I execute Countdown→SetText(…), the application crashes.
I checked, “Countdown” is not NULL.

I already tried with a signal alarm:


MyClass *MC;

void on_alarm(int signal) {
if(alarm_stop) return;
else alarm(alarm_period);
MC->MyFunction();
alarm(1);
}

int main() {
MC = new MyClass(BRect(50,50,248,238));
signal(SIGALRM,on_alarm);
alarm(1);
//…
}


But it’s the same, it crashes when executing Countdown→SetText(…).

It’s very strange because Countdown→Text() works fine in “MyFunction”.
So I can read the text but I cannot change it from the function.

So please, do you have any idea about this issue or another workaround to create a background process with a signal every seconds to decrease a countdown in a function while continuing to access the application in parallel?

In advance thank you very much for your help.

Best Regards,

I think that for your need, you will better using a BMessageRunner, an object that you create and can control to send a periodic message to a target, like your window here.

You can control the interval between each, start and stop it when you want.

Use it to send youself a “tick” message, and in your MessageReceived, on this message, do what you need to do to update the timer string value, which will trigger being refreshed on screen too.

1 Like

Thanks a lot for your fast suggestion.

I will try this BMessageRunner that I did not know, and then I keep you informed.

Thanks again.

1 Like

You’re welcome.

On a more general point, on BeOS/Haiku, it’s often the best approach to create/modify/delete GUI elements of a window from the thread managing this window, and the easiest way to do that via MessageReceived() hook method (directly there or via it), by sending messages from some other threads, like background thread(s) doing the heavy non-graphical work, when you wan’t to trigger the window UI to report some changes.

While it’s possible to modify UI elements of a given window outside the window thread, it’ll needs you to take care to lock that window object first (which you didn’t in MyFunction(), while the method is called from a different thread), and it will make your app design a bit messy, spreading in multiple part lines of code doing different kind of stuffs, mixing UI code with non UI code.

1 Like

Did you check the debug report? It will probably contain a message indicating clearly what the problem is: “Looper must be locked” or something like that.

3 Likes

Hello PHOUDOIN and WADDLESPLASH, thanks a lot for your replies.

The BMessageRunner works fine and is exactly what I was looking for. Many thanks for that!
I did not know this class, so I can progress successfully in my application with that.

Also, thank you PHOUDOIN for your detailed explanation about managing the GUI elements.

Kind Regards,

1 Like

Ahoy @YoYo ,

If you want to address forum member(s) explicitly in your reply

¤ you can do it more effectively and politely

if you use an ‘at’ sign directly before their user(account) name and forget ALL capital letters :wink: – just as I did it here – look at above ! – in this case, in my reply ..

Have a good day !

:beer: :cowboy_hat_face:

1 Like