Sign up

Passing Args to a non-void Callback?

Further to investigating signals, callbacks, and delegates, I've been trying to find a way way to pass arguments to a callback attached to addOnButtonRelease() and its ilk the way I can with addOnClicked() in the example below.

The big stumbling block seems to be that addOnButtonRelease(), addOnButtonPress(), etc. — any of the Widget object functions, in fact — return a bool whereas addOnClicked() is void.

I've tried a number of approaches, but I'm not coming up with anything that works. In the example below, I've used addOnClicked() in two ways (including the one that's commented out) and they both work, but using similar syntax with addOnButtonRelease() or any of the others just spits out errors.

Is this possible in a simple-ish way without having to, metaphorically speaking, balance the widget on its elbow?

import std.stdio;
import gtk.MainWindow;
import gtk.Main;
import gtk.Widget;
import gtk.Button;
import gdk.Event;

void main(string[] args)
{
	string title = "Test Rig OOP";
	Main.init(args);
	TestRigWindow myTestRig = new TestRigWindow(title);
	
	MyButton button = new MyButton("Click this", args);
	myTestRig.add(button);
	
	myTestRig.showAll();
	Main.run();
	
} // main()


class TestRigWindow : MainWindow
{
	this(string title)
	{
		super(title);
		addOnDestroy(&quitApp);
		
	} // this()
	
	
	void quitApp(Widget w)
	{
		writeln("Bye.");
		Main.quit();
		
	} // quitApp()

} // class TestRigWindow

 
class MyButton : Button
{
	this(string label, string[] args)
	{
		super(label);
		//addOnClicked(delegate void(Button b) { buttonAction(message); });
		addOnClicked(delegate void(_) { buttonAction(args); });
		
	} // this()
	
	
	void buttonAction(string[] args)
	{
		foreach(message; args)
		{
			writeln("The message is: ", message);
		}
		
	} // buttonAction()
	
} // class MyButton

Re: Passing Args to a non-void Callback?

You cannot change the method signature of event handlers, I would rewrite your code as follows to pass the arguments to the Window and have the window preserve them as a private variable which can then be referenced from the button handler.

import std.stdio;
import gtk.MainWindow;
import gtk.Main;
import gtk.Widget;
import gtk.Button;
import gdk.Event;

void main(string[] args)
{
	string title = "Test Rig OOP";
	Main.init(args);
	writeln("Argument count ", args.length);
	TestRigWindow myTestRig = new TestRigWindow(title, args);
	myTestRig.showAll();
	Main.run();

} // main()

class TestRigWindow : MainWindow
{
	private string[] args;

	private void onClicked(Button)
	{
		foreach (message; args)
		{
			writeln("The message is: ", message);
		}
	}

	this(string title, string[] args)
	{
		super(title);
		this.args = args;
		Button button = new Button("Click this");
		button.addOnClicked(&onClicked);
		add(button);
		addOnDestroy(&quitApp);
	} // this()

	void quitApp(Widget w)
	{
		writeln("Bye.");
		Main.quit();

	} // quitApp()

} // class TestRigWindow

Re: Passing Args to a non-void Callback?

Thanks for replying, Gerald.

Yes, you're right. I could store them as MainWindow object data and I could also store them in the Button object. But I'm on a voyage of exploration.

On Sun, 06 Jan 2019 00:13:43 GMT, Gerald Nunn wrote:

You cannot change the method signature of event handlers

But, I don't think that's what I would be doing. If these:

button.addOnClicked(&onClicked);

addOnClicked(delegate void(Button b) { buttonAction(message); });
addOnClicked(delegate void(_) { buttonAction(args); });

all work with addOnClicked(), some variation should also be doable with addOnButtonRelease(), etc. if I can find the right syntax.

My 'mission' is to go boldly and all that, to explore and find out what's possible. I'm not necessarily looking for the easy (or accepted) way.

Re: Passing Args to a non-void Callback?

On 06-01-2019 17:25, Ron Tarrant wrote:

Thanks for replying, Gerald.

Yes, you're right. I could store them as MainWindow object data and I could also store them in the Button object. But I'm on a voyage of exploration.

On Sun, 06 Jan 2019 00:13:43 GMT, Gerald Nunn wrote:

You cannot change the method signature of event handlers

But, I don't think that's what I would be doing. If these:

button.addOnClicked(&onClicked);

addOnClicked(delegate void(Button b) { buttonAction(message); });
addOnClicked(delegate void(_) { buttonAction(args); });

all work with addOnClicked(), some variation should also be doable with addOnButtonRelease(), etc. if I can find the right syntax.

My 'mission' is to go boldly and all that, to explore and find out what's possible. I'm not necessarily looking for the easy (or accepted) way.

Do you mean something like this:

addOnButtonRelease(delegate bool(Event e, Widget w){ buttonAction(args); 
return false; } );

I don't think the type inference works when both overloads have the same
amount of arguments.

The bool the function returns determines whether Gtk+ continues running
the other registered handlers or not. true if you handled the event
and Gtk should stop or false to let Gtk continue.

Re: Passing Args to a non-void Callback?

On Sun, 6 Jan 2019 19:16:17 +0100, Mike Wey wrote:

addOnButtonRelease(delegate bool(Event e, Widget w){ buttonAction(args); return false; } );

I don't think the type inference works when both overloads have the same
amount of arguments.

The bool the function returns determines whether Gtk+ continues running
the other registered handlers or not. true if you handled the event
and Gtk should stop or false to let Gtk continue.

Thanks, Mike. That did the trick. The final code:

import std.stdio;

import gtk.MainWindow;
import gtk.Main;
import gtk.Widget;
import gtk.Button;
import gdk.Event;

void main(string[] args)
{
	// initialization & creation
	Main.init(args);
	TestRigWindow myTestRig = new TestRigWindow("Test Rig OOP - Pass Args", args);
	
	// Show the window and its contents...
	myTestRig.showAll();
		
	// give control over to gtkD
	Main.run();
	
} // main()


class TestRigWindow : MainWindow
{
	this(string title, string[] args)
	{
		// window
		super(title);
		addOnDestroy(delegate void(Widget w) { quitApp(); } );
		
		// pass command line args to the button constructor
		MyArgsButton myButton = new MyArgsButton("Show Args", args);
		add(myButton);
		
		// Show the window and its contents...
		showAll();
		
	} // this()
	
	
	void quitApp()
	{
		// This exists in case we want to do anything
		// before exiting such as warn the user to
		// save work.
		writeln("Bye.");
		Main.quit();

	} // quitApp()

} // class TestRigWindow


class MyArgsButton : Button
{
	// string[] buttonArgs;
	
	this(string labelText, string[] args)
	{
		super(labelText);
		// addOnButtonRelease(&onButtonRelease);
		addOnButtonRelease(delegate bool(Event e, Widget w){ buttonAction(args); return false; } );
		// buttonArgs = args;
		
	} // this()
	
	
//	public bool buttonAction(Event event, Widget widget, string[] buttonArgs)
	public bool buttonAction(string[] buttonArgs)
	{
		writeln("got this bar.");
		
		foreach(arg; buttonArgs)
		{
			writeln("arg: ", arg);
		}

		return(true);
		
	} // buttonAction()

} // class MyArgsButton

Something I noticed...

Running this from the bash shell (the version included with git 2.20 from git-scm.com) nothing gets written to the shell window until I exit, but with the standard Windows command prompt, it's written out as soon as I release the button.

I didn't expect that.